Browse Source

++terraform-compliance-generator

master
Maxim Likhachev 3 years ago
parent
commit
fd94e51838
  1. 3
      README.md
  2. 186
      scripts/terraform-compliance-generator

3
README.md

@ -100,9 +100,10 @@ will create the symbolic link for each script in the \<path> directory.
- [gitlab-ci-linter](scripts/gitlab-ci-linter) checks Gitlab CI Pipeline syntax via GitLab API. - [gitlab-ci-linter](scripts/gitlab-ci-linter) checks Gitlab CI Pipeline syntax via GitLab API.
- [how](scripts/how) shows dev cheat sheets using [cheat.sh](https://cheat.sh). - [how](scripts/how) shows dev cheat sheets using [cheat.sh](https://cheat.sh).
- [robodoc2html](scripts/robodoc2html) converts a documentation in the robodoc format into html. - [robodoc2html](scripts/robodoc2html) converts a documentation in the robodoc format into html.
- [terraform-compliance-generator](scripts/terraform-compliance-generator) makes a [terraform-compliance](https://terraform-compliance.com/) compatible BDD testing scenario.
- [todolist](scripts/todolist) shows all `TODO` notes in current git repository. - [todolist](scripts/todolist) shows all `TODO` notes in current git repository.
- [vault-kv-tree](scripts/vault-kv-tree) shows all HashiCorp Vault's paths and keys recursively.
- [utable](scripts/utable) shows a Unicode table. - [utable](scripts/utable) shows a Unicode table.
- [vault-kv-tree](scripts/vault-kv-tree) shows all HashiCorp Vault's paths and keys recursively.
### Git ### Git

186
scripts/terraform-compliance-generator

@ -0,0 +1,186 @@
#!/usr/bin/env racket
;;;
;;; Copyright (C) 2022, Maxim Lihachev, <envrm@yandex.ru>
;;;
;;; This program is free software: you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by the Free
;;; Software Foundation, version 3.
;;;
;;; This program is distributed in the hope that it will be useful, but WITHOUT
;;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
;;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
;;; more details.
;;;
;;; You should have received a copy of the GNU General Public License along with
;;; this program. If not, see <https://www.gnu.org/licenses/>.
;;;
;;; terraform-compliance-generator can be used to generate
;;; https://terraform-compliance.com/ compatible BDD scenario.
#lang racket/base
(require
(for-syntax racket/base)
json
racket/format
racket/function
racket/list
racket/path
racket/port
racket/string
racket/stxparam
racket/vector)
;;; ----------------------------------------------------------------------------
;;
;; Terraform plan JSON:
;;
;; {
;; "resource_changes": [
;; {
;; "type": "helm_release",
;; "change": {
;; "after": {
;; "key": value,
;; ...
;; }
;; }
;; },
;; ...
;; ]
;; }
;;
(define (usage)
(display-lines
(list
"terraform-bdd generates terraform-compliance acceptable BDD tests.\n"
(format "USAGE: ~a [terraform.plan.json]~%" script-file)
"Command line options:"
" --help Show this help.")))
;;; ----------------------------------------------------------------------------
(define-syntax-parameter <resource>
(λ (stx) (raise-syntax-error '<resource> "Used outside of macro." stx)))
(define-syntax-parameter <properties>
(λ (stx) (raise-syntax-error '<properties> "Used outside of macro." stx)))
(define (to-string x)
(format "~a" x))
(define (read-terraform-plan plan-file)
(if (file-exists? plan-file)
(with-handlers
((exn:fail?
(λ (exn)
(fprintf (current-error-port)
"ERROR: Unable to read JSON data: ~a~%" (exn-message exn))
(exit 1))))
(with-input-from-file plan-file
(λ ()
(hash-ref (read-json) 'resource_changes))))
(printf "ERROR: file ~a does not exist.~%" plan-file)))
(define (fields l)
(filter (λ (xs)
(let ((x (cdr xs)))
(not (or (null? x)
(eq? (json-null) x)
(hash? x)
(list? x)))))
l))
(define (get-properties change)
(sort (fields
(hash->list
(hash-ref (hash-ref change 'change) 'after)))
#:key car (λ (a b) (string<? (to-string a) (to-string b)))))
(define (key pair) (car pair))
(define (value pair)
(let ((v (cdr pair)))
(cond ((boolean? v)
(case v
((#t) "true")
((#f) "false")))
((number? v) v)
(else (with-quotes v)))))
(define (with-quotes s)
(regexp-replace* #rx"(^\"+|\"+$)" (string-append "\"" s "\"") "\""))
(define (max-width fx l)
(apply max
(map
(lambda (x) (string-length (to-string (fx x)))) l)))
;;; ----------------------------------------------------------------------------
(define-syntax-rule (FEATURE terraform-plan expr ...)
(display-lines
(flatten
(list "Feature: Test Terraform Module"
(map (curry expr ...) terraform-plan)))))
(define-syntax-rule (EXAMPLES properties)
(let ((row (λ (q) (format " | ~a | ~a |"
(~a (key q) #:min-width (max-width key properties))
(~a (value q) #:min-width (max-width value properties))))))
(list
(format "~% Examples:")
(row (cons "<key>" "<value>"))
(map row properties))))
(define-syntax-rule (GIVEN resource expr ...)
(λ (short-list properties)
(list
(format " Given I have ~a defined" (string-replace (hash-ref resource 'type) "_" " "))
(if short-list
(map (curry expr ...) properties)
(list
(expr ... (cons (with-quotes "<key>") (with-quotes "<value>")))
(EXAMPLES properties))))))
(define-syntax-rule (THEN _ _)
(λ (x)
(syntax-parameterize
((<properties> (make-rename-transformer #'x)))
(format " Then it must have ~a~% And its value must be ~a" (key x) (value x)))))
(define-syntax-rule (SCENARIO _ expr ...)
(λ (x)
(syntax-parameterize
((<resource> (make-rename-transformer #'x)))
(let* ((properties (get-properties x))
(long-list (<= (length properties) 3))
(resource-type (hash-ref x 'type))
(scenario-type (if long-list "" " Outline")))
(list
(format "~%Scenario~a: Ensure that the ~a resource exists" scenario-type resource-type)
(expr ... long-list properties))))))
;;; ----------------------------------------------------------------------------
(define script-file (file-name-from-path (find-system-path 'run-file)))
(define args (current-command-line-arguments))
(when (or (vector-empty? args)
(equal? (vector-ref args 0) "--help"))
(usage)
(exit))
(define terraform-plan
(read-terraform-plan (vector-ref args 0)))
;;; ----------------------------------------------------------------------------
(FEATURE terraform-plan
(SCENARIO <resource>
(GIVEN <resource>
(THEN CHECK <properties>))))
Loading…
Cancel
Save