Skip to content

Commit

Permalink
Feature/validate xref (#39)
Browse files Browse the repository at this point in the history
* not needed anymore

* add more documentation

* fix markup

* implement xref validation
  • Loading branch information
brabster committed Aug 16, 2016
1 parent 84f6655 commit c7e4948
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 37 deletions.
17 changes: 16 additions & 1 deletion src/crucible/core.clj
@@ -1,6 +1,7 @@
(ns crucible.core
"Commonly used template construction functions"
(:require [clojure.spec :as s]
[clojure.walk :as walk]
[crucible.values :as v]
[crucible.parameters :as p]
[crucible.resources :as r]
Expand All @@ -17,6 +18,18 @@
(s/def ::template (s/cat :description ::description
:elements (s/nilable (s/map-of keyword? ::element))))

(defn validate [template]
(walk/prewalk
(fn [x]
(cond
(and (vector? x)
(= 2 (count x))
(= ::v/ref (first x))) (if-not (contains? (:elements template) (second x))
(throw (ex-info "Missing reference" {:ref (second x)}))
x)
:else x))
template))

(defn template
"Make a template structure with the given description and elements"
[description & {:as elements}]
Expand All @@ -25,7 +38,9 @@
parsed (s/conform spec input)]
(if (= parsed ::s/invalid)
(throw (ex-info "Invalid input" (s/explain-data spec input)))
(with-meta parsed {::template true}))))
(-> parsed
validate
(with-meta {::template true})))))

(defn parameter
"Make a template parameter element"
Expand Down
4 changes: 0 additions & 4 deletions src/crucible/encoding.clj
Expand Up @@ -8,9 +8,6 @@
(defmethod ->key :aws-template-format-version [_]
"AWSTemplateFormatVersion")

(defn validate-element [_ element]
element)

(defmulti rewrite-element-data (fn [[type _]] type))

(defn unqualify-keyword [kw] (-> kw name keyword))
Expand Down Expand Up @@ -55,7 +52,6 @@
(defn elements->template [elements-map empty-template]
(->> elements-map
seq
(map (partial validate-element elements-map))
(map rewrite-element)
(reduce assemble-template empty-template)))

Expand Down
4 changes: 4 additions & 0 deletions test-resources/aws/cloudwatch/alarm.json
@@ -1,6 +1,10 @@
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Description": "sample",
"Parameters": {
"WebServerScaleUpPolicy": {"Type": "String"},
"WebServerGroup": {"Type": "String"}
},
"Resources": {
"CpuAlarmHigh": {
"Type": "AWS::CloudWatch::Alarm",
Expand Down
2 changes: 2 additions & 0 deletions test/crucible/aws/cloudwatch_test.clj
Expand Up @@ -12,6 +12,8 @@
(cru/encode
(cru/template
"sample"
:web-server-scale-up-policy (cru/parameter)
:web-server-group (cru/parameter)
:cpu-alarm-high (cw/alarm #::cw{:alarm-description "Scale-up if CPU is greater than 90% for 10 minutes"
:metric-name "CPUUtilization"
:namespace "AWS/EC2"
Expand Down
20 changes: 3 additions & 17 deletions test/crucible/encoding/template_test.clj
Expand Up @@ -118,20 +118,6 @@
(template "t"
:my-resource (ec2/vpc {::ec2/cidr-block notification-arns}))))))))

#_(deftest resource-reference-validation-test
(testing "reference non-existent parameter from resource property throws"
(is (thrown? AssertionError (make-template {:resources
{:my-resource
{:name "Custom::Test"
:properties {:test [:ref :foo]}}}})))))

#_(deftest references-match-template-keys
(testing "references in values match template keys"
(let [t (make-template {:parameters {:foo nil}
:resources {:bar {:name "Custom::Test"
:properties {:baz [:ref :foo]}}}})]
(is (contains? (get t "Parameters") (get-in t ["Resources"
"Bar"
"Properties"
"Baz"
"Ref"]))))))
(deftest resource-reference-validation-test
(testing "reference non-existent parameter from resource property throws"
(is (thrown? Exception (template "t" :my-resource (ec2/vpc {::ec2/cidr-block (xref :foo)}))))))
39 changes: 24 additions & 15 deletions test/crucible/template_test.clj
Expand Up @@ -7,6 +7,12 @@
[crucible.resources :as res]
[crucible.aws.ec2 :as ec2]))

(deftest template-metadata-tag
(is (true? (-> "t"
template
meta
:crucible.core/template))))

(deftest minimal-template
(is (= {:description "t"
:elements
Expand All @@ -28,11 +34,11 @@
#::ec2{:cidr-block "1.2.3.4/16"
:vpc-id
#::v{:type ::v/xref,
:ref :foo}}}}}}
:ref :subnet}}}}}}
(template "t"
:vpc (ec2/vpc {::ec2/cidr-block "1.2.3.4/24"})
:subnet (ec2/subnet {::ec2/cidr-block "1.2.3.4/16"
::ec2/vpc-id (xref :foo)})))))
::ec2/vpc-id (xref :subnet)})))))

(deftest template-with-param
(is (= {:description "t"
Expand All @@ -48,37 +54,40 @@
:vpc (ec2/vpc {::ec2/cidr-block (xref :vpc-cidr)})))))

(deftest template-with-output
(is (= {:description "t",
(is (= {:description "t"
:elements
{:vpc-id
{:vpc-cidr {:type :parameter
:specification #::param{:type ::param/string}}
:vpc-id
{:type :output
:specification #::out{:description "the vpc id",
:value #::v{:type ::v/xref,
:ref :vpc}}},
:specification #::out{:description "the vpc id"
:value #::v{:type ::v/xref
:ref :vpc}}}
:vpc
{:type :resource
:specification #::res{:type "AWS::EC2::VPC",
:specification #::res{:type "AWS::EC2::VPC"
:properties {::ec2/cidr-block
#::v{:type ::v/xref,
#::v{:type ::v/xref
:ref :vpc-cidr}}}}}}
(template "t"
:vpc-cidr (parameter)
:vpc (ec2/vpc {::ec2/cidr-block (xref :vpc-cidr)})
:vpc-id (output (xref :vpc) "the vpc id")))))

(deftest join-fn-in-value-position
(is (= {:description "t",
(is (= {:description "t"
:elements
{:vpc-cidr
{:type :parameter
:specification #::param{:type ::param/string}},
:specification #::param{:type ::param/string}}
:vpc
{:type :resource
:specification #::res{:type "AWS::EC2::VPC",
:specification #::res{:type "AWS::EC2::VPC"
:properties
{::ec2/cidr-block
#::v{:type ::v/join,
:fn-values ["foo" #::v{:type ::v/xref,
:ref :vpc-cidr}],
#::v{:type ::v/join
:fn-values ["foo" #::v{:type ::v/xref
:ref :vpc-cidr}]
:delimiter "-"}}}}}}
(template "t"
:vpc-cidr (parameter)
Expand Down

0 comments on commit c7e4948

Please sign in to comment.