diff --git a/.circleci/config.yml b/.circleci/config.yml index d42f04d..29a6773 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,69 +1,175 @@ version: 2 +# TODO: centralize full configuration. Figure out how +# ?? Each step as a separate script that is downloaded and run ?? +# ?? CircleCI feature request to supoort include from remote sources +# More Markdown terraform_testing +# Python testing. Add doc and test that too +# circleci/python: Both 2 and 3? +# if src/requirements.txt get version from *.tf and test +# Style+: flake8 + hacking?, prospector? +# Security: bandit, RATS, + +# This file uses YAML anchors to deduplicate steps +# see https://circleci.com/blog/circleci-hacks-reuse-yaml-in-your-circleci-config-with-yaml/ +# and https://learnxinyminutes.com/docs/yaml/ + +.steps_template: &steps_terraform_static_analysis + steps: + - checkout + - run: + name: "Check: Validate tf files (terraform validate)" + command: | + find . -type f -name "*.tf" -exec dirname {} \;|sort -u | while read m; do (terraform validate -check-variables=false "$m" && echo "√ $m") || exit 1 ; done + - run: + name: "Check: Terraform formatting (terraform fmt)" + command: | + if [ `terraform fmt --list=true -diff=true -write=false | tee format-issues | wc -c` -ne 0 ]; then + echo "Some terraform files need be formatted, run 'terraform fmt' to fix" + echo "Formatting issues:" + cat format-issues + exit 1 + fi + - run: + name: "Install: tflint" + command: | + apk update + apk add jq wget + # Get latest version of tflint (v0.7.0 test if still need to exclude modules. Any other changes) + pkg_arch=linux_amd64 + dl_url=$(curl -s https://api.github.com/repos/wata727/tflint/releases/latest | jq -r ".assets[] | select(.name | test(\"${pkg_arch}\")) | .browser_download_url") + wget ${dl_url} + unzip tflint_linux_amd64.zip + mkdir -p /usr/local/tflint/bin + # Setup PATH for later run steps - ONLY for Bash and not in Bash + #echo 'export PATH=/usr/local/tflint/bin:$PATH' >> $BASH_ENV + echo "Installing tflint..." + install tflint /usr/local/tflint/bin + echo "Configuring tflint..." + tf_ver=$(terraform version | awk 'FNR <= 1' | cut -dv -f2) + echo -e "\tConfig for terraform version: ${tf_ver}" + if [ -f '.tflint.hcl' ]; then + sed -i "/terraform_version =/s/\".*\"/\"${tf_ver}\"/" .tflint.hcl + else + { + echo -e "config {\nterraform_version = \"${tf_ver}\"\ndeep_check = true\nignore_module = {" + for module in $(grep -h '[^a-zA-Z]source[ =]' *.tf | sed -r 's/.*=\s+//' | sort -u); do + # if not ^"../ + echo "${module} = true" + done + echo -e "}\n}\n" + } > .tflint.hcl + fi + echo "tflint configuration:" + cat .tflint.hcl + - run: + # Not supporting modules from registry ?? v0.5.4 + # For now, must ignore in config file + name: "Check: tflint" + command: | + #echo "Initializing terraform..." + #terraform init -input=false + echo "Running tflint..." + /usr/local/tflint/bin/tflint --version + /usr/local/tflint/bin/tflint + jobs: - build: + ### + ### Documentation testing: Markdown + ### + # Markdown Lint https://github.com/DavidAnson/markdownlint + # CLI https://github.com/igorshubovych/markdownlint-cli + # https://hub.docker.com/r/circleci/node/tags/ + markdown_lint_node: docker: - - image: hashicorp/terraform:0.11.3 - entrypoint: /bin/sh + - image: circleci/node:10.5.0 steps: - checkout - run: - name: "Validate tf files (terraform validate)" + name: "Install: markdown lint (node.js)" command: | - find . -type f -name "*.tf" -exec dirname {} \;|sort -u | while read m; do (terraform validate -check-variables=false "$m" && echo "√ $m") || exit 1 ; done + sudo npm install -g markdownlint-cli - run: - name: "Check: Terraform formatting (terraform fmt)" + name: "Check: markdown lint (node.js)" command: | - if [ `terraform fmt --list=true -diff=true -write=false | tee format-issues | wc -c` -ne 0 ]; then - echo "Some terraform files need be formatted, run 'terraform fmt' to fix" - echo "Formatting issues:" - cat format-issues - exit 1 - fi + #markdownlint --help + echo -n "markdownlint version: " + markdownlint --version + markdownlint ./ + # Markdown Lint https://github.com/markdownlint/markdownlint + # https://hub.docker.com/r/circleci/ruby/tags/ + markdown_lint_ruby: + docker: + - image: circleci/ruby:2.5.1 + steps: + - checkout + - run: + name: "Install: markdown lint (ruby)" + command: | + gem install mdl + - run: + name: "Check: markdown lint (ruby)" + command: | + #mdl --help + echo -n "mdl version: " + mdl --version + mdl . + markdown_proofer: + docker: + - image: circleci/golang:1.10 + entrypoint: /bin/sh + steps: + - checkout - run: - name: "Install: tflint" + name: "Install: markdown proofer" command: | - apk add jq wget - # Get latest version of tflint + # Get latest version pkg_arch=linux_amd64 - dl_url=$(curl -s https://api.github.com/repos/wata727/tflint/releases/latest | jq -r ".assets[] | select(.name | test(\"${pkg_arch}\")) | .browser_download_url") + # Prerelease, so latest doesn't work yet + #dl_url=$(curl -s https://api.github.com/repos/felicianotech/md-proofer/releases/latest | jq -r ".assets[] | select(.name | test(\"${pkg_arch}\")) | .browser_download_url") + dl_url='https://github.com/felicianotech/md-proofer/releases/download/v0.2.0/md-proofer--v0.2.0--linux-amd64.tar.gz' wget ${dl_url} - unzip tflint_linux_amd64.zip - mkdir -p /usr/local/tflint/bin - # Setup PATH for later run steps - ONLY for Bash and not in Bash - #echo 'export PATH=/usr/local/tflint/bin:$PATH' >> $BASH_ENV - echo "Installing tflint..." - install tflint /usr/local/tflint/bin - echo "Configuring tflint..." - tf_ver=$(terraform version | awk 'FNR <= 1' | cut -dv -f2) - echo -e "\tConfig for terraform version: ${tf_ver}" - if [ -f '.tflint.hcl' ]; then - sed -i "/terraform_version =/s/\".*\"/\"${tf_ver}\"/" .tflint.hcl - else - { - echo -e "config {\nterraform_version = \"${tf_ver}\"\ndeep_check = true\nignore_module = {" - for module in $(grep -h '[^a-zA-Z]source[ =]' *.tf | sed -r 's/.*=\s+//' | sort -u); do - # if not ^"../ - echo "${module} = true" - done - echo "}}" - } > .tflint.hcl - fi - echo "tflint configuration:" - cat .tflint.hcl + tar xzf md-proofer--v0.2.0--linux-amd64.tar.gz - run: - # Not supporting modules from registry ?? v0.5.4 - # For now, must ignore in config file - name: "Check: tflint" + name: "Check: markdown proofer" command: | - #echo "Initializing terraform..." - #terraform init -input=false - echo "Running tflint..." - /usr/local/tflint/bin/tflint --version - /usr/local/tflint/bin/tflint + ./md-proofer version + #./md-proofer lint --help + # Will this find all *.md in directory structure or need to run in each directory ? + if ./md-proofer lint ./; then + echo "md-proofer passed" + else + echo "md-proofer failed" + fi + ### + ### Terraform testing + ### + terraform_0_11_3: + docker: + - image: hashicorp/terraform:0.11.3 + entrypoint: /bin/sh + <<: *steps_terraform_static_analysis + + terraform_0_11_7: + docker: + - image: hashicorp/terraform:0.11.7 + entrypoint: /bin/sh + <<: *steps_terraform_static_analysis + + terraform_latest: + docker: + - image: hashicorp/terraform:latest + entrypoint: /bin/sh + <<: *steps_terraform_static_analysis workflows: version: 2 - build: + terraform_testing: jobs: - - build + - markdown_lint_node + - markdown_lint_ruby + # Currently doesn't do anything that markdownlint node doesn't do + #- markdown_proofer + - terraform_0_11_3 + - terraform_0_11_7 + - terraform_latest diff --git a/README-json.md b/README-json.md index bb9a7c5..1ad84f8 100644 --- a/README-json.md +++ b/README-json.md @@ -1,12 +1,23 @@ # escalation-policy.json -Currently Terraform is not capable of dynamically created the data structure needed to define a Pagerduty escalation policy. So, a [json file](escalation-policy.json-example) is used to specify the escalation policy details and a script does lookups in Pagerduty for details, then creates variables in HCL format for Terraform to consume. +Currently Terraform is not capable of dynamically created the data structure +needed to define a Pagerduty escalation policy. So, a +[json file](escalation-policy.json-example) is used to specify the escalation +policy details and a script does lookups in Pagerduty for details, then creates +variables in HCL format for Terraform to consume. -The [json file](escalation-policy.json-example) contains details for 2 variables: escalation-rules and teams +The [json file](escalation-policy.json-example) contains details for +2 variables: escalation-rules and teams -Escalation-rules is a list of maps. Each map defines an escalation rule. Each escalation rule has fields: escalation_delay and targets. escalation_delay is the delay in minutes between rules. This maps directly to Pagerduty. Targets is a list of targets for the escalation rule. Targets can be user email addresses or schedule names. These will be looked up in Pagerduty and ignored if not found. +Escalation-rules is a list of maps. Each map defines an escalation rule. Each +escalation rule has fields: escalation_delay and targets. escalation_delay +is the delay in minutes between rules. This maps directly to Pagerduty. +Targets is a list of targets for the escalation rule. Targets can be user +email addresses or schedule names. These will be looked up in Pagerduty and +ignored if not found. -Teams is a list of team names. These will be looked up in Pagerduty and ignored if not found. +Teams is a list of team names. These will be looked up in Pagerduty and +ignored if not found. Both variables are required. If teams are not being used, use "teams": [] diff --git a/README.md b/README.md index fe33567..829a135 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,20 @@ -[![CircleCI](https://circleci.com/gh/devops-workflow/terraform-pagerduty-service-complete.svg?style=svg)](https://circleci.com/gh/devops-workflow/terraform-pagerduty-service-complete) - # terraform-pagerduty-service-complete -This is a Terraform module to manage an opinionated PagerDuty service. It will create a service with: escalation policy and integrations for AWS Cloudwatch, Datadog, and an AWS Service endpoint monitor lambda. +[![CircleCI](https://circleci.com/gh/devops-workflow/terraform-pagerduty-service-complete.svg?style=svg)](https://circleci.com/gh/devops-workflow/terraform-pagerduty-service-complete) + +This is a Terraform module to manage an opinionated PagerDuty service. It will +create a service with: escalation policy and integrations for AWS Cloudwatch, +Datadog, and an AWS Service endpoint monitor lambda. -The idea to define a PagerDuty service for each application with the application's deployment via Terraform. Service, escalation policy, and integrations are unique to each application. +The idea to define a PagerDuty service for each application with the +application's deployment via Terraform. Service, escalation policy, and +integrations are unique to each application. -Escalation policy is defined with a [json file](README-json.md) due to limitations in Terraform. A [script](scripts/variable-generator.py) is run to lookup information in Pagerduty and generate a HCL file with the variable definitions for Terraform to use. Generated file is `variables-generated-escaaltion-policy.tf` +Escalation policy is defined with a [json file](README-json.md) due to +limitations in Terraform. A [script](scripts/variable-generator.py) is run to +lookup information in Pagerduty and generate a HCL file with the variable +definitions for Terraform to use. Generated file is +`variables-generated-escalation-policy.tf` Pagerduty integration keys are provided as outputs for other modules to use. diff --git a/examples/service/run.sh b/examples/service/run.sh index 49be6e7..64fdc07 100755 --- a/examples/service/run.sh +++ b/examples/service/run.sh @@ -1,3 +1,4 @@ python ../../scripts/variable-generator.py +terraform fmt terraform init terraform plan diff --git a/examples/service/variables-generated-escalation-policy.tf b/examples/service/variables-generated-escalation-policy.tf index 907ef39..48c04d7 100644 --- a/examples/service/variables-generated-escalation-policy.tf +++ b/examples/service/variables-generated-escalation-policy.tf @@ -1,24 +1,9 @@ variable "escalation_rules" { - type = "list" - - default = [ - { - "escalation_delay_in_minutes" = "11" - - "target" = [ - { - "type" = "user_reference" - "id" = "PDBFXEO" - }, - ] - }, - ] + type = "list" + default = [] } variable "teams" { - type = "list" - - default = [ - "PIUEF8D", - ] + type = "list" + default = [] } diff --git a/main.tf b/main.tf index b5d0cf7..2f47ed7 100644 --- a/main.tf +++ b/main.tf @@ -9,7 +9,7 @@ module "enabled" { source = "devops-workflow/boolean/local" - version = "0.1.1" + version = "0.1.2" value = "${var.enabled}" } @@ -92,24 +92,24 @@ resource "pagerduty_extension" "slack"{ "name": "Slack-Channel-X", "extension_objects": [ { - "self": "https://api.pagerduty.com/services/PWDXXXX", + "self": "https://api.pagerduty.com/services/PWXXXXX", "type": "service_reference", - "id": "PWDXXXX", - "html_url": "https://company.pagerduty.com/services/PWDXXXX", + "id": "PWXXXXX", + "html_url": "https://company.pagerduty.com/services/PWXXXXX", "summary": "[Service] Channel X" } ], - "authorization_url": "https://app.pagerduty.com/slack_oauth?webhook=PL6XXXX", + "authorization_url": "https://app.pagerduty.com/slack_oauth?webhook=PLXXXXX", "type": "webhook", - "self": "https://api.pagerduty.com/webhooks/PL6XXXX", + "self": "https://api.pagerduty.com/webhooks/PLXXXXX", "summary": "Slack-Channel-X", "html_url": null, - "id": "PL6XXXX", + "id": "PLXXXXX", "authorized": true, "extension_schema": { - "self": "https://api.pagerduty.com/extension_schemas/PD8XXXX", + "self": "https://api.pagerduty.com/extension_schemas/PDXXXXX", "type": "extension_schema_reference", - "id": "PD8XXXX", + "id": "PDXXXXX", "html_url": null, "summary": "Slack" }, @@ -118,13 +118,13 @@ resource "pagerduty_extension" "slack"{ "user_id": "U6SCXXXX", "access_token": "slack token", "bot": { - "bot_user_id": "U2P6XXXX" + "bot_user_id": "U2XXXXXX" }, "incoming_webhook": { "url": "https://hooks.slack.com/services/TTTTTTTT/BBBBBBBB/xxxxxx", - "channel_id": "CAC0BXXXX", + "channel_id": "CAXXXXXXX", "channel": "#mon-channel-x", - "configuration_url": "https://company.slack.com/services/BACDNXXXX" + "configuration_url": "https://company.slack.com/services/BAXXXXXXX" }, "restrict": "any", "team_id": "TTTTTTT", diff --git a/scripts/find-module-in-cache.sh b/scripts/find-module-in-cache.sh index 59e5385..1083833 100755 --- a/scripts/find-module-in-cache.sh +++ b/scripts/find-module-in-cache.sh @@ -1,3 +1,5 @@ + +# grep -E "source" *.tf # .terraform/modules/modules.json from current directory after init is run jq -r '.Modules[] | select(.Source == "devops-workflow/service-complete/pagerduty") | .Dir' modules.json