diff --git a/.env.template b/.env.template index d0e6bd3..9106b62 100644 --- a/.env.template +++ b/.env.template @@ -1,6 +1,6 @@ ARM_SUBSCRIPTION_ID="" -GO_VERSION=1.11 -TF_VERSION=0.11.13 +GO_VERSION=1.12.5 +TF_VERSION=0.12.1 BUILD_BUILDID=1 ARM_CLIENT_ID="" ARM_CLIENT_SECRET="" diff --git a/devops/providers/azure-devops/templates/azure-pipelines.yml b/devops/providers/azure-devops/templates/azure-pipelines.yml index f6ac2fd..091e8a5 100644 --- a/devops/providers/azure-devops/templates/azure-pipelines.yml +++ b/devops/providers/azure-devops/templates/azure-pipelines.yml @@ -35,9 +35,9 @@ pool: variables: - group: "KV Secrets" - name: GO_VERSION - value: '1.11' + value: '1.12.5' - name: TF_VERSION - value: '0.11.13' + value: '0.12.1' - name: TEST_HARNESS_BASE_IMAGE_TAG value: 'g$(GO_VERSION)t$(TF_VERSION)' - name: TEST_HARNESS_BASE_IMAGE diff --git a/go.mod b/go.mod index a7e81b9..6eee0f1 100644 --- a/go.mod +++ b/go.mod @@ -3,10 +3,11 @@ module github.com/microsoft/cobalt go 1.12 require ( - github.com/gruntwork-io/terratest v0.15.9 - github.com/hashicorp/terraform v0.11.14 + github.com/go-sql-driver/mysql v1.4.1 // indirect + github.com/google/uuid v1.1.1 // indirect + github.com/gruntwork-io/terratest v0.16.1 + github.com/hashicorp/terraform v0.12.1 github.com/magefile/mage v1.8.0 - github.com/mitchellh/go-homedir v1.1.0 - github.com/spf13/cobra v0.0.4 - github.com/spf13/viper v1.3.2 + github.com/pquerna/otp v1.2.0 // indirect + github.com/stretchr/testify v1.3.0 ) diff --git a/go.sum b/go.sum index 59cad2a..8b401ac 100644 --- a/go.sum +++ b/go.sum @@ -1,226 +1,406 @@ -cloud.google.com/go v0.15.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/Azure/azure-sdk-for-go v10.3.0-beta+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/go-autorest v9.10.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-ntlmssp v0.0.0-20170803034930-c92175d54006/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.31.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.36.0 h1:+aCSj7tOo2LODWVEuZDZeGCckdt6MlSF+X/rB3wUiS8= +cloud.google.com/go v0.36.0/go.mod h1:RUoy9p/M4ge0HzT8L+SDZ8jg+Q6fth0CiBuhFJpSV40= +dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= +dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= +dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= +dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= +git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +github.com/Azure/azure-sdk-for-go v21.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-autorest v10.15.4+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-ntlmssp v0.0.0-20180810175552-4a21cbd618b4/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/ChrisTrenkamp/goxpath v0.0.0-20170625215350-4fe035839290/go.mod h1:nuWgzSkT5PnyOd+272uUmV0dnAnAn42Mk7PiQC5VzN4= +github.com/ChrisTrenkamp/goxpath v0.0.0-20170922090931-c385f95c6022/go.mod h1:nuWgzSkT5PnyOd+272uUmV0dnAnAn42Mk7PiQC5VzN4= github.com/Unknwon/com v0.0.0-20151008135407-28b053d5a292/go.mod h1:KYCjqMOeHpNuTOiFQU6WEcTG7poCJrUs0YgyHNtn1no= github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af/go.mod h1:5Jv4cbFiHJMsVxt52+i0Ha45fjshj6wxYr1r19tB9bw= -github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8= github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= +github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE= +github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agl/ed25519 v0.0.0-20150830182803-278e1ec8e8a6/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0= -github.com/antchfx/xpath v0.0.0-20170728053731-b5c552e1acbd/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk= -github.com/antchfx/xquery v0.0.0-20170730121040-eb8c3c172607/go.mod h1:LzD22aAzDP8/dyiCKFp31He4m2GPjl0AFyzDtZzUu9M= -github.com/apparentlymart/go-cidr v0.0.0-20170616213631-2bd8b58cf427 h1:2P/DTyNDU+7qJOB6E5KeIpdc3qcT9IYjyA8hZ9HGz50= -github.com/apparentlymart/go-cidr v0.0.0-20170616213631-2bd8b58cf427/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= -github.com/apparentlymart/go-textseg v0.0.0-20170531203952-b836f5c4d331 h1:AIKxo1t7QE7MAqADwrmzMiaFC+QfHfXOk8lrmibN5Lk= -github.com/apparentlymart/go-textseg v0.0.0-20170531203952-b836f5c4d331/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/antchfx/xpath v0.0.0-20190129040759-c8489ed3251e/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk= +github.com/antchfx/xquery v0.0.0-20180515051857-ad5b8c7a47b0/go.mod h1:LzD22aAzDP8/dyiCKFp31He4m2GPjl0AFyzDtZzUu9M= +github.com/apparentlymart/go-cidr v1.0.0 h1:lGDvXx8Lv9QHjrAVP7jyzleG4F9+FkRhJcEsDFxeb8w= +github.com/apparentlymart/go-cidr v1.0.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= +github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= +github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= +github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0= +github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= +github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20160115234725-4239b77079c7 h1:MBXhrxjNkjdqJysfNbKMMPFNXlz6EzpOnPcsoYBeD3E= -github.com/armon/go-radix v0.0.0-20160115234725-4239b77079c7/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go v1.16.36 h1:POeH34ZME++pr7GBGh+ZO6Y5kOwSMQpqp5BGUgooJ6k= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.16.36/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.19.18 h1:Hb3+b9HCqrOrbAtFstUWg7H5TQ+/EcklJtE8VShVs8o= +github.com/aws/aws-sdk-go v1.19.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= -github.com/bgentry/speakeasy v0.0.0-20161015143505-675b82c74c0e h1:giZ2nnSSH4ntzmoNPwdncPXXA2nWdlO7NiebK0gozNI= -github.com/bgentry/speakeasy v0.0.0-20161015143505-675b82c74c0e/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/blang/semver v0.0.0-20170202183821-4a1e882c79dc h1:J/iAaGTCZYfT/allw61NfW/CEoflFsNdhQJny4iLU+0= -github.com/blang/semver v0.0.0-20170202183821-4a1e882c79dc/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/chzyer/logex v1.1.11-0.20160617073814-96a4d311aa9b/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= +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/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= +github.com/bsm/go-vlq v0.0.0-20150828105119-ec6e8d4f5f4e/go.mod h1:N+BjUcTjSxc2mtRGSCPsat1kze3CUtvJN3/jTXlp29k= +github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20161106042343-c914be64f07d/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20160617131543-bea8f082b6fd/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/coreos/bbolt v1.3.1-coreos.1/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.2.0-rc.1.0.20170908195435-80aa810309d4+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +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/coreos/bbolt v1.3.0/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= 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-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= 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 v0.0.0-20160617170158-f0777076321a/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dnaeon/go-vcr v0.0.0-20170218072653-87d4990451a8/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dimchansky/utfbom v1.0.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/dnaeon/go-vcr v0.0.0-20180920040454-5637cf3d8a31/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dylanmei/iso8601 v0.1.0/go.mod h1:w9KhXSgIyROl1DefbMYIE7UVSIvELTbMrCfx+QkYnoQ= -github.com/dylanmei/winrmtest v0.0.0-20170819153634-c2fbb09e6c08/go.mod h1:VBVDFSBXCIW8JaHQpI8lldSKfYaLMzP9oyq6IJ4fhzY= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/dylanmei/winrmtest v0.0.0-20190225150635-99b7fe2fddf1/go.mod h1:lcy9/2gH1jn/VCLouHA6tOEwLoNVd4GW6zhuKLmHC2Y= +github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-test/deep v1.0.1 h1:UQhStjbkDClarlmv0am7OXXO4/GaPdCGiUiMTvi28sg= github.com/go-test/deep v1.0.1/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/gogo/protobuf v0.0.0-20170307180453-100ba4e88506/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= +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 v1.1.0/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.0 h1:kbxbvI4Un1LUWKxufD+BiE6AEExYYgkQLQmLFqA1LFk= +github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.1.1-0.20171002171727-8ebdfab36c66/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/googleapis/gax-go v0.0.0-20161107002406-da06d194a00e/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +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/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.0.0+incompatible h1:j0GKcs05QVmm7yesiZq2+9cxHkNK9YM6zKx4D2qucQU= +github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/googleapis/gax-go/v2 v2.0.3 h1:siORttZ36U2R/WjiJuDz8znElWBiAlO9rVt+mqJt0Cc= +github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/gophercloud/gophercloud v0.0.0-20190208042652-bc37892e1968/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4= github.com/gophercloud/utils v0.0.0-20190128072930-fbb6ab446f01/go.mod h1:wjDF8z83zTeg5eMLml5EBSlAhbF7G8DobyI1YsMuyzw= -github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/grpc-ecosystem/go-grpc-prometheus v0.0.0-20160910222444-6b7015e65d36/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.2.2/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= -github.com/gruntwork-io/terratest v0.15.9 h1:SBYLlpa6AUm+uRDAErUyQuCmdvP86omWdEGWhQrQPl0= -github.com/gruntwork-io/terratest v0.15.9/go.mod h1:NjUn6YXA5Skxt8Rs20t3isYx5Rl+EgvGB8/+RRXddqk= -github.com/hashicorp/atlas-go v0.0.0-20161107204910-1792bd8de119/go.mod h1:ckHDuH0pxfnmXZkq1niVSguIIV0pA65gifQv3so9llw= -github.com/hashicorp/aws-sdk-go-base v0.3.0/go.mod h1:ZIWACGGi0N7a4DZbf15yuE1JQORmWLtBcVM6F5SXNFU= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +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.0/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.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/grpc-ecosystem/grpc-gateway v1.5.1/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/gruntwork-io/terratest v0.16.1 h1:r4kQps7wevleXDik2fGMXnT+ehWAFMrRy/yQQQtA3bo= +github.com/gruntwork-io/terratest v0.16.1/go.mod h1:NjUn6YXA5Skxt8Rs20t3isYx5Rl+EgvGB8/+RRXddqk= +github.com/hashicorp/aws-sdk-go-base v0.2.0/go.mod h1:ZIWACGGi0N7a4DZbf15yuE1JQORmWLtBcVM6F5SXNFU= github.com/hashicorp/consul v0.0.0-20171026175957-610f3c86a089/go.mod h1:mFrjN1mfidgJfYP1xrJCF+AfRhr6Eaqhb2+sfyn/OOI= +github.com/hashicorp/errwrap v0.0.0-20180715044906-d6c0cd880357/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-checkpoint v0.0.0-20171009173528-1545e56e46de/go.mod h1:xIwEieBHERyEvaeKF/TcHh1Hu+lxPM+n2vT1+g9I4m4= +github.com/hashicorp/go-azure-helpers v0.0.0-20190129193224-166dfd221bb2/go.mod h1:lu62V//auUow6k0IykxLK2DCNW8qTmpm8KqhYVWattA= +github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg= github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-getter v0.0.0-20180327010114-90bb99a48d86 h1:hLYM35twiyKH44g36g+GFYODcrZQetEAY4+zrJtGea0= -github.com/hashicorp/go-getter v0.0.0-20180327010114-90bb99a48d86/go.mod h1:6rdJFnhkXnzGOJbvkrdv4t9nLwKcVA+tmbQeUlkIzrU= -github.com/hashicorp/go-hclog v0.0.0-20170716174523-b4e5765d1e5f/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-getter v1.3.0 h1:pFMSFlI9l5NaeuzkpE3L7BYk9qQ9juTAgXW/H0cqxcU= +github.com/hashicorp/go-getter v1.3.0/go.mod h1:/O1k/AizTN0QmfEKknCYGvICeyKUDqCYA8vvWtGWDeQ= +github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= +github.com/hashicorp/go-hclog v0.0.0-20181001195459-61d530d6c27f/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-immutable-radix v0.0.0-20180129170900-7f3cd4390caa/go.mod h1:6ij3Z20p+OhOkCSrA0gImAWoHYQRGbnlcuk6XYTiaRw= +github.com/hashicorp/go-msgpack v0.5.4/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v0.0.0-20180717150148-3d5d8f294aa0/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-plugin v0.0.0-20180125190438-e53f54cbf51e/go.mod h1:JSqWYsict+jzcj0+xElxyrBQRPNoiWQuddnxArJ7XHQ= +github.com/hashicorp/go-plugin v1.0.1-0.20190430211030-5692942914bb/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= github.com/hashicorp/go-retryablehttp v0.5.2/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-rootcerts v0.0.0-20160503143440-6bb64b370b90/go.mod h1:o4zcYY1e0GEZI6eSEr+43QDYmuGglw1qSO6qdHUHCgg= -github.com/hashicorp/go-safetemp v0.0.0-20180326211150-b1a1dbde6fdc h1:wAa9fGALVHfjYxZuXRnmuJG2CnwRpJYOTvY6YdErAh0= -github.com/hashicorp/go-safetemp v0.0.0-20180326211150-b1a1dbde6fdc/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= +github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= github.com/hashicorp/go-slug v0.3.0/go.mod h1:I5tq5Lv0E2xcNXNkmx7BSfzi1PsJ2cNjs3cC3LwyhK8= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-tfe v0.3.14/go.mod h1:SuPHR+OcxvzBZNye7nGPfwZTEyd3rWPfLVbCgyZPezM= +github.com/hashicorp/go-sockaddr v0.0.0-20180320115054-6d291a969b86/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-tfe v0.3.16/go.mod h1:SuPHR+OcxvzBZNye7nGPfwZTEyd3rWPfLVbCgyZPezM= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.0.0 h1:21MVWPKDphxa7ineQQTrCU5brh7OuVVAzGOCnnCPtE8= -github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0= +github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f h1:UdxlrJz4JOnY8W+DbLISwf2B8WXEolNRA8BGCwI9jws= github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/hcl2 v0.0.0-20180308163058-5f8ed954abd8 h1:laCE8EKBOUVN6LwBt7Be9IX7i2RQ2cnfbt+Z5a+0PRI= -github.com/hashicorp/hcl2 v0.0.0-20180308163058-5f8ed954abd8/go.mod h1:xp1eMAxqhQKBxz+yQUTsig9bBMRRWRWw+rK3FJmHf/A= -github.com/hashicorp/hil v0.0.0-20170627220502-fa9f258a9250 h1:fooK5IvDL/KIsi4LxF/JH68nVdrBSiGNPhS2JAQjtjo= -github.com/hashicorp/hil v0.0.0-20170627220502-fa9f258a9250/go.mod h1:KHvg/R2/dPtaePb16oW4qIyzkMxXOL38xjRN64adsts= -github.com/hashicorp/logutils v0.0.0-20150609070431-0dc08b1671f3/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/memberlist v0.0.0-20170208211506-23ad4b7d7b38/go.mod h1:ncdBp14cuox2iFOq3kDiquKU6fqsTBc3W6JvZwjxxsE= -github.com/hashicorp/serf v0.8.2-0.20171022020050-c20a0b1b1ea9/go.mod h1:h/Ru6tmZazX7WO/GDmwdpS975F019L4t5ng5IgwbNrE= -github.com/hashicorp/terraform v0.11.14 h1:2PnZWaQ9Apr+6QciC7JY0NsnPq7B+4Le406gn8ZPmuA= -github.com/hashicorp/terraform v0.11.14/go.mod h1:bES0uNzlesKO5m01e2zTbu1jO2KNXd1gvj22zBIDL3M= -github.com/hashicorp/vault v0.0.0-20161029210149-9a60bf2a50e4/go.mod h1:KfSyffbKxoVyspOdlaGVjIuwLobi07qD1bAbosPMpP0= -github.com/hashicorp/yamux v0.0.0-20160720233140-d1caa6c97c9f/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/hashicorp/hcl2 v0.0.0-20181208003705-670926858200/go.mod h1:ShfpTh661oAaxo7VcNxg0zcZW6jvMa7Moy2oFx7e5dE= +github.com/hashicorp/hcl2 v0.0.0-20190515223218-4b22149b7cef h1:xZRvbcwHY8zhaxDwgkmpAp2emwZkVn7p3gat0zhq2X0= +github.com/hashicorp/hcl2 v0.0.0-20190515223218-4b22149b7cef/go.mod h1:4oI94iqF3GB10QScn46WqbG0kgTUpha97SAzzg2+2ec= +github.com/hashicorp/hil v0.0.0-20190212112733-ab17b08d6590 h1:2yzhWGdgQUWZUCNK+AoO35V+HTsgEmcM4J9IkArh7PI= +github.com/hashicorp/hil v0.0.0-20190212112733-ab17b08d6590/go.mod h1:n2TSygSNwsLJ76m8qFXTSc7beTb+auJxYdqrnoqwZWE= +github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/memberlist v0.1.0/go.mod h1:ncdBp14cuox2iFOq3kDiquKU6fqsTBc3W6JvZwjxxsE= +github.com/hashicorp/serf v0.0.0-20160124182025-e4ec8cc423bb/go.mod h1:h/Ru6tmZazX7WO/GDmwdpS975F019L4t5ng5IgwbNrE= +github.com/hashicorp/terraform v0.12.1 h1:A56pUiGbDZ372cvDKWixzVciTGZkqZ01hH58GTNQ4lg= +github.com/hashicorp/terraform v0.12.1/go.mod h1:T3xp83QKah46oRMg37OPBbEVjEwokcGdn7+aNQtQbKo= +github.com/hashicorp/terraform-config-inspect v0.0.0-20190327195015-8022a2663a70 h1:oZm5nE11yhzsTRz/YrUyDMSvixePqjoZihwn8ipuOYI= +github.com/hashicorp/terraform-config-inspect v0.0.0-20190327195015-8022a2663a70/go.mod h1:ItvqtvbC3K23FFET62ZwnkwtpbKZm8t8eMcWjmVVjD8= +github.com/hashicorp/vault v0.10.4/go.mod h1:KfSyffbKxoVyspOdlaGVjIuwLobi07qD1bAbosPMpP0= +github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/joyent/triton-go v0.0.0-20180313100802-d8f9c0314926/go.mod h1:U+RSyWxWd04xTqnuOQxnai7XGS2PrPY2cfGoDKtMHjA= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/kardianos/osext v0.0.0-20160811001526-c2c54e542fb7/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= +github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= +github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= github.com/keybase/go-crypto v0.0.0-20161004153544-93f5b35093ba/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lusis/go-artifactory v0.0.0-20160115162124-7e4ce345df82/go.mod h1:y54tfGmO3NKssKveTEFFzH8C/akrSOy/iW9qEAUDV84= github.com/magefile/mage v1.8.0 h1:mzL+xIopvPURVBwHG9A50JcjBO+xV3b5iZ7khFRI+5E= github.com/magefile/mage v1.8.0/go.mod h1:IUDi13rsHje59lecXokTfGX0QIzO45uVPlXnJYsXepA= -github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/masterzen/azure-sdk-for-go v0.0.0-20161014135628-ee4f0065d00c/go.mod h1:mf8fjOu33zCqxUjuiU3I8S1lJMyEAlH+0F2+M5xl3hE= +github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= github.com/masterzen/simplexml v0.0.0-20160608183007-4572e39b1ab9/go.mod h1:kCEbxUJlNDEBNbdQMkPSp6yaKcRXVI6f4ddk8Riv4bc= -github.com/masterzen/winrm v0.0.0-20180224160350-7e40f93ae939/go.mod h1:CfZSN7zwz5gJiFhZJz49Uzk7mEBHIceWmbFmYx7Hf7E= -github.com/mattn/go-colorable v0.0.0-20160220075935-9cbef7c35391/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-isatty v0.0.0-20161123143637-30a891c33c7c h1:YHHK/dEmr2Jo1cWD1VMB2waEeHJhHFp3CEylwWy/VcY= -github.com/mattn/go-isatty v0.0.0-20161123143637-30a891c33c7c/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-shellwords v1.0.1/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +github.com/masterzen/winrm v0.0.0-20190223112901-5e5c9a7fe54b/go.mod h1:wr1VqkwW0AB5JS0QLy5GpVMS9E3VtRoSYXUYyVk46KY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-shellwords v1.0.4/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/mitchellh/cli v0.0.0-20171129193617-33edc47170b5 h1:OYr3N2fY3e3kP/x/d81CJXlcZrIV2hH8gPnuRLpiME4= -github.com/mitchellh/cli v0.0.0-20171129193617-33edc47170b5/go.mod h1:oGumspjLm2kTyiT1QMGpFqRlmxnKHfCvhZEVnx+5UeE= -github.com/mitchellh/colorstring v0.0.0-20150917214807-8631ce90f286/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= -github.com/mitchellh/copystructure v0.0.0-20170525013902-d23ffcb85de3 h1:dECZqiJYhKdj9QlLpiQaRDXHDXRTdiyZI3owdDGhlYY= -github.com/mitchellh/copystructure v0.0.0-20170525013902-d23ffcb85de3/go.mod h1:eOsF2yLPlBBJPvD+nhl5QMTBSOBbOph6N7j/IDUw7PY= -github.com/mitchellh/go-homedir v0.0.0-20161203194507-b8bc1bf76747/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-linereader v0.0.0-20141013185533-07bab5fdd958/go.mod h1:OaY7UOoTkkrX3wRwjpYRKafIkkyeD0UtweSHAWWiqQM= -github.com/mitchellh/go-testing-interface v0.0.0-20170730050907-9a441910b168 h1:FW/lWFII8EehRx+hVNy5OkkIhWXz9NC69vO5Zr2RExY= -github.com/mitchellh/go-testing-interface v0.0.0-20170730050907-9a441910b168/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM= +github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= +github.com/miekg/dns v1.0.8/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0 h1:iGBIsUe3+HZ/AD/Vd7DErOt5sU9fa8Uj7A2s1aggv1Y= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= +github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= +github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-linereader v0.0.0-20190213213312-1b945b3263eb/go.mod h1:OaY7UOoTkkrX3wRwjpYRKafIkkyeD0UtweSHAWWiqQM= +github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/hashstructure v0.0.0-20160209213820-6b17d669fac5 h1:h+4fp6yIoLPf/K2egDK3kvYM2zqb28gJIWWMiDzBdKM= -github.com/mitchellh/hashstructure v0.0.0-20160209213820-6b17d669fac5/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= -github.com/mitchellh/mapstructure v0.0.0-20170307201123-53818660ed49/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/hashstructure v1.0.0 h1:ZkRJX1CyOoTkar7p/mLS5TZU4nJ1Rn/F8u9dGS02Q3Y= +github.com/mitchellh/hashstructure v1.0.0/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/panicwrap v0.0.0-20161208170302-ba9e1a65e0f7/go.mod h1:QuAqW7/z+iv6aWFJdrA8kCbsF0OOJVKCICqTcYBexuY= -github.com/mitchellh/prefixedio v0.0.0-20151214002211-6e6954073784/go.mod h1:kB1naBgV9ORnkiTVeyJOI1DavaJkG4oNIq0Af6ZVKUo= -github.com/mitchellh/reflectwalk v0.0.0-20170726202117-63d60e9d0dbc h1:gqYjvctjtX4GHzgfutJxZpvZ7XhGwQLGR5BASwhpO2o= -github.com/mitchellh/reflectwalk v0.0.0-20170726202117-63d60e9d0dbc/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/panicwrap v0.0.0-20190213213626-17011010aaa4/go.mod h1:YYMf4xtQnR8LRC0vKi3afvQ5QwRPQ17zjcpkBCufb+I= +github.com/mitchellh/prefixedio v0.0.0-20190213213902-5733675afd51/go.mod h1:kB1naBgV9ORnkiTVeyJOI1DavaJkG4oNIq0Af6ZVKUo= +github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= +github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/packer-community/winrmcp v0.0.0-20180102160824-81144009af58/go.mod h1:f6Izs6JvFTdnRbziASagjZ2vmf55NSIkC/weStxCHqk= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.0.0-20170505043639-c605e284fe17/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +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/posener/complete v0.0.0-20171219111128-6bee943216c8 h1:lcb1zvdlaZyEbl2OXifN3uOYYyIvllofUbmp9bwbL+0= -github.com/posener/complete v0.0.0-20171219111128-6bee943216c8/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.1 h1:LrvDIY//XNo65Lq84G/akBuMGlawHvGBABv8f/ZN6DI= +github.com/posener/complete v1.2.1/go.mod h1:6gapUrK/U1TAN7ciCoNRIdVC5sbdBTUh1DKN0g6uH7E= +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.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_model v0.0.0-20170216185247-6f3806018612/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/ryanuber/columnize v0.0.0-20161220214920-0fbbb3f0e3fb/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/satori/go.uuid v0.0.0-20160927100844-b061729afc07/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/satori/uuid v0.0.0-20160927100844-b061729afc07/go.mod h1:B8HLsPLik/YNn6KKWVMDJ8nzCL8RP5WyfsnmvnAEwIU= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= +github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= +github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= +github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= +github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= +github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= +github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg= +github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw= +github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y= +github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= +github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ= +github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I= +github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0= +github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= +github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= +github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= +github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= +github.com/sirupsen/logrus v1.1.1/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spf13/afero v1.0.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.4 h1:S0tLZ3VOKl2Te0hpq8+ke0eSJPfCnNTPiDlsfwi1/NE= -github.com/spf13/cobra v0.0.4/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= +github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= +github.com/spf13/afero v1.2.1 h1:qgMbHoJbPbw579P+1zVY+6n4nIFuIchaIjzZ/I/Yq8M= +github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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/svanharmelen/jsonapi v0.0.0-20180618144545-0c0828c3f16d/go.mod h1:BSTlc8jOjh0niykqEGVXOLXdi9o0r0kR8tCYiMvjFgw= +github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/terraform-providers/terraform-provider-openstack v1.15.0/go.mod h1:2aQ6n/BtChAl1y2S60vebhyJyZXBsuAI5G4+lHrT1Ew= -github.com/ugorji/go v0.0.0-20170107133203-ded73eae5db7/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ulikunitz/xz v0.5.4 h1:zATC2OoZ8H1TZll3FpbX+ikwmadbO699PE06cIkm9oU= -github.com/ulikunitz/xz v0.5.4/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= -github.com/xanzy/ssh-agent v0.2.0/go.mod h1:0NyE30eGUDliuLEHJgYte/zncp2zdTStcOnWhgSqHD8= +github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go v0.0.0-20180813092308-00b869d2f4a5/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= +github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok= +github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= +github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= +github.com/vmihailenco/msgpack v4.0.1+incompatible h1:RMF1enSPeKTlXrXdOcqjFUElywVZjjC6pqse21bKbEU= +github.com/vmihailenco/msgpack v4.0.1+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= +github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/zclconf/go-cty v0.0.0-20180302160414-49fa5e03c418 h1:uZKhc0PzQtIg+6+BqQU1m0zzcIgY2hHJk/Xwf00QUNw= -github.com/zclconf/go-cty v0.0.0-20180302160414-49fa5e03c418/go.mod h1:LnDKxj8gN4aatfXUqmUNooaDjvmDcLPbAN3hYBIVoJE= -golang.org/x/crypto v0.0.0-20180211211603-9de5f2eaf759/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9 h1:mKdxBk7AujPs8kU4m80U72y/zjbZ3UcXC7dClwKbUI0= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd h1:HuTn7WObtcDo9uEEU7rEqL0jYthdXAmZ6PP+meazmaU= +github.com/zclconf/go-cty v0.0.0-20181129180422-88fbe721e0f8/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= +github.com/zclconf/go-cty v0.0.0-20190426224007-b18a157db9e2/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= +github.com/zclconf/go-cty v0.0.0-20190516203816-4fecf87372ec h1:MSeYjmyjucsFbecMTxg63ASg23lcSARP/kr9sClTFfk= +github.com/zclconf/go-cty v0.0.0-20190516203816-4fecf87372ec/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= +go.opencensus.io v0.18.0 h1:Mk5rgZcggtbvtAun5aJzAtjKKN/t0R3jJPlWILlv938= +go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= +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.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= +golang.org/x/crypto v0.0.0-20180816225734-aabede6cba87/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190222235706-ffb98f73852f/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-20190426145343-a29dc8fdc734 h1:p/H982KKEjUnLJkM3tt/LemDnOc1GiZL5FCVlORJ5zo= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180811021610-c39426892332/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-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181106065722-10aee1819953/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-20181129055619-fae4c4e3ad76/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/oauth2 v0.0.0-20170928010508-bb50c06baba3/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +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-20190502183928-7f726cade0ab h1:9RfW3ktsOZxgo9YNbBAjq1FWzc/igwEcUzZz8IXgSbk= +golang.org/x/net v0.0.0-20190502183928-7f726cade0ab/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190220154721-9b3c75971fc9 h1:pfyU+l9dEu0vZzDDMsdAKa1gZbJYEn6urYXj/+Xkz7s= +golang.org/x/oauth2 v0.0.0-20190220154721-9b3c75971fc9/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= +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/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a h1:1n5lsVfiQW3yfsRGu98756EH1YthsFqr/5mxHduZW2A= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/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-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181213200352-4d1cda033e06/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/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-20190221075227-b4e8571b14e0/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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82 h1:vsphBvatvfbhlb4PO1BYSr9dzugGxJ/SQHoNufZJq1w= +golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +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= -google.golang.org/api v0.0.0-20171005000305-7a7376eff6a5/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= -google.golang.org/appengine v0.0.0-20150527042145-b667a5000b08/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/genproto v0.0.0-20171002232614-f676e0f3ac63/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/grpc v0.0.0-20170809211603-7657092a1303/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/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-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.1.0 h1:K6z2u68e86TPdSdefXdzvXgR1zEMa+459vBSfWYAZkI= +google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= +google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922 h1:mBVYJnbrXLA/ZCBTCe7PtEgAUP+1bg92qTaFoPHdz+8= +google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922/go.mod h1:L3J43x8/uS+qIUoksaLKe6OS3nUKxOKuIFz1sl2/jx4= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.18.0 h1:IZl7mfBGfbhYx2p2rKRtYgDFw6SBz+kclmxYrCksPPA= +google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.0.0-20170407172122-cd8b52f8269e/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= +sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= +sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/infra/modules/providers/azure/api-mgmt/main.tf b/infra/modules/providers/azure/api-mgmt/main.tf deleted file mode 100644 index 8b13789..0000000 --- a/infra/modules/providers/azure/api-mgmt/main.tf +++ /dev/null @@ -1 +0,0 @@ - diff --git a/infra/modules/providers/azure/api-mgmt/output.tf b/infra/modules/providers/azure/api-mgmt/output.tf deleted file mode 100644 index 8b13789..0000000 --- a/infra/modules/providers/azure/api-mgmt/output.tf +++ /dev/null @@ -1 +0,0 @@ - diff --git a/infra/modules/providers/azure/api-mgmt/variables.tf b/infra/modules/providers/azure/api-mgmt/variables.tf deleted file mode 100644 index 8b13789..0000000 --- a/infra/modules/providers/azure/api-mgmt/variables.tf +++ /dev/null @@ -1 +0,0 @@ - diff --git a/infra/modules/providers/azure/api-mgmt/versions.tf b/infra/modules/providers/azure/api-mgmt/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/infra/modules/providers/azure/api-mgmt/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/infra/modules/providers/azure/app-gateway/main.tf b/infra/modules/providers/azure/app-gateway/main.tf index 60fd8c0..dc0bf12 100644 --- a/infra/modules/providers/azure/app-gateway/main.tf +++ b/infra/modules/providers/azure/app-gateway/main.tf @@ -1,5 +1,5 @@ data "azurerm_resource_group" "appgateway" { - name = "${var.resource_group_name}" + name = var.resource_group_name } locals { @@ -9,54 +9,54 @@ locals { } resource "azurerm_application_gateway" "appgateway" { - name = "${var.appgateway_name}" - resource_group_name = "${data.azurerm_resource_group.appgateway.name}" - location = "${data.azurerm_resource_group.appgateway.location}" - tags = "${var.resource_tags}" + name = var.appgateway_name + resource_group_name = data.azurerm_resource_group.appgateway.name + location = data.azurerm_resource_group.appgateway.location + tags = var.resource_tags sku { - name = "${var.appgateway_sku_name}" - tier = "${var.appgateway_tier}" - capacity = "${var.appgateway_capacity}" + name = var.appgateway_sku_name + tier = var.appgateway_tier + capacity = var.appgateway_capacity } gateway_ip_configuration { - name = "${var.appgateway_ipconfig_name}" - subnet_id = "${var.virtual_network_subnet_id}" + name = var.appgateway_ipconfig_name + subnet_id = var.virtual_network_subnet_id } frontend_port { - name = "${var.appgateway_frontend_port_name}" - port = "${var.frontend_http_port}" + name = var.appgateway_frontend_port_name + port = var.frontend_http_port } frontend_ip_configuration { - name = "${var.appgateway_frontend_ip_configuration_name}" - public_ip_address_id = "${var.public_pip_id}" + name = var.appgateway_frontend_ip_configuration_name + public_ip_address_id = var.public_pip_id } ssl_certificate { - name = "${local.ssl_certificate_name}" - data = "${var.appgateway_ssl_private_pfx}" + name = local.ssl_certificate_name + data = var.appgateway_ssl_private_pfx password = "" } authentication_certificate { - name = "${local.authentication_certificate_name}" - data = "${var.appgateway_ssl_public_cert}" + name = local.authentication_certificate_name + data = var.appgateway_ssl_public_cert } backend_address_pool { - name = "${var.appgateway_backend_address_pool_name}" - fqdns = ["${var.backendpool_fqdns}"] + name = var.appgateway_backend_address_pool_name + fqdns = var.backendpool_fqdns } backend_http_settings { - name = "${var.appgateway_backend_http_setting_name}" - cookie_based_affinity = "${var.backend_http_cookie_based_affinity}" - port = "${var.backend_http_port}" - protocol = "${var.backend_http_protocol}" - probe_name = "${local.backend_probe_name}" + name = var.appgateway_backend_http_setting_name + cookie_based_affinity = var.backend_http_cookie_based_affinity + port = var.backend_http_port + protocol = var.backend_http_protocol + probe_name = local.backend_probe_name request_timeout = 1 pick_host_name_from_backend_address = true } @@ -64,43 +64,42 @@ resource "azurerm_application_gateway" "appgateway" { # TODO This is locked into a single api endpoint... We'll need to eventually support multiple endpoints # but the count property is only supported at the resource level. probe { - name = "${local.backend_probe_name}" - protocol = "${var.backend_http_protocol}" + name = local.backend_probe_name + protocol = var.backend_http_protocol path = "/" - interval = "30" - timeout = "30" - unhealthy_threshold = "3" + interval = 30 + timeout = 30 + unhealthy_threshold = 3 pick_host_name_from_backend_http_settings = true } http_listener { - name = "${var.appgateway_listener_name}" - frontend_ip_configuration_name = "${var.appgateway_frontend_ip_configuration_name}" - frontend_port_name = "${var.appgateway_frontend_port_name}" - protocol = "${var.http_listener_protocol}" - ssl_certificate_name = "${local.ssl_certificate_name}" + name = var.appgateway_listener_name + frontend_ip_configuration_name = var.appgateway_frontend_ip_configuration_name + frontend_port_name = var.appgateway_frontend_port_name + protocol = var.http_listener_protocol + ssl_certificate_name = local.ssl_certificate_name } waf_configuration { - enabled = "true" - firewall_mode = "${var.appgateway_waf_config_firewall_mode}" + enabled = true + firewall_mode = var.appgateway_waf_config_firewall_mode rule_set_type = "OWASP" rule_set_version = "3.0" } request_routing_rule { - name = "${var.appgateway_request_routing_rule_name}" - http_listener_name = "${var.appgateway_listener_name}" - rule_type = "${var.request_routing_rule_type}" - backend_address_pool_name = "${var.appgateway_backend_address_pool_name}" - backend_http_settings_name = "${var.appgateway_backend_http_setting_name}" + name = var.appgateway_request_routing_rule_name + http_listener_name = var.appgateway_listener_name + rule_type = var.request_routing_rule_type + backend_address_pool_name = var.appgateway_backend_address_pool_name + backend_http_settings_name = var.appgateway_backend_http_setting_name } } data "external" "app_gw_health" { - depends_on = [ - "azurerm_application_gateway.appgateway", - ] + depends_on = [azurerm_application_gateway.appgateway] - program = ["az", "network", "application-gateway", "show-backend-health", "-g", "${data.azurerm_resource_group.appgateway.name}", "-n", "${var.appgateway_name}", "-o", "json", "--query", "backendAddressPools[0].backendHttpSettingsCollection[0].servers[0].{address:address,health:health}"] + program = ["az", "network", "application-gateway", "show-backend-health", "-g", data.azurerm_resource_group.appgateway.name, "-n", var.appgateway_name, "-o", "json", "--query", "backendAddressPools[0].backendHttpSettingsCollection[0].servers[0].{address:address,health:health}"] } + diff --git a/infra/modules/providers/azure/app-gateway/output.tf b/infra/modules/providers/azure/app-gateway/output.tf index 7173ba1..f64c7ec 100644 --- a/infra/modules/providers/azure/app-gateway/output.tf +++ b/infra/modules/providers/azure/app-gateway/output.tf @@ -1,22 +1,23 @@ output "appgateway_name" { description = "The name of the Application Gateway created" - value = "${azurerm_application_gateway.appgateway.name}" + value = azurerm_application_gateway.appgateway.name } output "appgateway_ipconfig" { description = "The Application Gateway IP Configuration" - value = "${azurerm_application_gateway.appgateway.gateway_ip_configuration}" + value = azurerm_application_gateway.appgateway.gateway_ip_configuration } output "appgateway_frontend_ip_configuration" { description = "The Application Gateway Frontend IP Configuration" - value = "${azurerm_application_gateway.appgateway.frontend_ip_configuration}" + value = azurerm_application_gateway.appgateway.frontend_ip_configuration } output "appgateway_health_probe_backend_status" { - value = "${lookup(data.external.app_gw_health.result, "health")}" + value = data.external.app_gw_health.result["health"] } output "app_gateway_health_probe_backend_address" { - value = "${lookup(data.external.app_gw_health.result, "address")}" + value = data.external.app_gw_health.result["address"] } + diff --git a/infra/modules/providers/azure/app-gateway/variables.tf b/infra/modules/providers/azure/app-gateway/variables.tf index bb52390..c450da8 100644 --- a/infra/modules/providers/azure/app-gateway/variables.tf +++ b/infra/modules/providers/azure/app-gateway/variables.tf @@ -1,150 +1,149 @@ -# TODO convert all numeric string to true number scalar types once we're migrated to terraform V12. This -# change should take place across both module and template configuration defintions. variable "resource_group_name" { description = "Resource group name that the app gateway will be created in." - type = "string" + type = string } variable "virtual_network_name" { description = "Virtual Network name that the app gateway will be created in." - type = "string" + type = string } variable "virtual_network_subnet_id" { description = "Subnet id that the app gateway will be created in." - type = "string" + type = string } variable "appgateway_name" { description = "The name of the application gateway" - type = "string" + type = string } variable "appgateway_ssl_private_pfx" { description = "PFX certificate" - type = "string" + type = string } variable "appgateway_ssl_public_cert" { description = "The contents of the Authentication Certificate which should be used" - type = "string" + type = string } variable "public_pip_id" { description = "the public ip resource id of the frontend configuration" - type = "string" + type = string } variable "resource_tags" { description = "Map of tags to apply to taggable resources in this module. By default the taggable resources are tagged with the name defined above and this map is merged in" - type = "map" + type = map(string) default = {} } variable "appgateway_frontend_port_name" { description = "The Frontend Port Name for the Appication Gateway to be created" - type = "string" + type = string default = "https-frontend-port" } variable "appgateway_sku_name" { description = "The SKU for the Appication Gateway to be created" - type = "string" + type = string default = "WAF_Medium" } variable "appgateway_tier" { description = "The tier of the application gateway. Small/Medium/Large. More details can be found at https://azure.microsoft.com/en-us/pricing/details/application-gateway/" - type = "string" + type = string default = "WAF" } variable "appgateway_capacity" { description = "The capacity of application gateway to be created" - type = "string" + type = number default = 2 } variable "appgateway_ipconfig_name" { description = "The IP Config Name for the Appication Gateway to be created" - type = "string" + type = string default = "subnet" } variable "frontend_http_port" { description = "The frontend port for the Appication Gateway to be created" - type = "string" + type = number default = 443 } variable "appgateway_frontend_ip_configuration_name" { description = "The Frontend IP configuration name for the Appication Gateway to be created" - type = "string" + type = string default = "frontend" } variable "appgateway_backend_address_pool_name" { description = "The Backend Addres Pool Name for the Appication Gateway to be created" - type = "string" + type = string default = "backend_pool" } variable "appgateway_backend_http_setting_name" { description = "The Backend Http Settings Name for the Appication Gateway to be created" - type = "string" + type = string default = "backend_settings" } variable "backend_http_cookie_based_affinity" { description = "The Backend Http cookie based affinity for the Appication Gateway to be created" - type = "string" + type = string default = "Disabled" } variable "backend_http_port" { description = "The backend port for the Appication Gateway to be created" - type = "string" + type = number default = 443 } variable "backend_http_protocol" { description = "The backend protocol for the Appication Gateway to be created" - type = "string" + type = string default = "Https" } variable "http_listener_protocol" { description = "The Http Listener protocol for the Appication Gateway to be created" - type = "string" + type = string default = "Https" } variable "appgateway_listener_name" { description = "The Listener Name for the Appication Gateway to be created" - type = "string" + type = string default = "http_proxy_listener" } variable "appgateway_request_routing_rule_name" { description = "The rule name to request routing for the Appication Gateway to be created" - type = "string" + type = string default = "request_proxy_routing_rule" } variable "request_routing_rule_type" { description = "The rule type to request routing for the Appication Gateway to be created" - type = "string" + type = string default = "Basic" } variable "appgateway_waf_config_firewall_mode" { description = "The firewall mode on the waf gateway" - type = "string" + type = string default = "Prevention" } variable "backendpool_fqdns" { description = "A list of FQDN's which should be part of the Backend Address Pool." - type = "list" + type = list(string) default = [] } + diff --git a/infra/modules/providers/azure/app-gateway/versions.tf b/infra/modules/providers/azure/app-gateway/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/infra/modules/providers/azure/app-gateway/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/infra/modules/providers/azure/app-insights/main.tf b/infra/modules/providers/azure/app-insights/main.tf index b268249..2e58334 100644 --- a/infra/modules/providers/azure/app-insights/main.tf +++ b/infra/modules/providers/azure/app-insights/main.tf @@ -1,11 +1,12 @@ data "azurerm_resource_group" "appinsights" { - name = "${var.service_plan_resource_group_name}" + name = var.service_plan_resource_group_name } resource "azurerm_application_insights" "appinsights" { - name = "${var.appinsights_name}" - resource_group_name = "${data.azurerm_resource_group.appinsights.name}" - location = "${data.azurerm_resource_group.appinsights.location}" - application_type = "${var.appinsights_application_type}" - tags = "${var.resource_tags}" + name = var.appinsights_name + resource_group_name = data.azurerm_resource_group.appinsights.name + location = data.azurerm_resource_group.appinsights.location + application_type = var.appinsights_application_type + tags = var.resource_tags } + diff --git a/infra/modules/providers/azure/app-insights/output.tf b/infra/modules/providers/azure/app-insights/output.tf index 0bce233..a65658e 100644 --- a/infra/modules/providers/azure/app-insights/output.tf +++ b/infra/modules/providers/azure/app-insights/output.tf @@ -1,10 +1,11 @@ output "app_insights_app_id" { description = "The App ID associated with this Application Insights component" - value = "${azurerm_application_insights.appinsights.app_id}" + value = azurerm_application_insights.appinsights.app_id } output "app_insights_instrumentation_key" { description = "The Instrumentation Key for this Application Insights component." - value = "${azurerm_application_insights.appinsights.instrumentation_key}" + value = azurerm_application_insights.appinsights.instrumentation_key sensitive = true } + diff --git a/infra/modules/providers/azure/app-insights/variables.tf b/infra/modules/providers/azure/app-insights/variables.tf index 9d3d6a9..a9a474e 100644 --- a/infra/modules/providers/azure/app-insights/variables.tf +++ b/infra/modules/providers/azure/app-insights/variables.tf @@ -1,20 +1,21 @@ variable "service_plan_resource_group_name" { description = "The name of the resource group in which the service plan was created." - type = "string" + type = string } variable "resource_tags" { description = "Map of tags to apply to taggable resources in this module (enter as a set of curly braces containing key-value pairs, as in: {\"tag1\" = \"value1\", \"tag2\" = \"value2\"}). By default the taggable resources are tagged with the name defined above and this map is merged in" - type = "map" + type = map(string) default = {} } variable "appinsights_name" { description = "Name of the App Insights to create" - type = "string" + type = string } variable "appinsights_application_type" { description = "Type of the App Insights Application. Valid values are ios for iOS, java for Java web, MobileCenter for App Center, Node.JS for Node.js, other for General, phone for Windows Phone, store for Windows Store and web for ASP.NET." - type = "string" + type = string } + diff --git a/infra/modules/providers/azure/app-insights/versions.tf b/infra/modules/providers/azure/app-insights/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/infra/modules/providers/azure/app-insights/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/infra/modules/providers/azure/app-monitoring/main.tf b/infra/modules/providers/azure/app-monitoring/main.tf index cde1fd1..891617e 100644 --- a/infra/modules/providers/azure/app-monitoring/main.tf +++ b/infra/modules/providers/azure/app-monitoring/main.tf @@ -4,40 +4,41 @@ locals { } resource "azurerm_monitor_action_group" "appmonitoring" { - count = "${var.action_group_email_receiver == "" ? 0 : 1}" - name = "${var.action_group_name}" - resource_group_name = "${var.resource_group_name}" - short_name = "${var.action_group_short_name}" + count = var.action_group_email_receiver == "" ? 0 : 1 + name = var.action_group_name + resource_group_name = var.resource_group_name + short_name = var.action_group_short_name email_receiver { - name = "${var.action_group_email_receiver_name}" - email_address = "${var.action_group_email_receiver}" + name = var.action_group_email_receiver_name + email_address = var.action_group_email_receiver } } resource "azurerm_monitor_metric_alert" "appmonitoring" { - count = "${var.action_group_email_receiver == "" ? 0 : 1}" - name = "${var.metric_alert_name}" - resource_group_name = "${azurerm_monitor_action_group.appmonitoring.resource_group_name}" - scopes = ["${var.resource_ids}"] - frequency = "${var.metric_alert_frequency}" - window_size = "${var.metric_alert_period}" + count = var.action_group_email_receiver == "" ? 0 : 1 + name = var.metric_alert_name + resource_group_name = azurerm_monitor_action_group.appmonitoring[0].resource_group_name + scopes = var.resource_ids + frequency = var.metric_alert_frequency + window_size = var.metric_alert_period criteria { - metric_namespace = "${var.metric_alert_criteria_namespace}" - metric_name = "${var.metric_alert_criteria_name}" - aggregation = "${var.metric_alert_criteria_aggregation}" - operator = "${var.metric_alert_criteria_operator}" - threshold = "${var.metric_alert_criteria_threshold}" + metric_namespace = var.metric_alert_criteria_namespace + metric_name = var.metric_alert_criteria_name + aggregation = var.metric_alert_criteria_aggregation + operator = var.metric_alert_criteria_operator + threshold = var.metric_alert_criteria_threshold dimension { - name = "${local.scaling_name}" - operator = "${local.scaling_operator}" - values = "${var.scaling_values}" + name = local.scaling_name + operator = local.scaling_operator + values = var.scaling_values } } action { - action_group_id = "${azurerm_monitor_action_group.appmonitoring.id}" + action_group_id = azurerm_monitor_action_group.appmonitoring[0].id } } + diff --git a/infra/modules/providers/azure/app-monitoring/output.tf b/infra/modules/providers/azure/app-monitoring/output.tf index 85c8205..2fb5cc6 100644 --- a/infra/modules/providers/azure/app-monitoring/output.tf +++ b/infra/modules/providers/azure/app-monitoring/output.tf @@ -1,4 +1,5 @@ output "rule_resource_id" { description = "The id of a metric alert rule." - value = "${azurerm_monitor_metric_alert.appmonitoring.*.id}" + value = azurerm_monitor_metric_alert.appmonitoring.*.id } + diff --git a/infra/modules/providers/azure/app-monitoring/variables.tf b/infra/modules/providers/azure/app-monitoring/variables.tf index 951d591..a1f6dcb 100644 --- a/infra/modules/providers/azure/app-monitoring/variables.tf +++ b/infra/modules/providers/azure/app-monitoring/variables.tf @@ -1,81 +1,82 @@ variable "resource_group_name" { description = "The name of the resource group." - type = "string" + type = string } # action group attributes variable "action_group_name" { description = "The name of the action group." - type = "string" + type = string } variable "action_group_email_receiver" { description = "The e-mail receiver for an alert rule resource." - type = "string" + type = string default = "" } variable "action_group_email_receiver_name" { description = "The e-mail receiver name for an alert group." - type = "string" + type = string default = "E-mail Receiver" } variable "action_group_short_name" { description = "The abbreviated name of the action group." - type = "string" + type = string default = "Notify" } # metric alert attributes variable "resource_ids" { description = "Resource Ids to be monitored." - type = "list" + type = list(string) } variable "metric_alert_name" { description = "The display name of a group of metric alert criteria." - type = "string" + type = string } variable "metric_alert_criteria_name" { description = "A predefined Azure resource alert monitoring rule name." - type = "string" + type = string } variable "metric_alert_criteria_namespace" { description = "A monitored resource namespace that holds metric alert criteria." - type = "string" + type = string } variable "metric_alert_criteria_aggregation" { description = "The calculation used for building metric alert criteria." - type = "string" + type = string } variable "metric_alert_criteria_operator" { description = "A logical operator used for building metric alert criteria." - type = "string" + type = string } variable "metric_alert_criteria_threshold" { description = "The criteria threshold value that activates the metric alert." - type = "string" + type = string } variable "scaling_values" { description = "App instance names made available from app service plan scaling options." - type = "list" + type = list(string) } variable "metric_alert_frequency" { description = "The frequency with which the metric alert checks if the conditions are met." - type = "string" + type = string default = "PT1M" } variable "metric_alert_period" { description = "The look back window over which metric values are checked." - type = "string" + type = string default = "PT5M" } + diff --git a/infra/modules/providers/azure/app-monitoring/versions.tf b/infra/modules/providers/azure/app-monitoring/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/infra/modules/providers/azure/app-monitoring/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/infra/modules/providers/azure/app-service/main.tf b/infra/modules/providers/azure/app-service/main.tf index 6665b45..2a10bdb 100644 --- a/infra/modules/providers/azure/app-service/main.tf +++ b/infra/modules/providers/azure/app-service/main.tf @@ -4,35 +4,35 @@ locals { } data "azurerm_resource_group" "appsvc" { - name = "${var.service_plan_resource_group_name}" + name = var.service_plan_resource_group_name } data "azurerm_app_service_plan" "appsvc" { - name = "${var.service_plan_name}" - resource_group_name = "${data.azurerm_resource_group.appsvc.name}" + name = var.service_plan_name + resource_group_name = data.azurerm_resource_group.appsvc.name } resource "azurerm_app_service" "appsvc" { name = "${lower(element(keys(var.app_service_name), count.index))}-${lower(terraform.workspace)}" - resource_group_name = "${data.azurerm_resource_group.appsvc.name}" - location = "${data.azurerm_resource_group.appsvc.location}" - app_service_plan_id = "${data.azurerm_app_service_plan.appsvc.id}" - tags = "${var.resource_tags}" - count = "${length(keys(var.app_service_name))}" + resource_group_name = data.azurerm_resource_group.appsvc.name + location = data.azurerm_resource_group.appsvc.location + app_service_plan_id = data.azurerm_app_service_plan.appsvc.id + tags = var.resource_tags + count = length(keys(var.app_service_name)) - app_settings { - WEBSITES_ENABLE_APP_SERVICE_STORAGE = "${var.enable_storage}" - DOCKER_REGISTRY_SERVER_URL = "${var.docker_registry_server_url}" - DOCKER_REGISTRY_SERVER_USERNAME = "${var.docker_registry_server_username}" - DOCKER_REGISTRY_SERVER_PASSWORD = "${var.docker_registry_server_password}" - APPINSIGHTS_INSTRUMENTATIONKEY = "${var.app_insights_instrumentation_key}" - KEYVAULT_URI = "${var.vault_uri}" + app_settings = { + WEBSITES_ENABLE_APP_SERVICE_STORAGE = var.enable_storage + DOCKER_REGISTRY_SERVER_URL = var.docker_registry_server_url + DOCKER_REGISTRY_SERVER_USERNAME = var.docker_registry_server_username + DOCKER_REGISTRY_SERVER_PASSWORD = var.docker_registry_server_password + APPINSIGHTS_INSTRUMENTATIONKEY = var.app_insights_instrumentation_key + KEYVAULT_URI = var.vault_uri } site_config { - linux_fx_version = "${element(values(var.app_service_name), count.index)}" - always_on = "${var.site_config_always_on}" - virtual_network_name = "${var.vnet_name}" + linux_fx_version = element(values(var.app_service_name), count.index) + always_on = var.site_config_always_on + virtual_network_name = var.vnet_name } identity { @@ -43,26 +43,27 @@ resource "azurerm_app_service" "appsvc" { resource "azurerm_app_service_slot" "appsvc_staging_slot" { name = "staging" app_service_name = "${lower(element(keys(var.app_service_name), count.index))}-${lower(terraform.workspace)}" - count = "${length(keys(var.app_service_name))}" - location = "${data.azurerm_resource_group.appsvc.location}" - resource_group_name = "${data.azurerm_resource_group.appsvc.name}" - app_service_plan_id = "${data.azurerm_app_service_plan.appsvc.id}" - depends_on = ["azurerm_app_service.appsvc"] + count = length(keys(var.app_service_name)) + location = data.azurerm_resource_group.appsvc.location + resource_group_name = data.azurerm_resource_group.appsvc.name + app_service_plan_id = data.azurerm_app_service_plan.appsvc.id + depends_on = [azurerm_app_service.appsvc] } resource "azurerm_template_deployment" "access_restriction" { name = "access_restriction" - count = "${var.vnet_name == "" ? 0 : length(keys(var.app_service_name))}" - resource_group_name = "${data.azurerm_resource_group.appsvc.name}" + count = var.vnet_name == "" ? 0 : length(keys(var.app_service_name)) + resource_group_name = data.azurerm_resource_group.appsvc.name parameters = { service_name = "${lower(element(keys(var.app_service_name), count.index))}-${lower(terraform.workspace)}" - vnet_subnet_id = "${var.vnet_subnet_id}" - access_restriction_name = "${local.access_restriction_name}" - access_restriction_description = "${local.access_restriction_description}" + vnet_subnet_id = var.vnet_subnet_id + access_restriction_name = local.access_restriction_name + access_restriction_description = local.access_restriction_description } deployment_mode = "Incremental" - template_body = "${file("${path.module}/azuredeploy.json")}" - depends_on = ["azurerm_app_service.appsvc"] + template_body = file("${path.module}/azuredeploy.json") + depends_on = [azurerm_app_service.appsvc] } + diff --git a/infra/modules/providers/azure/app-service/output.tf b/infra/modules/providers/azure/app-service/output.tf index 7513f3a..2ef3667 100644 --- a/infra/modules/providers/azure/app-service/output.tf +++ b/infra/modules/providers/azure/app-service/output.tf @@ -1,19 +1,20 @@ output "app_service_uri" { description = "The URL of the app service created" - value = ["${azurerm_app_service.appsvc.*.default_site_hostname}"] + value = azurerm_app_service.appsvc.*.default_site_hostname } output "app_service_ids" { description = "The resource ids of the app service created" - value = ["${azurerm_app_service.appsvc.*.id}"] + value = azurerm_app_service.appsvc.*.id } output "app_service_identity_tenant_id" { description = " The Tenant ID for the Service Principal associated with the Managed Service Identity of this App Service." - value = "${azurerm_app_service.appsvc.0.identity.0.tenant_id}" + value = azurerm_app_service.appsvc[0].identity[0].tenant_id } output "app_service_identity_object_ids" { description = " The Principal IDs for the Service Principal associated with the Managed Service Identity for all App Services." - value = ["${azurerm_app_service.appsvc.*.identity.0.principal_id}"] + value = azurerm_app_service.appsvc.*.identity.0.principal_id } + diff --git a/infra/modules/providers/azure/app-service/variables.tf b/infra/modules/providers/azure/app-service/variables.tf index 2c42adf..1c00eca 100644 --- a/infra/modules/providers/azure/app-service/variables.tf +++ b/infra/modules/providers/azure/app-service/variables.tf @@ -1,75 +1,76 @@ variable "service_plan_resource_group_name" { description = "The name of the resource group in which the service plan was created." - type = "string" + type = string } variable "service_plan_name" { description = "The name of the service plan" - type = "string" + type = string } variable "resource_tags" { description = "Map of tags to apply to taggable resources in this module. By default the taggable resources are tagged with the name defined above and this map is merged in" - type = "map" + type = map(string) default = {} } variable "app_service_name" { description = "The name of the app service to be created" - type = "map" + type = map(string) default = {} } variable "enable_storage" { description = "Determines whether or not a storage is attached to the app service." - type = "string" - default = "false" + type = bool + default = false } variable "vault_uri" { description = "Specifies the URI of the Key Vault resource. Providing this will create a new app setting called KEYVAULT_URI containing the uri value." - type = "string" + type = string default = "" } variable "docker_registry_server_url" { description = "The docker registry server URL for app service to be created" - type = "string" + type = string default = "index.docker.io" } variable "docker_registry_server_username" { description = "The docker registry server username for app service to be created" - type = "string" + type = string default = "" } variable "docker_registry_server_password" { description = "The docker registry server password for app service to be created" - type = "string" + type = string default = "" } variable "app_insights_instrumentation_key" { description = "The Instrumentation Key for the Application Insights component used for app service to be created" - type = "string" + type = string default = "" } variable "site_config_always_on" { description = "Should the app be loaded at all times? Defaults to false." - type = "string" - default = "false" + type = bool + default = false } variable "vnet_name" { - description = "The vnet integration name." - type = "string" + description = "The vnet integration name" + type = string default = "" } variable "vnet_subnet_id" { description = "The vnet integration subnet gateway identifier." - type = "string" + type = string default = "" } + diff --git a/infra/modules/providers/azure/app-service/versions.tf b/infra/modules/providers/azure/app-service/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/infra/modules/providers/azure/app-service/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/infra/modules/providers/azure/container-registry/main.tf b/infra/modules/providers/azure/container-registry/main.tf index ba0cf46..421c6b9 100644 --- a/infra/modules/providers/azure/container-registry/main.tf +++ b/infra/modules/providers/azure/container-registry/main.tf @@ -1,12 +1,13 @@ data "azurerm_resource_group" "container_registry" { - name = "${var.resource_group_name}" + name = var.resource_group_name } resource "azurerm_container_registry" "container_registry" { - name = "${var.container_registry_name}" - resource_group_name = "${data.azurerm_resource_group.container_registry.name}" - location = "${data.azurerm_resource_group.container_registry.location}" - sku = "${var.container_registry_sku}" - admin_enabled = "${var.container_registry_admin_enabled}" - tags = "${var.container_registry_tags}" + name = var.container_registry_name + resource_group_name = data.azurerm_resource_group.container_registry.name + location = data.azurerm_resource_group.container_registry.location + sku = var.container_registry_sku + admin_enabled = var.container_registry_admin_enabled + tags = var.container_registry_tags } + diff --git a/infra/modules/providers/azure/container-registry/output.tf b/infra/modules/providers/azure/container-registry/output.tf index 62a8b39..b7428c1 100644 --- a/infra/modules/providers/azure/container-registry/output.tf +++ b/infra/modules/providers/azure/container-registry/output.tf @@ -1,15 +1,16 @@ output "container_registry_id" { description = "The Container Registry ID." - value = "${azurerm_container_registry.container_registry.id}" + value = azurerm_container_registry.container_registry.id } output "container_registry_login_server" { description = "The URL that can be used to log into the container registry." - value = "${azurerm_container_registry.container_registry.login_server}" + value = azurerm_container_registry.container_registry.login_server } output "container_registry_admin_username" { description = "The Username associated with the Container Registry Admin account - if the admin account is enabled." - value = "${azurerm_container_registry.container_registry.admin_username}" + value = azurerm_container_registry.container_registry.admin_username sensitive = true } + diff --git a/infra/modules/providers/azure/container-registry/variables.tf b/infra/modules/providers/azure/container-registry/variables.tf index 42f1fc1..4c1f72e 100644 --- a/infra/modules/providers/azure/container-registry/variables.tf +++ b/infra/modules/providers/azure/container-registry/variables.tf @@ -1,11 +1,11 @@ variable "resource_group_name" { description = "(Required) The name of the resource group in which to create the Container Registry. Changing this forces a new resource to be created." - type = "string" + type = string } variable "container_registry_name" { description = "(Required) Specifies the name of the Container Registry. Changing this forces a new resource to be created." - type = "string" + type = string } variable "container_registry_admin_enabled" { @@ -15,12 +15,13 @@ variable "container_registry_admin_enabled" { variable "container_registry_sku" { description = "(Optional) The SKU name of the the container registry. Possible values are Basic, Standard and Premium." - type = "string" + type = string default = "Basic" } variable "container_registry_tags" { description = "(Optional) A mapping of tags to assign to the resource." - type = "map" + type = map(string) default = {} } + diff --git a/infra/modules/providers/azure/container-registry/versions.tf b/infra/modules/providers/azure/container-registry/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/infra/modules/providers/azure/container-registry/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/infra/modules/providers/azure/cosmosdb/main.tf b/infra/modules/providers/azure/cosmosdb/main.tf index cdc61d1..88a6e2b 100644 --- a/infra/modules/providers/azure/cosmosdb/main.tf +++ b/infra/modules/providers/azure/cosmosdb/main.tf @@ -1,22 +1,23 @@ data "azurerm_resource_group" "cosmosdb" { - name = "${var.service_plan_resource_group_name}" + name = var.service_plan_resource_group_name } resource "azurerm_cosmosdb_account" "cosmosdb" { - name = "${var.cosmosdb_name}" - location = "${data.azurerm_resource_group.cosmosdb.location}" - resource_group_name = "${data.azurerm_resource_group.cosmosdb.name}" + name = var.cosmosdb_name + location = data.azurerm_resource_group.cosmosdb.location + resource_group_name = data.azurerm_resource_group.cosmosdb.name offer_type = "Standard" - kind = "${var.cosmosdb_kind}" + kind = var.cosmosdb_kind - enable_automatic_failover = "${var.cosmosdb_automatic_failover}" + enable_automatic_failover = var.cosmosdb_automatic_failover consistency_policy { - consistency_level = "${var.consistency_level}" + consistency_level = var.consistency_level } geo_location { - location = "${var.primary_replica_location}" + location = var.primary_replica_location failover_priority = 0 } } + diff --git a/infra/modules/providers/azure/cosmosdb/output.tf b/infra/modules/providers/azure/cosmosdb/output.tf index aa1106a..f411d31 100644 --- a/infra/modules/providers/azure/cosmosdb/output.tf +++ b/infra/modules/providers/azure/cosmosdb/output.tf @@ -1,15 +1,16 @@ output "cosmosdb_endpoint" { description = "The endpoint used to connect to the CosmosDB account." - value = "${azurerm_cosmosdb_account.cosmosdb.endpoint}" + value = azurerm_cosmosdb_account.cosmosdb.endpoint } output "cosmosdb_primary_master_key" { description = "The Primary master key for the CosmosDB Account." - value = "${azurerm_cosmosdb_account.cosmosdb.primary_master_key}" + value = azurerm_cosmosdb_account.cosmosdb.primary_master_key sensitive = true } output "cosmosdb_connection_strings" { description = "A list of connection strings available for this CosmosDB account." - value = "${azurerm_cosmosdb_account.cosmosdb.connection_strings}" + value = azurerm_cosmosdb_account.cosmosdb.connection_strings } + diff --git a/infra/modules/providers/azure/cosmosdb/variables.tf b/infra/modules/providers/azure/cosmosdb/variables.tf index 13c7118..6db0030 100644 --- a/infra/modules/providers/azure/cosmosdb/variables.tf +++ b/infra/modules/providers/azure/cosmosdb/variables.tf @@ -1,16 +1,16 @@ variable "service_plan_resource_group_name" { description = "Resource group name that the CosmosDB will be created in." - type = "string" + type = string } variable "cosmosdb_name" { description = "The name that CosmosDB will be created with." - type = "string" + type = string } variable "cosmosdb_kind" { description = "Determines the kind of CosmosDB to create. Can either be 'GlobalDocumentDB' or 'MongoDB'." - type = "string" + type = string default = "GlobalDocumentDB" } @@ -21,11 +21,12 @@ variable "cosmosdb_automatic_failover" { variable "consistency_level" { description = "The Consistency Level to use for this CosmosDB Account. Can be either 'BoundedStaleness', 'Eventual', 'Session', 'Strong' or 'ConsistentPrefix'." - type = "string" + type = string default = "Session" } variable "primary_replica_location" { description = "The name of the Azure region to host replicated data." - type = "string" + type = string } + diff --git a/infra/modules/providers/azure/cosmosdb/versions.tf b/infra/modules/providers/azure/cosmosdb/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/infra/modules/providers/azure/cosmosdb/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/infra/modules/providers/azure/keyvault-cert/main.tf b/infra/modules/providers/azure/keyvault-cert/main.tf index 120e375..0de5747 100644 --- a/infra/modules/providers/azure/keyvault-cert/main.tf +++ b/infra/modules/providers/azure/keyvault-cert/main.tf @@ -1,17 +1,18 @@ data "azurerm_key_vault" "vault" { - name = "${var.keyvault_name}" - resource_group_name = "${var.resource_group_name}" + name = var.keyvault_name + resource_group_name = var.resource_group_name } -data "azurerm_client_config" "current" {} +data "azurerm_client_config" "current" { +} resource "azurerm_key_vault_certificate" "kv_cert_import" { - count = "${var.key_vault_cert_import_filepath == "" ? 0 : 1}" - name = "${var.key_vault_cert_name}" - key_vault_id = "${data.azurerm_key_vault.vault.id}" + count = var.key_vault_cert_import_filepath == "" ? 0 : 1 + name = var.key_vault_cert_name + key_vault_id = data.azurerm_key_vault.vault.id certificate { - contents = "${filebase64("${var.key_vault_cert_import_filepath}")}" + contents = filebase64(var.key_vault_cert_import_filepath) password = "" } @@ -28,15 +29,15 @@ resource "azurerm_key_vault_certificate" "kv_cert_import" { } secret_properties { - content_type = "${var.key_vault_content_type}" + content_type = var.key_vault_content_type } } } resource "azurerm_key_vault_certificate" "kv_cert_self_assign" { - count = "${var.key_vault_cert_import_filepath == "" ? 1 : 0}" - name = "${var.key_vault_cert_name}" - key_vault_id = "${data.azurerm_key_vault.vault.id}" + count = var.key_vault_cert_import_filepath == "" ? 1 : 0 + name = var.key_vault_cert_name + key_vault_id = data.azurerm_key_vault.vault.id certificate_policy { issuer_parameters { @@ -56,12 +57,12 @@ resource "azurerm_key_vault_certificate" "kv_cert_self_assign" { } trigger { - days_before_expiry = "${var.key_vault_cert_days_before_expiry}" + days_before_expiry = var.key_vault_cert_days_before_expiry } } secret_properties { - content_type = "${var.key_vault_content_type}" + content_type = var.key_vault_content_type } x509_certificate_properties { @@ -79,29 +80,30 @@ resource "azurerm_key_vault_certificate" "kv_cert_self_assign" { ] subject_alternative_names { - dns_names = ["${var.key_vault_cert_alt_names}"] + dns_names = var.key_vault_cert_alt_names } subject = "CN=${var.key_vault_cert_subject}" - validity_in_months = "${var.key_vault_cert_validity_months}" + validity_in_months = var.key_vault_cert_validity_months } } } data "external" "public_cert" { depends_on = [ - "azurerm_key_vault_certificate.kv_cert_self_assign", - "azurerm_key_vault_certificate.kv_cert_import", + azurerm_key_vault_certificate.kv_cert_self_assign, + azurerm_key_vault_certificate.kv_cert_import, ] - program = ["az", "keyvault", "certificate", "show", "--name", "${var.key_vault_cert_name}", "--vault-name", "${var.keyvault_name}", "-o", "json", "--query", "{cer:cer}"] + program = ["az", "keyvault", "certificate", "show", "--name", var.key_vault_cert_name, "--vault-name", var.keyvault_name, "-o", "json", "--query", "{cer:cer}"] } data "external" "private_pfx" { depends_on = [ - "azurerm_key_vault_certificate.kv_cert_self_assign", - "azurerm_key_vault_certificate.kv_cert_import", + azurerm_key_vault_certificate.kv_cert_self_assign, + azurerm_key_vault_certificate.kv_cert_import, ] - program = ["az", "keyvault", "secret", "show", "--name", "${var.key_vault_cert_name}", "--vault-name", "${var.keyvault_name}", "-o", "json", "--query", "{value:value}"] + program = ["az", "keyvault", "secret", "show", "--name", var.key_vault_cert_name, "--vault-name", var.keyvault_name, "-o", "json", "--query", "{value:value}"] } + diff --git a/infra/modules/providers/azure/keyvault-cert/output.tf b/infra/modules/providers/azure/keyvault-cert/output.tf index 0802739..1022fc8 100644 --- a/infra/modules/providers/azure/keyvault-cert/output.tf +++ b/infra/modules/providers/azure/keyvault-cert/output.tf @@ -1,17 +1,18 @@ output "cert_name" { - value = "${var.key_vault_cert_name}" + value = var.key_vault_cert_name } output "public_cert" { - value = "${lookup(data.external.public_cert.result, "cer")}" + value = data.external.public_cert.result["cer"] sensitive = true } output "private_pfx" { - value = "${lookup(data.external.private_pfx.result, "value")}" + value = data.external.private_pfx.result["value"] sensitive = true } output "vault_id" { - value = "${data.azurerm_key_vault.vault.id}" + value = data.azurerm_key_vault.vault.id } + diff --git a/infra/modules/providers/azure/keyvault-cert/variables.tf b/infra/modules/providers/azure/keyvault-cert/variables.tf index 2aaefb5..9832c02 100644 --- a/infra/modules/providers/azure/keyvault-cert/variables.tf +++ b/infra/modules/providers/azure/keyvault-cert/variables.tf @@ -1,51 +1,52 @@ variable "keyvault_name" { - type = "string" + type = string description = "The name of the Key Vault where the Certificate should be created." } variable "resource_group_name" { - type = "string" + type = string description = "Default resource group name that the network will be created in." } variable "key_vault_cert_name" { description = "Name of the certifacte to create" - type = "string" + type = string default = "pfx-certificate" } variable "key_vault_cert_alt_names" { - type = "list" + type = list(string) description = "A list of alternative DNS names (FQDNs) identified by the Certificate. Changing this forces a new resource to be created." default = [""] } variable "key_vault_content_type" { - type = "string" + type = string description = " The Content-Type of the Certificate, such as application/x-pkcs12 for a PFX or application/x-pem-file for a PEM. Changing this forces a new resource to be created." default = "application/x-pkcs12" } variable "key_vault_cert_import_filepath" { - type = "string" + type = string description = "The base64-encoded certificate file path. Changing this forces a new resource to be created." default = "" } variable "key_vault_cert_subject" { - type = "string" + type = string description = "The Certificate's Subject. Changing this forces a new resource to be created." default = "" } variable "key_vault_cert_validity_months" { - type = "string" + type = number description = "The Certificates Validity Period in Months." - default = "12" + default = 12 } variable "key_vault_cert_days_before_expiry" { - type = "string" + type = number description = "The number of days before the Certificate expires that the action associated with this Trigger should run." - default = "30" + default = 30 } + diff --git a/infra/modules/providers/azure/keyvault-cert/versions.tf b/infra/modules/providers/azure/keyvault-cert/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/infra/modules/providers/azure/keyvault-cert/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/infra/modules/providers/azure/keyvault-policy/main.tf b/infra/modules/providers/azure/keyvault-policy/main.tf index 5b20d2d..5fc5838 100644 --- a/infra/modules/providers/azure/keyvault-policy/main.tf +++ b/infra/modules/providers/azure/keyvault-policy/main.tf @@ -1,11 +1,12 @@ resource "azurerm_key_vault_access_policy" "keyvault" { - count = "${var.instance_count}" - key_vault_id = "${var.vault_id}" + count = var.instance_count + key_vault_id = var.vault_id - tenant_id = "${var.tenant_id}" - object_id = "${var.object_ids[count.index]}" + tenant_id = var.tenant_id + object_id = var.object_ids[count.index] - key_permissions = "${var.key_permissions}" - secret_permissions = "${var.secret_permissions}" - certificate_permissions = "${var.certificate_permissions}" + key_permissions = var.key_permissions + secret_permissions = var.secret_permissions + certificate_permissions = var.certificate_permissions } + diff --git a/infra/modules/providers/azure/keyvault-policy/variables.tf b/infra/modules/providers/azure/keyvault-policy/variables.tf index 0e5398e..c8c2235 100644 --- a/infra/modules/providers/azure/keyvault-policy/variables.tf +++ b/infra/modules/providers/azure/keyvault-policy/variables.tf @@ -1,37 +1,38 @@ variable "vault_id" { description = "Specifies the name of the Key Vault resource." - type = "string" + type = string } variable "tenant_id" { description = "The Azure Active Directory tenant ID that should be used for authenticating requests to the key vault. Changing this forces a new resource to be created." - type = "string" + type = string } variable "instance_count" { description = "the number of access policies that we need to create. Terraform requires the resource instance count to be known during the plan creation step. This will be removed once we upgrade to TF version 12" - type = "string" + type = string } variable "object_ids" { description = "The object IDs of a user, service principal or security group in the Azure Active Directory tenant for the vault. The object ID must be unique for the list of access policies. Changing this forces a new resource to be created." - type = "list" + type = list(string) } variable "key_permissions" { description = "List of key permissions, must be one or more from the following: backup, create, decrypt, delete, encrypt, get, import, list, purge, recover, restore, sign, unwrapKey, update, verify and wrapKey" - type = "list" + type = list(string) default = ["create", "delete", "get", "list"] } variable "secret_permissions" { - type = "list" + type = list(string) description = "List of secret permissions, must be one or more from the following: backup, delete, get, list, purge, recover, restore and set." default = ["delete", "get", "set", "list"] } variable "certificate_permissions" { - type = "list" + type = list(string) description = "List of storage permissions, must be one or more from the following: backup, delete, deletesas, get, getsas, list, listsas, purge, recover, regeneratekey, restore, set, setsas and update." default = ["create", "delete", "get", "list"] } + diff --git a/infra/modules/providers/azure/keyvault-policy/versions.tf b/infra/modules/providers/azure/keyvault-policy/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/infra/modules/providers/azure/keyvault-policy/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/infra/modules/providers/azure/keyvault/main.tf b/infra/modules/providers/azure/keyvault/main.tf index b0c2916..687eebb 100644 --- a/infra/modules/providers/azure/keyvault/main.tf +++ b/infra/modules/providers/azure/keyvault/main.tf @@ -3,28 +3,30 @@ module "azure-provider" { } data "azurerm_resource_group" "kv" { - name = "${var.resource_group_name}" + name = var.resource_group_name } -data "azurerm_client_config" "current" {} +data "azurerm_client_config" "current" { +} resource "azurerm_key_vault" "keyvault" { - name = "${var.keyvault_name}" - location = "${data.azurerm_resource_group.kv.location}" - resource_group_name = "${data.azurerm_resource_group.kv.name}" - tenant_id = "${data.azurerm_client_config.current.tenant_id}" + name = var.keyvault_name + location = data.azurerm_resource_group.kv.location + resource_group_name = data.azurerm_resource_group.kv.name + tenant_id = data.azurerm_client_config.current.tenant_id sku { - name = "${var.keyvault_sku}" + name = var.keyvault_sku } access_policy { - tenant_id = "${data.azurerm_client_config.current.tenant_id}" - object_id = "${data.azurerm_client_config.current.service_principal_object_id}" - key_permissions = "${var.keyvault_key_permissions}" - secret_permissions = "${var.keyvault_secret_permissions}" - certificate_permissions = "${var.keyvault_certificate_permissions}" + tenant_id = data.azurerm_client_config.current.tenant_id + object_id = data.azurerm_client_config.current.service_principal_object_id + key_permissions = var.keyvault_key_permissions + secret_permissions = var.keyvault_secret_permissions + certificate_permissions = var.keyvault_certificate_permissions } - tags = "${var.resource_tags}" + tags = var.resource_tags } + diff --git a/infra/modules/providers/azure/keyvault/output.tf b/infra/modules/providers/azure/keyvault/output.tf index f9dc84a..94c43e1 100644 --- a/infra/modules/providers/azure/keyvault/output.tf +++ b/infra/modules/providers/azure/keyvault/output.tf @@ -1,14 +1,15 @@ output "keyvault_id" { description = "The id of the Keyvault" - value = "${azurerm_key_vault.keyvault.id}" + value = azurerm_key_vault.keyvault.id } output "keyvault_uri" { description = "The uri of the keyvault" - value = "${azurerm_key_vault.keyvault.vault_uri}" + value = azurerm_key_vault.keyvault.vault_uri } output "keyvault_name" { description = "The name of the Keyvault" - value = "${azurerm_key_vault.keyvault.name}" + value = azurerm_key_vault.keyvault.name } + diff --git a/infra/modules/providers/azure/keyvault/variables.tf b/infra/modules/providers/azure/keyvault/variables.tf index b1ce5e1..d8e2e59 100644 --- a/infra/modules/providers/azure/keyvault/variables.tf +++ b/infra/modules/providers/azure/keyvault/variables.tf @@ -1,40 +1,41 @@ variable "keyvault_name" { description = "Name of the keyvault to create" - type = "string" + type = string default = "spkeyvault" } variable "keyvault_sku" { description = "SKU of the keyvault to create" - type = "string" + type = string default = "standard" } variable "resource_group_name" { - type = "string" + type = string description = "Default resource group name that the network will be created in." } variable "keyvault_key_permissions" { description = "Permissions that the service principal has for accessing keys from KeyVault" - type = "list" + type = list(string) default = ["create", "delete", "get"] } variable "keyvault_secret_permissions" { description = "Permissions that the service principal has for accessing secrets from KeyVault" - type = "list" + type = list(string) default = ["set", "delete", "get", "list"] } variable "keyvault_certificate_permissions" { description = "Permissions that the service principal has for accessing certificates from KeyVault" - type = "list" + type = list(string) default = ["create", "delete", "get", "list"] } variable "resource_tags" { description = "Map of tags to apply to taggable resources in this module. By default the taggable resources are tagged with the name defined above and this map is merged in" - type = "map" + type = map(string) default = {} } + diff --git a/infra/modules/providers/azure/keyvault/versions.tf b/infra/modules/providers/azure/keyvault/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/infra/modules/providers/azure/keyvault/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/infra/modules/providers/azure/provider/README.md b/infra/modules/providers/azure/provider/README.md index ee8bf9b..3d938df 100644 --- a/infra/modules/providers/azure/provider/README.md +++ b/infra/modules/providers/azure/provider/README.md @@ -21,7 +21,7 @@ resource "azurerm_resource_group" "example" { } ``` -### Terraform (Version 0.11.13 or higher) +### Terraform (Version 0.12.1 or higher) Terraform enables you to safely and predictably create, change, and improve infrastructure. It is an open source tool that codifies APIs into declarative configuration files that can be shared amongst team members, treated as code, edited, reviewed, and versioned. In Cobalt, we use Terraform for all our resource deployments on Azure. diff --git a/infra/modules/providers/azure/provider/main.tf b/infra/modules/providers/azure/provider/main.tf index 4b220bc..6b62a77 100644 --- a/infra/modules/providers/azure/provider/main.tf +++ b/infra/modules/providers/azure/provider/main.tf @@ -1,15 +1,12 @@ provider "azurerm" { - version = "~>1.27.0" -} - -terraform { - required_version = "~> 0.11.13" + version = "~>1.30.1" } provider "null" { - version = "~>2.0.0" + version = "~>2.1.0" } provider "azuread" { version = "~>0.4.0" } + diff --git a/infra/modules/providers/azure/provider/versions.tf b/infra/modules/providers/azure/provider/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/infra/modules/providers/azure/provider/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/infra/modules/providers/azure/service-plan/main.tf b/infra/modules/providers/azure/service-plan/main.tf index 57b6f90..9be347e 100644 --- a/infra/modules/providers/azure/service-plan/main.tf +++ b/infra/modules/providers/azure/service-plan/main.tf @@ -1,73 +1,73 @@ data "azurerm_resource_group" "svcplan" { - name = "${var.resource_group_name}" + name = var.resource_group_name } resource "azurerm_app_service_plan" "svcplan" { - name = "${var.service_plan_name}" - location = "${data.azurerm_resource_group.svcplan.location}" - resource_group_name = "${var.resource_group_name}" - kind = "${var.service_plan_kind}" - tags = "${var.resource_tags}" - reserved = "${var.service_plan_kind == "Linux" ? true : "${var.service_plan_reserved}"}" + name = var.service_plan_name + location = data.azurerm_resource_group.svcplan.location + resource_group_name = var.resource_group_name + kind = var.service_plan_kind + tags = var.resource_tags + reserved = var.service_plan_kind == "Linux" ? true : var.service_plan_reserved sku { - tier = "${var.service_plan_tier}" - size = "${var.service_plan_size}" - capacity = "${var.service_plan_capacity}" + tier = var.service_plan_tier + size = var.service_plan_size + capacity = var.service_plan_capacity } } resource "azurerm_monitor_autoscale_setting" "app_service_auto_scale" { name = "${var.service_plan_name}-autoscale" - resource_group_name = "${var.resource_group_name}" - location = "${data.azurerm_resource_group.svcplan.location}" - target_resource_id = "${azurerm_app_service_plan.svcplan.id}" + resource_group_name = var.resource_group_name + location = data.azurerm_resource_group.svcplan.location + target_resource_id = azurerm_app_service_plan.svcplan.id profile { name = "Scale on CPU usage" capacity { default = 1 - minimum = "${var.autoscale_capacity_minimum}" - maximum = "${azurerm_app_service_plan.svcplan.maximum_number_of_workers}" + minimum = var.autoscale_capacity_minimum + maximum = azurerm_app_service_plan.svcplan.maximum_number_of_workers } rule { metric_trigger { - metric_name = "${var.autoscale_rule_out_metric_name}" - metric_resource_id = "${azurerm_app_service_plan.svcplan.id}" + metric_name = var.autoscale_rule_out_metric_name + metric_resource_id = azurerm_app_service_plan.svcplan.id time_grain = "PT1M" - statistic = "${var.autoscale_rule_out_statistic}" + statistic = var.autoscale_rule_out_statistic time_window = "PT5M" - time_aggregation = "${var.autoscale_rule_out_statistic}" - operator = "${var.autoscale_rule_out_operator}" - threshold = "${var.autoscale_rule_out_threshold}" + time_aggregation = var.autoscale_rule_out_statistic + operator = var.autoscale_rule_out_operator + threshold = var.autoscale_rule_out_threshold } scale_action { direction = "Increase" type = "ChangeCount" - value = "${var.autoscale_rule_out_action_change_count}" + value = var.autoscale_rule_out_action_change_count cooldown = "PT10M" } } rule { metric_trigger { - metric_name = "${var.autoscale_rule_in_metric_name}" - metric_resource_id = "${azurerm_app_service_plan.svcplan.id}" + metric_name = var.autoscale_rule_in_metric_name + metric_resource_id = azurerm_app_service_plan.svcplan.id time_grain = "PT1M" - statistic = "${var.autoscale_rule_in_statistic}" + statistic = var.autoscale_rule_in_statistic time_window = "PT5M" - time_aggregation = "${var.autoscale_rule_in_statistic}" - operator = "${var.autoscale_rule_in_operator}" - threshold = "${var.autoscale_rule_in_threshold}" + time_aggregation = var.autoscale_rule_in_statistic + operator = var.autoscale_rule_in_operator + threshold = var.autoscale_rule_in_threshold } scale_action { direction = "Decrease" type = "ChangeCount" - value = "${var.autoscale_rule_in_action_change_count}" + value = var.autoscale_rule_in_action_change_count cooldown = "PT1M" } } @@ -80,3 +80,4 @@ resource "azurerm_monitor_autoscale_setting" "app_service_auto_scale" { } } } + diff --git a/infra/modules/providers/azure/service-plan/output.tf b/infra/modules/providers/azure/service-plan/output.tf index 65e9cdf..c6cd6fd 100644 --- a/infra/modules/providers/azure/service-plan/output.tf +++ b/infra/modules/providers/azure/service-plan/output.tf @@ -1,13 +1,14 @@ output "service_plan_name" { description = "The name of the service plan created" - value = "${azurerm_app_service_plan.svcplan.name}" + value = azurerm_app_service_plan.svcplan.name } output "service_plan_kind" { description = "The kind of service plan created" - value = "${azurerm_app_service_plan.svcplan.kind}" + value = azurerm_app_service_plan.svcplan.kind } output "app_service_plan_id" { - value = "${azurerm_app_service_plan.svcplan.id}" + value = azurerm_app_service_plan.svcplan.id } + diff --git a/infra/modules/providers/azure/service-plan/variables.tf b/infra/modules/providers/azure/service-plan/variables.tf index f66f394..59bd858 100644 --- a/infra/modules/providers/azure/service-plan/variables.tf +++ b/infra/modules/providers/azure/service-plan/variables.tf @@ -1,111 +1,112 @@ variable "resource_group_name" { description = "The name of the resource group in which to create the storage account. Changing this forces a new resource to be created. If omitted, will create a new RG based on the `name` above" - type = "string" + type = string } variable "resource_tags" { description = "Map of tags to apply to taggable resources in this module. By default the taggable resources are tagged with the name defined above and this map is merged in" - type = "map" + type = map(string) default = {} } variable "service_plan_name" { description = "The name of the service plan to be created" - type = "string" + type = string } variable "service_plan_tier" { description = "The tier under which the service plan is created. Details can be found at https://docs.microsoft.com/en-us/azure/app-service/overview-hosting-plans" - type = "string" + type = string default = "Standard" } variable "service_plan_size" { description = "The compute and storage needed for the service plan to be deployed. Details can be found at https://azure.microsoft.com/en-us/pricing/details/app-service/windows/" - type = "string" + type = string default = "S1" } variable "service_plan_kind" { description = "The kind of Service Plan to be created. Possible values are Windows/Linux/FunctionApp/App" - type = "string" + type = string default = "Linux" } variable "service_plan_capacity" { description = "The capacity of Service Plan to be created." - type = "string" - default = "1" + type = number + default = 1 } variable "service_plan_reserved" { description = "Is the Service Plan to be created reserved. Possible values are true/false" - type = "string" - default = "true" + type = bool + default = true } variable "autoscale_capacity_minimum" { description = "The minimum number of instances for this resource. Valid values are between 0 and 1000" - type = "string" - default = "1" + type = number + default = 1 } variable "autoscale_rule_out_metric_name" { description = "The name of the scale out rule metric that defines what the rule monitors, such as Percentage CPU for Virtual Machine Scale Sets and CpuPercentage for App Service Plan." - type = "string" + type = string default = "CpuPercentage" } variable "autoscale_rule_out_statistic" { description = "Specifies how the scale out rule metrics from multiple instances are combined. Possible values are Average, Min and Max." - type = "string" + type = string default = "Average" } variable "autoscale_rule_out_operator" { description = "Specifies how the scale out rule metrics from multiple instances are combined. Possible values are Average, Min and Max." - type = "string" + type = string default = "GreaterThan" } variable "autoscale_rule_out_threshold" { description = "Specifies the threshold of the scale out rule metric that triggers the scale action." - type = "string" - default = "70" + type = number + default = 70 } variable "autoscale_rule_out_action_change_count" { description = "Specifies the number of instances involved in the scaling action." - type = "string" - default = "1" + type = number + default = 1 } variable "autoscale_rule_in_metric_name" { description = "The name of the scale in rule metric that defines what the rule monitors, such as Percentage CPU for Virtual Machine Scale Sets and CpuPercentage for App Service Plan." - type = "string" + type = string default = "CpuPercentage" } variable "autoscale_rule_in_statistic" { description = "Specifies how the scale in rule metrics from multiple instances are combined. Possible values are Average, Min and Max." - type = "string" + type = string default = "Average" } variable "autoscale_rule_in_operator" { description = "Specifies how the scale in rule metrics from multiple instances are combined. Possible values are Average, Min and Max." - type = "string" + type = string default = "GreaterThan" } variable "autoscale_rule_in_threshold" { description = "Specifies the threshold of the scale in rule metric that triggers the scale action." - type = "string" - default = "25" + type = number + default = 25 } variable "autoscale_rule_in_action_change_count" { description = "Specifies the number of instances involved in the scaling action." - type = "string" - default = "1" + type = number + default = 1 } + diff --git a/infra/modules/providers/azure/service-plan/versions.tf b/infra/modules/providers/azure/service-plan/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/infra/modules/providers/azure/service-plan/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/infra/modules/providers/azure/service-principal/main.tf b/infra/modules/providers/azure/service-principal/main.tf index b06d05a..e8159c1 100644 --- a/infra/modules/providers/azure/service-principal/main.tf +++ b/infra/modules/providers/azure/service-principal/main.tf @@ -3,23 +3,25 @@ module "azure-provider" { } locals { - sps_to_create = "${var.create_for_rbac == "true" ? 1 : 0}" + sps_to_create = var.create_for_rbac == true ? 1 : 0 } -data "azurerm_subscription" "sp" {} +data "azurerm_subscription" "sp" { +} resource "azuread_application" "sp" { - count = "${local.sps_to_create}" - name = "${var.service_principal_display_name}" + count = local.sps_to_create + name = var.service_principal_display_name } resource "azuread_service_principal" "sp" { - count = "${local.sps_to_create}" - application_id = "${azuread_application.sp.application_id}" + count = local.sps_to_create + application_id = azuread_application.sp[0].application_id } resource "azurerm_role_assignment" "sp" { - role_definition_name = "${var.role_name}" - principal_id = "${var.create_for_rbac == "true" ? azuread_service_principal.sp.object_id : var.service_principle_object_id}" - scope = "${var.role_scope}" + role_definition_name = var.role_name + principal_id = var.create_for_rbac == true ? azuread_service_principal.sp[0].object_id : var.service_principle_object_id + scope = var.role_scope } + diff --git a/infra/modules/providers/azure/service-principal/output.tf b/infra/modules/providers/azure/service-principal/output.tf index 7ccbffd..4306b2a 100644 --- a/infra/modules/providers/azure/service-principal/output.tf +++ b/infra/modules/providers/azure/service-principal/output.tf @@ -1,14 +1,15 @@ output "service_principal_object_id" { description = "The ID of the Azure AD Service Principal" - value = "${azuread_service_principal.sp.*.object_id}" + value = azuread_service_principal.sp.*.object_id } output "service_principal_application_id" { description = "The ID of the Azure AD Application" - value = "${azuread_service_principal.sp.*.application_id}" + value = azuread_service_principal.sp.*.application_id } output "service_principal_display_name" { description = "The Display Name of the Azure AD Application associated with this Service Principal" - value = "${azuread_service_principal.sp.*.display_name}" + value = azuread_service_principal.sp.*.display_name } + diff --git a/infra/modules/providers/azure/service-principal/variables.tf b/infra/modules/providers/azure/service-principal/variables.tf index 5f270a3..d6cdfd9 100644 --- a/infra/modules/providers/azure/service-principal/variables.tf +++ b/infra/modules/providers/azure/service-principal/variables.tf @@ -1,26 +1,27 @@ variable "create_for_rbac" { description = "Create a new Service Principle" - type = "string" - default = "true" + type = bool + default = true } variable "display_name" { description = "Display name of the AD application" - type = "string" + type = string } variable "object_id" { description = "Object Id of the service principle to assign a role" - type = "string" + type = string default = "" } variable "role_name" { description = "The name of the role definition to assign a service principle too." - type = "string" + type = string } variable "role_scope" { description = "The scope at which the Role Assignment applies too, such as /subscriptions/0b1f6471-1bf0-4dda-aec3-111122223333" - type = "string" + type = string } + diff --git a/infra/modules/providers/azure/service-principal/versions.tf b/infra/modules/providers/azure/service-principal/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/infra/modules/providers/azure/service-principal/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/infra/modules/providers/azure/traffic-manager/main.tf b/infra/modules/providers/azure/traffic-manager/main.tf index 6db213c..50cc817 100644 --- a/infra/modules/providers/azure/traffic-manager/main.tf +++ b/infra/modules/providers/azure/traffic-manager/main.tf @@ -1,43 +1,44 @@ data "azurerm_resource_group" "tmrg" { - name = "${var.resource_group_name}" + name = var.resource_group_name } resource "azurerm_traffic_manager_profile" "profile" { - name = "${var.traffic_manager_profile_name}" - resource_group_name = "${data.azurerm_resource_group.tmrg.name}" + name = var.traffic_manager_profile_name + resource_group_name = data.azurerm_resource_group.tmrg.name traffic_routing_method = "Weighted" dns_config { - relative_name = "${var.traffic_manager_dns_name}" + relative_name = var.traffic_manager_dns_name ttl = 30 } monitor_config { - protocol = "${var.traffic_manager_monitor_protocol}" - port = "${var.traffic_manager_monitor_port}" + protocol = var.traffic_manager_monitor_protocol + port = var.traffic_manager_monitor_port path = "/" } - tags = "${var.tags}" + tags = var.tags } resource "azurerm_public_ip" "pip" { - name = "${var.public_ip_name}" - location = "${data.azurerm_resource_group.tmrg.location}" - resource_group_name = "${data.azurerm_resource_group.tmrg.name}" + name = var.public_ip_name + location = data.azurerm_resource_group.tmrg.location + resource_group_name = data.azurerm_resource_group.tmrg.name allocation_method = "Dynamic" domain_name_label = "${var.public_ip_name}-dns" - tags = "${var.tags}" + tags = var.tags } resource "azurerm_traffic_manager_endpoint" "endpoint" { name = "${var.endpoint_name}-ep" - resource_group_name = "${data.azurerm_resource_group.tmrg.name}" - profile_name = "${var.traffic_manager_profile_name}" + resource_group_name = data.azurerm_resource_group.tmrg.name + profile_name = var.traffic_manager_profile_name target = "${var.endpoint_name}-dns" - target_resource_id = "${azurerm_public_ip.pip.id}" + target_resource_id = azurerm_public_ip.pip.id type = "azureEndpoints" weight = 1 - depends_on = ["azurerm_traffic_manager_profile.profile"] + depends_on = [azurerm_traffic_manager_profile.profile] } + diff --git a/infra/modules/providers/azure/traffic-manager/output.tf b/infra/modules/providers/azure/traffic-manager/output.tf index 0f597dc..2cb499d 100644 --- a/infra/modules/providers/azure/traffic-manager/output.tf +++ b/infra/modules/providers/azure/traffic-manager/output.tf @@ -1,11 +1,12 @@ output "public_pip_id" { - value = "${azurerm_public_ip.pip.id}" + value = azurerm_public_ip.pip.id } output "tm_fqdn" { - value = "${azurerm_traffic_manager_profile.profile.fqdn}" + value = azurerm_traffic_manager_profile.profile.fqdn } output "public_pip_fqdn" { - value = "${azurerm_public_ip.pip.fqdn}" + value = azurerm_public_ip.pip.fqdn } + diff --git a/infra/modules/providers/azure/traffic-manager/variables.tf b/infra/modules/providers/azure/traffic-manager/variables.tf index 3e2dde5..07c03bc 100644 --- a/infra/modules/providers/azure/traffic-manager/variables.tf +++ b/infra/modules/providers/azure/traffic-manager/variables.tf @@ -1,39 +1,40 @@ variable "traffic_manager_profile_name" { - type = "string" + type = string } variable "public_ip_name" { - type = "string" + type = string } variable "endpoint_name" { - type = "string" + type = string } variable "resource_group_name" { - type = "string" + type = string } variable "traffic_manager_dns_name" { - type = "string" + type = string } variable "traffic_manager_monitor_protocol" { - type = "string" + type = string default = "https" } variable "traffic_manager_monitor_port" { - type = "string" - default = "443" + type = number + default = 443 } variable "tags" { description = "The tags to associate with the public ip address." - type = "map" + type = map(string) default = { tag1 = "" tag2 = "" } } + diff --git a/infra/modules/providers/azure/traffic-manager/versions.tf b/infra/modules/providers/azure/traffic-manager/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/infra/modules/providers/azure/traffic-manager/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/infra/templates/azure-simple-hw/backend.tf b/infra/templates/azure-simple-hw/backend.tf index 3384210..db7d6f9 100644 --- a/infra/templates/azure-simple-hw/backend.tf +++ b/infra/templates/azure-simple-hw/backend.tf @@ -3,3 +3,4 @@ terraform { key = "terraform.tfstate" } } + diff --git a/infra/templates/azure-simple-hw/main.tf b/infra/templates/azure-simple-hw/main.tf index c1781ad..e494131 100644 --- a/infra/templates/azure-simple-hw/main.tf +++ b/infra/templates/azure-simple-hw/main.tf @@ -3,20 +3,21 @@ module "provider" { } resource "azurerm_resource_group" "main" { - name = "${var.prefix}" - location = "${var.resource_group_location}" + name = var.prefix + location = var.resource_group_location } module "service_plan" { source = "../../modules/providers/azure/service-plan" - resource_group_name = "${azurerm_resource_group.main.name}" + resource_group_name = azurerm_resource_group.main.name service_plan_name = "${azurerm_resource_group.main.name}-sp" } module "app_service" { source = "../../modules/providers/azure/app-service" - app_service_name = "${var.app_service_name}" - service_plan_name = "${module.service_plan.service_plan_name}" - service_plan_resource_group_name = "${azurerm_resource_group.main.name}" - docker_registry_server_url = "${var.docker_registry_server_url}" + app_service_name = var.app_service_name + service_plan_name = module.service_plan.service_plan_name + service_plan_resource_group_name = azurerm_resource_group.main.name + docker_registry_server_url = var.docker_registry_server_url } + diff --git a/infra/templates/azure-simple-hw/outputs.tf b/infra/templates/azure-simple-hw/outputs.tf index 80164e7..03bd975 100644 --- a/infra/templates/azure-simple-hw/outputs.tf +++ b/infra/templates/azure-simple-hw/outputs.tf @@ -1,3 +1,4 @@ output "app_service_default_hostname" { value = "http://${element(module.app_service.app_service_uri, 0)}" } + diff --git a/infra/templates/azure-simple-hw/tests/integration/azure_simple_test.go b/infra/templates/azure-simple-hw/tests/integration/azure_simple_test.go index 5e9b11d..62c9514 100644 --- a/infra/templates/azure-simple-hw/tests/integration/azure_simple_test.go +++ b/infra/templates/azure-simple-hw/tests/integration/azure_simple_test.go @@ -21,8 +21,8 @@ var tfOptions = &terraform.Options{ TerraformDir: "../../", Upgrade: true, Vars: map[string]interface{}{ - "prefix": prefix, - "location": datacenter, + "prefix": prefix, + "resource_group_location": datacenter, }, BackendConfig: map[string]interface{}{ "storage_account_name": os.Getenv("TF_VAR_remote_state_account"), diff --git a/infra/templates/azure-simple-hw/tests/unit/azure_simple_test.go b/infra/templates/azure-simple-hw/tests/unit/azure_simple_test.go index 23a7787..03ccf3e 100644 --- a/infra/templates/azure-simple-hw/tests/unit/azure_simple_test.go +++ b/infra/templates/azure-simple-hw/tests/unit/azure_simple_test.go @@ -10,15 +10,16 @@ import ( "github.com/microsoft/cobalt/test-harness/infratests" ) +var workspace = fmt.Sprintf("azure-simple-hw-%s", random.UniqueId()) var prefix = fmt.Sprintf("helloworld-unit-tst-%s", random.UniqueId()) var datacenter = "eastus" -var tf_options = &terraform.Options{ +var tfOptions = &terraform.Options{ TerraformDir: "../../", Upgrade: true, Vars: map[string]interface{}{ - "prefix": prefix, - "location": datacenter, + "prefix": prefix, + "resource_group_location": datacenter, }, BackendConfig: map[string]interface{}{ "storage_account_name": os.Getenv("TF_VAR_remote_state_account"), @@ -29,22 +30,28 @@ var tf_options = &terraform.Options{ func TestAzureSimple(t *testing.T) { testFixture := infratests.UnitTestFixture{ GoTest: t, - TfOptions: tf_options, + TfOptions: tfOptions, ExpectedResourceCount: 8, PlanAssertions: nil, + Workspace: workspace, ExpectedResourceAttributeValues: infratests.ResourceDescription{ - "azurerm_app_service.appsvc": infratests.AttributeValueMapping{ - "resource_group_name": prefix, - "site_config.0.linux_fx_version": "DOCKER|appsvcsample/static-site:latest", - "app_settings.WEBSITES_ENABLE_APP_SERVICE_STORAGE": "false", + "module.app_service.azurerm_app_service.appsvc[0]": map[string]interface{}{ + "resource_group_name": prefix, + "app_settings": map[string]interface{}{ + "WEBSITES_ENABLE_APP_SERVICE_STORAGE": "false", + }, + "site_config": []interface{}{ + map[string]interface{}{"linux_fx_version": "DOCKER|appsvcsample/static-site:latest"}, + }, }, - "azurerm_app_service_plan.svcplan": infratests.AttributeValueMapping{ - "kind": "Linux", - "reserved": "true", - "sku.0.size": "S1", - "sku.0.tier": "Standard", + "module.service_plan.azurerm_app_service_plan.svcplan": map[string]interface{}{ + "kind": "Linux", + "reserved": true, + "sku": []interface{}{ + map[string]interface{}{"size": "S1", "tier": "Standard"}, + }, }, - "azurerm_resource_group.main": infratests.AttributeValueMapping{ + "azurerm_resource_group.main": map[string]interface{}{ "location": datacenter, "name": prefix, }, diff --git a/infra/templates/azure-simple-hw/variables.tf b/infra/templates/azure-simple-hw/variables.tf index 40cfdfa..c2cb9cd 100644 --- a/infra/templates/azure-simple-hw/variables.tf +++ b/infra/templates/azure-simple-hw/variables.tf @@ -4,16 +4,17 @@ variable "prefix" { variable "resource_group_location" { description = "The Azure location where all resources in this example should be created." - type = "string" + type = string } variable "app_service_name" { description = "The name key value pair where the key is the name assigned to the app service and value is the source container." - type = "map" + type = map(string) } variable "docker_registry_server_url" { description = "The url of the container registry that will be utilized to pull container into the Web Apps for containers" - type = "string" + type = string default = "https://index.docker.io" } + diff --git a/infra/templates/azure-simple-hw/versions.tf b/infra/templates/azure-simple-hw/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/infra/templates/azure-simple-hw/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/infra/templates/azure-simple/admin.tf b/infra/templates/azure-simple/admin.tf index 582b8ac..9eb2170 100644 --- a/infra/templates/azure-simple/admin.tf +++ b/infra/templates/azure-simple/admin.tf @@ -1,6 +1,6 @@ locals { prefix = "${lower(var.name)}-${lower(terraform.workspace)}" - prefix_short = "${format("%.20s", local.prefix)}" + prefix_short = format("%.20s", local.prefix) tm_profile_name = "${local.prefix}-tf" vnet_name = "${local.prefix}-vnet" tm_endpoint_name = "${var.resource_group_location}_${var.name}" @@ -8,57 +8,57 @@ locals { appgateway_name = "${local.prefix}-gateway" public_pip_name = "${local.prefix}-ip" kv_name = "${local.prefix_short}-kv" - resource_group_name = "${local.prefix}" + resource_group_name = local.prefix } resource "azurerm_resource_group" "svcplan" { - name = "${local.resource_group_name}" - location = "${var.resource_group_location}" + name = local.resource_group_name + location = var.resource_group_location } module "vnet" { source = "github.com/Microsoft/bedrock/cluster/azure/vnet" - vnet_name = "${local.vnet_name}" - address_space = "${var.address_space}" - resource_group_name = "${azurerm_resource_group.svcplan.name}" - resource_group_location = "${azurerm_resource_group.svcplan.location}" - subnet_names = ["${var.subnet_names}"] - subnet_prefixes = ["${var.subnet_prefixes}"] - subnet_service_endpoints = "${var.subnet_service_endpoints}" + vnet_name = local.vnet_name + address_space = var.address_space + resource_group_name = azurerm_resource_group.svcplan.name + resource_group_location = azurerm_resource_group.svcplan.location + subnet_names = var.subnet_names + subnet_prefixes = var.subnet_prefixes + subnet_service_endpoints = var.subnet_service_endpoints } module "keyvault" { source = "../../modules/providers/azure/keyvault" - keyvault_name = "${local.kv_name}" - resource_group_name = "${azurerm_resource_group.svcplan.name}" + keyvault_name = local.kv_name + resource_group_name = azurerm_resource_group.svcplan.name } module "traffic_manager" { source = "../../modules/providers/azure/traffic-manager" - resource_group_name = "${azurerm_resource_group.svcplan.name}" - traffic_manager_profile_name = "${local.tm_profile_name}" - public_ip_name = "${local.public_pip_name}" - endpoint_name = "${local.tm_endpoint_name}" - traffic_manager_profile_name = "${local.tm_profile_name}" - traffic_manager_dns_name = "${local.tm_dns_name}" + resource_group_name = azurerm_resource_group.svcplan.name + traffic_manager_profile_name = local.tm_profile_name + public_ip_name = local.public_pip_name + endpoint_name = local.tm_endpoint_name + traffic_manager_dns_name = local.tm_dns_name } module "keyvault_certificate" { source = "../../modules/providers/azure/keyvault-cert" - keyvault_name = "${module.keyvault.keyvault_name}" - resource_group_name = "${azurerm_resource_group.svcplan.name}" - key_vault_cert_subject = "${module.traffic_manager.public_pip_fqdn}" - key_vault_cert_alt_names = ["${module.app_service.app_service_uri}"] + keyvault_name = module.keyvault.keyvault_name + resource_group_name = azurerm_resource_group.svcplan.name + key_vault_cert_subject = module.traffic_manager.public_pip_fqdn + key_vault_cert_alt_names = module.app_service.app_service_uri } module "app_gateway" { source = "../../modules/providers/azure/app-gateway" - appgateway_name = "${local.appgateway_name}" - resource_group_name = "${azurerm_resource_group.svcplan.name}" - virtual_network_name = "${module.vnet.vnet_name}" - appgateway_ssl_private_pfx = "${module.keyvault_certificate.private_pfx}" - appgateway_ssl_public_cert = "${module.keyvault_certificate.public_cert}" - public_pip_id = "${module.traffic_manager.public_pip_id}" - virtual_network_subnet_id = "${module.vnet.vnet_subnet_ids[0]}" - backendpool_fqdns = "${module.app_service.app_service_uri}" + appgateway_name = local.appgateway_name + resource_group_name = azurerm_resource_group.svcplan.name + virtual_network_name = module.vnet.vnet_name + appgateway_ssl_private_pfx = module.keyvault_certificate.private_pfx + appgateway_ssl_public_cert = module.keyvault_certificate.public_cert + public_pip_id = module.traffic_manager.public_pip_id + virtual_network_subnet_id = module.vnet.vnet_subnet_ids[0] + backendpool_fqdns = module.app_service.app_service_uri } + diff --git a/infra/templates/azure-simple/appdev.tf b/infra/templates/azure-simple/appdev.tf index 35d3adf..7dfde42 100644 --- a/infra/templates/azure-simple/appdev.tf +++ b/infra/templates/azure-simple/appdev.tf @@ -9,52 +9,53 @@ module "provider" { module "service_plan" { source = "../../modules/providers/azure/service-plan" - resource_group_name = "${azurerm_resource_group.svcplan.name}" - service_plan_name = "${local.service_plan_name}" + resource_group_name = azurerm_resource_group.svcplan.name + service_plan_name = local.service_plan_name } module "app_service" { source = "../../modules/providers/azure/app-service" - app_service_name = "${var.app_service_name}" - service_plan_name = "${module.service_plan.service_plan_name}" - service_plan_resource_group_name = "${azurerm_resource_group.svcplan.name}" - app_insights_instrumentation_key = "${module.app_insight.app_insights_instrumentation_key}" - docker_registry_server_url = "${var.docker_registry_server_url}" - docker_registry_server_username = "${var.docker_registry_server_username}" - docker_registry_server_password = "${var.docker_registry_server_password}" - vnet_name = "${local.vnet_name}" - vnet_subnet_id = "${module.vnet.vnet_subnet_ids[0]}" - vault_uri = "${module.keyvault.keyvault_uri}" + app_service_name = var.app_service_name + service_plan_name = module.service_plan.service_plan_name + service_plan_resource_group_name = azurerm_resource_group.svcplan.name + app_insights_instrumentation_key = module.app_insight.app_insights_instrumentation_key + docker_registry_server_url = var.docker_registry_server_url + docker_registry_server_username = var.docker_registry_server_username + docker_registry_server_password = var.docker_registry_server_password + vnet_name = local.vnet_name + vnet_subnet_id = module.vnet.vnet_subnet_ids[0] + vault_uri = module.keyvault.keyvault_uri } module "app_insight" { source = "../../modules/providers/azure/app-insights" - service_plan_resource_group_name = "${azurerm_resource_group.svcplan.name}" - appinsights_name = "${local.app_insights_name}" - appinsights_application_type = "${var.application_type}" + service_plan_resource_group_name = azurerm_resource_group.svcplan.name + appinsights_name = local.app_insights_name + appinsights_application_type = var.application_type } module "keyvault_appsvc_policy" { source = "../../modules/providers/azure/keyvault-policy" - instance_count = "${length(keys(var.app_service_name))}" - vault_id = "${module.keyvault_certificate.vault_id}" - tenant_id = "${module.app_service.app_service_identity_tenant_id}" - object_ids = "${module.app_service.app_service_identity_object_ids}" + instance_count = length(keys(var.app_service_name)) + vault_id = module.keyvault_certificate.vault_id + tenant_id = module.app_service.app_service_identity_tenant_id + object_ids = module.app_service.app_service_identity_object_ids } module "app_monitoring" { source = "../../modules/providers/azure/app-monitoring" - resource_group_name = "${azurerm_resource_group.svcplan.name}" - resource_ids = ["${module.service_plan.app_service_plan_id}"] - action_group_name = "${var.action_group_name}" - action_group_email_receiver = "${var.action_group_email_receiver}" - metric_alert_name = "${var.metric_alert_name}" - metric_alert_frequency = "${var.metric_alert_frequency}" - metric_alert_period = "${var.metric_alert_period}" - metric_alert_criteria_namespace = "${var.metric_alert_criteria_namespace}" - metric_alert_criteria_name = "${var.metric_alert_criteria_name}" - metric_alert_criteria_aggregation = "${var.metric_alert_criteria_aggregation}" - metric_alert_criteria_operator = "${var.metric_alert_criteria_operator}" - metric_alert_criteria_threshold = "${var.metric_alert_criteria_threshold}" - scaling_values = "${var.scaling_values}" + resource_group_name = azurerm_resource_group.svcplan.name + resource_ids = [module.service_plan.app_service_plan_id] + action_group_name = var.action_group_name + action_group_email_receiver = var.action_group_email_receiver + metric_alert_name = var.metric_alert_name + metric_alert_frequency = var.metric_alert_frequency + metric_alert_period = var.metric_alert_period + metric_alert_criteria_namespace = var.metric_alert_criteria_namespace + metric_alert_criteria_name = var.metric_alert_criteria_name + metric_alert_criteria_aggregation = var.metric_alert_criteria_aggregation + metric_alert_criteria_operator = var.metric_alert_criteria_operator + metric_alert_criteria_threshold = var.metric_alert_criteria_threshold + scaling_values = var.scaling_values } + diff --git a/infra/templates/azure-simple/backend.tf b/infra/templates/azure-simple/backend.tf index 3384210..db7d6f9 100644 --- a/infra/templates/azure-simple/backend.tf +++ b/infra/templates/azure-simple/backend.tf @@ -3,3 +3,4 @@ terraform { key = "terraform.tfstate" } } + diff --git a/infra/templates/azure-simple/outputs.tf b/infra/templates/azure-simple/outputs.tf index 093babe..82141bb 100644 --- a/infra/templates/azure-simple/outputs.tf +++ b/infra/templates/azure-simple/outputs.tf @@ -1,15 +1,16 @@ output "app_gateway_health_probe_backend_status" { - value = "${module.app_gateway.appgateway_health_probe_backend_status}" + value = module.app_gateway.appgateway_health_probe_backend_status } output "app_gateway_health_probe_backend_address" { - value = "${module.app_gateway.app_gateway_health_probe_backend_address}" + value = module.app_gateway.app_gateway_health_probe_backend_address } output "tm_fqdn" { - value = "${module.traffic_manager.public_pip_fqdn}" + value = module.traffic_manager.public_pip_fqdn } output "public_cert" { - value = "${module.keyvault_certificate.public_cert}" + value = module.keyvault_certificate.public_cert } + diff --git a/infra/templates/azure-simple/tests/unit/template_unit_test.go b/infra/templates/azure-simple/tests/unit/template_unit_test.go index 4ae3808..7aad868 100644 --- a/infra/templates/azure-simple/tests/unit/template_unit_test.go +++ b/infra/templates/azure-simple/tests/unit/template_unit_test.go @@ -1,6 +1,7 @@ package test import ( + "encoding/json" "os" "testing" @@ -11,7 +12,7 @@ import ( var region = "eastus" var workspace = "azsimple" -var tf_options = &terraform.Options{ +var tfOptions = &terraform.Options{ TerraformDir: "../../", Upgrade: true, Vars: map[string]interface{}{ @@ -23,72 +24,98 @@ var tf_options = &terraform.Options{ }, } +// helper function to parse blocks of JSON into a generic Go map +func asMap(t *testing.T, jsonString string) map[string]interface{} { + var theMap map[string]interface{} + if err := json.Unmarshal([]byte(jsonString), &theMap); err != nil { + t.Fatal(err) + } + return theMap +} + func TestTemplate(t *testing.T) { + expectedAppServicePlan := asMap(t, `{ + "name": "cobalt-backend-api-`+workspace+`", + "site_config": [{"linux_fx_version": "DOCKER|msftcse/cobalt-azure-simple:0.1"}] + }`) + + expectedAppGatewayPlan := asMap(t, `{ + "authentication_certificate": [{"name": "gateway-public-key"}], + "frontend_port": [{"port": 443}], + "http_listener": [{"protocol": "Https"}], + "backend_http_settings": [{"port": 443, "protocol": "Https"}], + "probe": [{"protocol": "Https", "timeout": 30, "unhealthy_threshold": 3}], + "sku": [{"capacity": 2, "name": "WAF_Medium", "tier": "WAF"}] + }`) + + expectedAutoScalePlan := asMap(t, `{ + "enabled": true, + "notification": [{ + "email": [{ + "send_to_subscription_administrator": true, + "send_to_subscription_co_administrator": true + }] + }], + "profile": [{ + "rule": [{ + "metric_trigger": [{ + "metric_name": "CpuPercentage", + "operator": "GreaterThan", + "statistic": "Average", + "threshold": 70, + "time_aggregation": "Average", + "time_grain": "PT1M", + "time_window": "PT5M" + }], + "scale_action": [{ + "cooldown": "PT10M", + "direction": "Increase", + "type": "ChangeCount", + "value": 1 + }] + },{ + "metric_trigger": [{ + "metric_name": "CpuPercentage", + "operator": "GreaterThan", + "statistic": "Average", + "threshold": 25, + "time_aggregation": "Average", + "time_grain": "PT1M", + "time_window": "PT5M" + }], + "scale_action": [{ + "cooldown": "PT1M", + "direction": "Decrease", + "type": "ChangeCount", + "value": 1 + }] + }] + }] + }`) + testFixture := infratests.UnitTestFixture{ GoTest: t, - TfOptions: tf_options, + TfOptions: tfOptions, Workspace: workspace, PlanAssertions: nil, ExpectedResourceCount: 28, ExpectedResourceAttributeValues: infratests.ResourceDescription{ - "azurerm_resource_group.svcplan": infratests.AttributeValueMapping{ + "azurerm_resource_group.svcplan": map[string]interface{}{ "location": region, "name": "cobalt-az-simple-" + workspace, }, - "azurerm_app_service_slot.appsvc_staging_slot": infratests.AttributeValueMapping{ + "module.app_gateway.data.azurerm_resource_group.appgateway": map[string]interface{}{ + "name": "cobalt-az-simple-" + workspace, + }, + "module.app_insight.data.azurerm_resource_group.appinsights": map[string]interface{}{ + "name": "cobalt-az-simple-" + workspace, + }, + "module.app_service.azurerm_app_service_slot.appsvc_staging_slot[0]": map[string]interface{}{ "name": "staging", }, - "azurerm_app_service.appsvc": infratests.AttributeValueMapping{ - "name": "cobalt-backend-api-" + workspace, - "site_config.0.linux_fx_version": "DOCKER|msftcse/cobalt-azure-simple:0.1", - }, - "data.azurerm_resource_group.appgateway": infratests.AttributeValueMapping{ - "name": "cobalt-az-simple-" + workspace, - }, - "azurerm_application_gateway.appgateway": infratests.AttributeValueMapping{ - "authentication_certificate.0.name": "gateway-public-key", - "frontend_port.0.port": "443", - "http_listener.0.protocol": "Https", - "backend_http_settings.0.port": "443", - "backend_http_settings.0.protocol": "Https", - "probe.0.protocol": "Https", - "probe.0.timeout": "30", - "probe.0.unhealthy_threshold": "3", - "sku.0.capacity": "2", - "sku.0.name": "WAF_Medium", - "sku.0.tier": "WAF", - }, - "data.azurerm_resource_group.appinsights": infratests.AttributeValueMapping{ - "name": "cobalt-az-simple-" + workspace, - }, - "azurerm_monitor_autoscale_setting.app_service_auto_scale": infratests.AttributeValueMapping{ - "enabled": "true", - "name": "cobalt-az-simple-" + workspace + "-sp-autoscale", - "notification.0.email.0.send_to_subscription_administrator": "true", - "notification.0.email.0.send_to_subscription_co_administrator": "true", - "profile.0.rule.0.metric_trigger.0.metric_name": "CpuPercentage", - "profile.0.rule.0.metric_trigger.0.operator": "GreaterThan", - "profile.0.rule.0.metric_trigger.0.statistic": "Average", - "profile.0.rule.0.metric_trigger.0.threshold": "70", - "profile.0.rule.0.metric_trigger.0.time_aggregation": "Average", - "profile.0.rule.0.metric_trigger.0.time_grain": "PT1M", - "profile.0.rule.0.metric_trigger.0.time_window": "PT5M", - "profile.0.rule.0.scale_action.0.cooldown": "PT10M", - "profile.0.rule.0.scale_action.0.direction": "Increase", - "profile.0.rule.0.scale_action.0.type": "ChangeCount", - "profile.0.rule.0.scale_action.0.value": "1", - "profile.0.rule.1.metric_trigger.0.metric_name": "CpuPercentage", - "profile.0.rule.1.metric_trigger.0.operator": "GreaterThan", - "profile.0.rule.1.metric_trigger.0.statistic": "Average", - "profile.0.rule.1.metric_trigger.0.threshold": "25", - "profile.0.rule.1.metric_trigger.0.time_aggregation": "Average", - "profile.0.rule.1.metric_trigger.0.time_grain": "PT1M", - "profile.0.rule.1.metric_trigger.0.time_window": "PT5M", - "profile.0.rule.1.scale_action.0.cooldown": "PT1M", - "profile.0.rule.1.scale_action.0.direction": "Decrease", - "profile.0.rule.1.scale_action.0.type": "ChangeCount", - "profile.0.rule.1.scale_action.0.value": "1", - }, + "module.app_service.azurerm_app_service.appsvc[0]": expectedAppServicePlan, + "module.app_gateway.azurerm_application_gateway.appgateway": expectedAppGatewayPlan, + "module.service_plan.azurerm_monitor_autoscale_setting.app_service_auto_scale": expectedAutoScalePlan, }, } diff --git a/infra/templates/azure-simple/variables.tf b/infra/templates/azure-simple/variables.tf index a4a797c..45811c6 100644 --- a/infra/templates/azure-simple/variables.tf +++ b/infra/templates/azure-simple/variables.tf @@ -1,7 +1,7 @@ # Resource Group variable "resource_group_location" { description = "The deployment location of resource group container all the resources" - type = "string" + type = string } variable "application_type" { @@ -11,17 +11,17 @@ variable "application_type" { variable "name" { description = "The name of the deployment. This will be used across the resource created in this solution" - type = "string" + type = string } variable "app_service_name" { description = "The name key value pair where the key is the name assigned to the app service and value is the source container" - type = "map" + type = map(string) } variable "subnet_service_endpoints" { description = "The list of service endpoints that will be given to each subnet" - type = "list" + type = list(string) default = ["Microsoft.Web"] } @@ -53,67 +53,67 @@ variable "appgateway_http_listener_protocol" { # Monitoring Service variable "action_group_name" { description = "The name of the action group." - type = "string" + type = string default = "Simple Default Action Group" } variable "action_group_email_receiver" { description = "The e-mail receiver for an alert rule resource." - type = "string" + type = string default = "" } variable "metric_alert_name" { description = "The display name of a group of metric alert criteria." - type = "string" + type = string default = "Simple Default Metric Alerts" } variable "metric_alert_frequency" { description = "The frequency with which the metric alert checks if the conditions are met." - type = "string" + type = string default = "PT1M" } variable "metric_alert_period" { description = "The look back window over which metric values are checked. Value must be greater than 'frequency'." - type = "string" + type = string default = "PT5M" } variable "metric_alert_criteria_namespace" { description = "A monitored resource namespace with configurable metric alert criteria." - type = "string" + type = string default = "Microsoft.Web/serverfarms" } variable "metric_alert_criteria_name" { description = "A predefined Azure resource alert monitoring rule name." - type = "string" + type = string default = "CpuPercentage" } variable "metric_alert_criteria_aggregation" { description = "The calculation used for building metric alert criteria." - type = "string" + type = string default = "Average" } variable "metric_alert_criteria_operator" { description = "A logical operator used for building metric alert criteria." - type = "string" + type = string default = "GreaterThan" } variable "metric_alert_criteria_threshold" { description = "The criteria threshold value that activates the metric alert." - type = "string" - default = "50" + type = number + default = 50 } variable "scaling_values" { description = "Targets app instances made available from app service plan scaling options." - type = "list" + type = list(string) default = ["*"] } @@ -121,18 +121,19 @@ variable "scaling_values" { variable "docker_registry_server_url" { description = "The url of the container registry that will be utilized to pull container into the Web Apps for containers" - type = "string" + type = string default = "index.docker.io" } variable "docker_registry_server_username" { description = "The username used to authenticate with the container registry" - type = "string" + type = string default = "" } variable "docker_registry_server_password" { description = "The password used to authenticate with the container regitry" - type = "string" + type = string default = "" } + diff --git a/infra/templates/azure-simple/versions.tf b/infra/templates/azure-simple/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/infra/templates/azure-simple/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/test-harness/README.md b/test-harness/README.md index fd2083a..1228630 100644 --- a/test-harness/README.md +++ b/test-harness/README.md @@ -199,8 +199,8 @@ Our test harness uses a base docker image to pre-package dependencies like Terra ##### Script Arguments -- `-g` | `--go_version`: Golang version specification. This argument drives the version of the `golang` stretch base image. **Defaults** to `1.11`. -- `-t` | `--tf_version`: Terraform version specification. This argument drives which terraform version release this image will use.. **Defaults** to `0.11.13` +- `-g` | `--go_version`: Golang version specification. This argument drives the version of the `golang` stretch base image. **Defaults** to `1.12.5`. +- `-t` | `--tf_version`: Terraform version specification. This argument drives which terraform version release this image will use.. **Defaults** to `0.12.1` Keep in mind that the terraform version should align with the version from the provider [module](/infra/modules/providers/azure/provider/main.tf#L6) diff --git a/test-harness/build-base-image.sh b/test-harness/build-base-image.sh index a4e554f..3117d3f 100755 --- a/test-harness/build-base-image.sh +++ b/test-harness/build-base-image.sh @@ -110,8 +110,8 @@ function build_image(){ --build-arg tfver=$tf_version } -declare go_version="1.11" -declare tf_version="0.11.13" +declare go_version="1.12.5" +declare tf_version="0.12.1" parseInput "$@" declare docker_img="msftcse/cobalt-test-base" diff --git a/test-harness/docker/base-images/Dockerfile b/test-harness/docker/base-images/Dockerfile index b6de731..dec8d2b 100644 --- a/test-harness/docker/base-images/Dockerfile +++ b/test-harness/docker/base-images/Dockerfile @@ -34,7 +34,7 @@ ENV GOPATH $HOME/go ENV GOBIN /usr/local/go # Install Terraform -ARG tfver=0.11.13 +ARG tfver=0.12.1 ENV TF_VERSION=$tfver RUN wget --quiet https://releases.hashicorp.com/terraform/${TF_VERSION}/terraform_${TF_VERSION}_linux_amd64.zip \ && unzip terraform_${TF_VERSION}_linux_amd64.zip \ diff --git a/test-harness/docker/base-images/README.md b/test-harness/docker/base-images/README.md index 39665e0..4ac4d80 100644 --- a/test-harness/docker/base-images/README.md +++ b/test-harness/docker/base-images/README.md @@ -31,7 +31,7 @@ Golang version specification. This argument drives the version of the `golang` s Terraform version specification. This argument drives which terraform version release this image will use. ```shell -docker build -f "test-harness\docker\base-images\Dockerfile" -t msftcse/cobalt-test-base:1.11 . --build-arg gover=1.11 tfver=0.11.13 +docker build -f "test-harness\docker\base-images\Dockerfile" -t msftcse/cobalt-test-base:1.12.5 . --build-arg gover=1.12.5 tfver=0.12.1 ``` ## Contributing diff --git a/test-harness/infratests/integration.go b/test-harness/infratests/integration.go index d96c79c..b612d9c 100644 --- a/test-harness/infratests/integration.go +++ b/test-harness/infratests/integration.go @@ -1,5 +1,5 @@ /* -This file provides abstractions that simplify the process of integration-testing terraform templates. The goal +Package infratests This file provides abstractions that simplify the process of integration-testing terraform templates. The goal is to minimize the boiler plate code required to effectively test terraform templates in order to reduce the effort required to write robust template integration-tests. */ diff --git a/test-harness/infratests/plan.go b/test-harness/infratests/plan.go new file mode 100644 index 0000000..07698ad --- /dev/null +++ b/test-harness/infratests/plan.go @@ -0,0 +1,17 @@ +/* +Package infratests this file provides a model for the JSON representation of a terraform plan. It describes +a minimal set of metadata produced by the plan and can be expanded to support other attributes +if needed +*/ +package infratests + +// TerraformPlan a JSON schema for the output of `terraform plan ` +type TerraformPlan struct { + ResourceChanges []struct { + Address string `json:"address"` + Change struct { + Actions []string `json:"actions"` + After map[string]interface{} `json:"after"` + } `json:"change"` + } `json:"resource_changes"` +} diff --git a/test-harness/infratests/unit.go b/test-harness/infratests/unit.go index d39f0b1..0219987 100644 --- a/test-harness/infratests/unit.go +++ b/test-harness/infratests/unit.go @@ -1,30 +1,28 @@ /* -This file provides abstractions that simplify the process of unit-testing terraform templates. The goal +Package infratests This file provides abstractions that simplify the process of unit-testing terraform templates. The goal is to minimize the boiler plate code required to effectively test terraform templates in order to reduce the effort required to write robust template unit-tests. */ package infratests import ( + "encoding/json" "errors" "fmt" "os" - "path" + "os/exec" + "path/filepath" "testing" "github.com/gruntwork-io/terratest/modules/random" "github.com/gruntwork-io/terratest/modules/terraform" - terraformCore "github.com/hashicorp/terraform/terraform" ) -// AttributeValueMapping Identifies mapping between attributes and values -type AttributeValueMapping map[string]string - // ResourceDescription Identifies mappings between resources and attributes -type ResourceDescription map[string]AttributeValueMapping +type ResourceDescription map[string]map[string]interface{} // TerraformPlanValidation A function that can run an assertion over a terraform plan -type TerraformPlanValidation func(goTest *testing.T, plan *terraformCore.Plan) +type TerraformPlanValidation func(goTest *testing.T, plan TerraformPlan) // UnitTestFixture Holds metadata required to execute a unit test against a test against a terraform template type UnitTestFixture struct { @@ -55,7 +53,7 @@ func RunUnitTests(fixture *UnitTestFixture) { defer terraform.RunTerraformCommand(fixture.GoTest, fixture.TfOptions, "workspace", "delete", workspaceName) defer terraform.WorkspaceSelectOrNew(fixture.GoTest, fixture.TfOptions, "default") - tfPlanFilePath := random.UniqueId() + ".plan" + tfPlanFilePath := filepath.FromSlash(fmt.Sprintf("%s/%s.plan", os.TempDir(), random.UniqueId())) terraform.RunTerraformCommand( fixture.GoTest, fixture.TfOptions, @@ -72,17 +70,7 @@ func RunUnitTests(fixture *UnitTestFixture) { // - The resource <--> attribute <--> attribute value mappings match the parameters from the test fixture // - The plan passes any user-defined assertions func validateTerraformPlanFile(fixture *UnitTestFixture, tfPlanFilePath string) { - file, err := os.Open(path.Join(fixture.TfOptions.TerraformDir, tfPlanFilePath)) - if err != nil { - fixture.GoTest.Fatal(err) - } - defer file.Close() - - plan, err := terraformCore.ReadPlan(file) - if err != nil { - fixture.GoTest.Fatal(err) - } - + plan := parseTerraformPlan(fixture, tfPlanFilePath) validatePlanCreateProperties(fixture, plan) validatePlanResourceKeyValues(fixture, plan) @@ -94,74 +82,86 @@ func validateTerraformPlanFile(fixture *UnitTestFixture, tfPlanFilePath string) } } +func parseTerraformPlan(fixture *UnitTestFixture, filePath string) TerraformPlan { + // Note: when the PR linked below is merged and the new build is used by this codebase, + // we can leverage Terratest to run this for us. Currently with large plan outputs, + // a buffer overflow will happen in Terratest because the default max character limit + // may be exceeded for large plan files: + // + // - Issue: https://github.com/gruntwork-io/terratest/issues/203 + // - PR: https://github.com/gruntwork-io/terratest/pull/317 + // + // jsonBytes := []bytes(terraform.RunTerraformCommand( + // fixture.GoTest, + // fixture.TfOptions, + // terraform.FormatArgs(&terraform.Options{}, "show", "-json", filePath)...)) + cmd := exec.Command("terraform", "show", "-json", filePath) + cmd.Dir = fixture.TfOptions.TerraformDir + jsonBytes, cmdErr := cmd.Output() + if cmdErr != nil { + fixture.GoTest.Fatal(cmdErr) + } + + fmt.Println("Got terraform plan...", string(jsonBytes)) + var plan TerraformPlan + jsonErr := json.Unmarshal(jsonBytes, &plan) + if jsonErr != nil { + fixture.GoTest.Fatal(jsonErr) + } + return plan +} + // Validates high level attributes of a terraform plan creat properties. This includes: // - The plan is not empty // - The plan contains the correct number of resources -// - The plan is only creating resources -func validatePlanCreateProperties(fixture *UnitTestFixture, plan *terraformCore.Plan) { - if plan.Diff.Empty() { +// - The plan is not executing any destructive actions +func validatePlanCreateProperties(fixture *UnitTestFixture, plan TerraformPlan) { + if len(plan.ResourceChanges) == 0 { fixture.GoTest.Fatal(errors.New("Plan diff was unexpectedly empty")) } - // plans should contain diffs of type `DiffCreate` otherwise the test may accidentally remove resources - for _, module := range plan.Diff.Modules { - if module.ChangeType() != terraformCore.DiffCreate { - fixture.GoTest.Fatal( - fmt.Errorf("Plan unexpectedly contained an update of type '%s'", string(module.ChangeType()))) - } - } - - resourceCount := 0 - for _, module := range plan.Diff.Modules { - resourceCount += len(module.Resources) - } - - // every plan should have the correct number of resources - if resourceCount != fixture.ExpectedResourceCount { + if len(plan.ResourceChanges) != fixture.ExpectedResourceCount { fixture.GoTest.Fatal(fmt.Errorf( - "Plan unexpectedly had %d resources instead of %d", resourceCount, fixture.ExpectedResourceCount)) - } -} - -// validates that the resource <--> attribute <--> attribute value mappings match the parameters -// from the test fixture -func validatePlanResourceKeyValues(fixture *UnitTestFixture, plan *terraformCore.Plan) { - // collect actual resource attrubte value mappings by iterating over the TF plan - seen := ResourceDescription{} - for _, module := range plan.Diff.Modules { - for resource, resourceDiffs := range module.Resources { - seen[resource] = AttributeValueMapping{} - for attribute, vals := range resourceDiffs.Attributes { - seen[resource][attribute] = vals.New - } - } + "Plan unexpectedly had %d resources instead of %d", len(plan.ResourceChanges), fixture.ExpectedResourceCount)) } - // verify that for each of the expected resource attribute value mappings that the expected - // values are found in the terraform plan - for resource, expectedMappings := range fixture.ExpectedResourceAttributeValues { - _, resourceFound := seen[resource] - if !resourceFound { - fixture.GoTest.Fatal(fmt.Errorf( - "Plan unexpectedly did not contain a change for resource '%s'", resource)) - } - - for expectedAttr, expectedVal := range expectedMappings { - actualVal, attrFound := seen[resource][expectedAttr] - if !attrFound { - fixture.GoTest.Fatal(fmt.Errorf( - "Plan unexpectedly did not contain a change for '%s.%s'", resource, expectedAttr)) - } - - if expectedVal != actualVal { - fixture.GoTest.Fatal(fmt.Errorf( - "Plan unexpectedly had value '%s' instead of '%s' for '%s.%s'", - actualVal, - expectedVal, - resource, - expectedAttr, - )) + // a unit test should never create a destructive action like deleting a resource + allowedActions := map[string]bool{"create": true, "read": true} + for _, resource := range plan.ResourceChanges { + for _, action := range resource.Change.Actions { + if !allowedActions[action] { + fixture.GoTest.Fatal( + fmt.Errorf("Plan unexpectedly actions other than `create`: %s", resource.Change.Actions)) } } } } + +// verifies that the attribute value mappings for each resource specified by the client exist +// as a subset of the actual values defined in the terraform plan. +func validatePlanResourceKeyValues(fixture *UnitTestFixture, plan TerraformPlan) { + theRealPlanAsMap := planToMap(plan) + theExpectedPlanAsMap := resourceDescriptionToMap(fixture.ExpectedResourceAttributeValues) + + if err := verifyTargetsExistInMap(theRealPlanAsMap, theExpectedPlanAsMap); err != nil { + fixture.GoTest.Fatal(err) + } +} + +// transforms the output of `terraform show -json ` into a generic map +func planToMap(plan TerraformPlan) map[string]interface{} { + mp := make(map[string]interface{}) + for _, resource := range plan.ResourceChanges { + mp[resource.Address] = resource.Change.After + } + return mp +} + +// transforms a resource description into a generic map +func resourceDescriptionToMap(resources ResourceDescription) map[string]interface{} { + mp := make(map[string]interface{}) + for key, value := range resources { + mp[key] = value + } + return mp +} diff --git a/test-harness/infratests/validate.go b/test-harness/infratests/validate.go new file mode 100644 index 0000000..e2a2b33 --- /dev/null +++ b/test-harness/infratests/validate.go @@ -0,0 +1,128 @@ +/* +Package infratests This file provides validation utilities that can be used by the core testing constructs +*/ +package infratests + +import ( + "fmt" + "reflect" +) + +// This function validates that a set of search targets exist in a map. The intended use case is to allow +// a user of this library to provide a set of *expected values* that should exist within a larger set of +// *actual values.* In other words, this is a map equality check that does not care about ordering in keys/lists +// and will not fail if the *expected values* are a subset of the *actual values.* +// +// In the case that the *expected values* are found in the *actual values,* nil will be returned. Otherwise an +// error describing the mismatch will be returned. +// +// Some examples (in pseudo-code): +// - Exact Match: +// a := {"key1":[{"key2" : "foo"}, {"key2" : "bar"}]} +// verifyTargetsExistInMap(a, a) --> nil +// +// - Subset Match #1: +// a := {"key1":[{"key2" : "foo"}, {"key2" : "bar"}]} +// b := {"key1":[{"key2" : "foo"}]} +// verifyTargetsExistInMap(a, b) --> nil +// +// - Subset Match #2: +// a := {"key1":[{"key2" : "foo"}, {"key2" : "bar"}]} +// b := {"key1":[]} +// verifyTargetsExistInMap(a, b) --> nil +// +// - Subset Match #3: +// a := {"key1":{"key2": "foo", "key3", "bar"}} +// b := {"key1":{"key3", "bar"}} +// verifyTargetsExistInMap(a, b) --> nil +// +// - Mismatch #1: +// a := {"key1":{"key2": "foo", "key3", "bar"}} +// b := {"key1":[]} +// verifyTargetsExistInMap(a, b) --> ERROR: wrong type for key `key1` +// +// - Mismatch #2: +// a := {"key1":{"key2": "foo", "key3", "bar"}} +// b := {"key1":{"key4": "foo"}} +// verifyTargetsExistInMap(a, b) --> ERROR: `key4` not found +// +// - Mismatch #3: +// a := {"key1":{"key2": "foo", "key3", "bar"}} +// b := {"key1":{"key2": "bar"}} +// verifyTargetsExistInMap(a, b) --> ERROR: wrong value for `key2` +// +// The algorithm used to do the equality check is to execute a DFS search in parallel for both maps. In the case +// that a mismatch (the values do not match, or the shape of the maps is different in a way that indicates a mismatch) +// is identified, the search will be terminated. If no mismatches are found then `nil` is returned +func verifyTargetsExistInMap(dataSource map[string]interface{}, searchTargets map[string]interface{}) error { + for targetKey := range searchTargets { + candidateMatch, candidateExists := dataSource[targetKey] + target, targetExists := searchTargets[targetKey] + + // both maps should contain the target search key + if !candidateExists || !targetExists { + return fmt.Errorf("Unexpectedly could not find key '%s'", targetKey) + } + + // the values for the key should be the same type + if !isSameType(candidateMatch, target) { + return fmt.Errorf("Unexpectedly found type '%T' instead of '%T'", candidateMatch, target) + } + + // the key is found and both values are of the same type. time to look for a subset match + switch typedTarget := target.(type) { + case bool, float32, float64, int, string: + if typedTarget != candidateMatch { + return fmt.Errorf("Expected %s but got %s", typedTarget, candidateMatch) + } + case []interface{}: + if err := verifyTargetsExistInList(candidateMatch.([]interface{}), typedTarget); err != nil { + return err + } + case map[string]interface{}: + if err := verifyTargetsExistInMap(candidateMatch.(map[string]interface{}), typedTarget); err != nil { + return err + } + default: + return fmt.Errorf("Comparison for type '%T' in a map not implemented", typedTarget) + } + + } + + return nil +} + +// This function has the same semantics as `verifyTargetsExistInMap` (so the documentation will not be repeated) +// except that it works for lists. +func verifyTargetsExistInList(dataSource []interface{}, searchTargets []interface{}) error { + for _, target := range searchTargets { + matchFound := false + + switch typedTarget := target.(type) { + case bool, float32, float64, int, string: + for _, candidateMatch := range dataSource { + matchFound = matchFound || typedTarget == candidateMatch + } + case map[string]interface{}: + for _, candidateMatch := range dataSource { + if isSameType(candidateMatch, typedTarget) { + err := verifyTargetsExistInMap(candidateMatch.(map[string]interface{}), typedTarget) + matchFound = matchFound || err == nil + } + } + default: + return fmt.Errorf("Comparison for type '%T' in a list not yet implemented", typedTarget) + } + + if !matchFound { + return fmt.Errorf("Unexpectedly did not find '%s' in '%s'", target, dataSource) + } + } + + return nil +} + +// return true if the values have the same type, false otherwise +func isSameType(a interface{}, b interface{}) bool { + return reflect.TypeOf(a) == reflect.TypeOf(b) +} diff --git a/test-harness/infratests/validate_test.go b/test-harness/infratests/validate_test.go new file mode 100644 index 0000000..2ca560a --- /dev/null +++ b/test-harness/infratests/validate_test.go @@ -0,0 +1,89 @@ +package infratests + +import ( + "encoding/json" + "testing" +) + +var tests = []struct { + dataSourceJSON string + searchTargetsJSON string + shouldPass bool +}{ + { + `{"key1":[{"key2" : "foo"}, {"key2" : "bar"}]}`, + `{"key1":[{"key2" : "foo"}, {"key2" : "bar"}]}`, + true, + }, { + `{"key1":[{"key2" : "foo"}, {"key2" : "bar"}]}`, + `{"key1":[{"key2" : "foo"}]}`, + true, + }, { + `{"key1":[{"key2" : "foo"}, {"key2" : "bar"}]}`, + `{"key1":[]}`, + true, + }, { + `{"key1":{"key2": "foo", "key3": "bar"}}`, + `{"key1":{"key3": "bar"}}`, + true, + }, { + `{"key1":[{"key2" : "foo"}, {"key2" : "bar"}]}`, + `{}`, + true, + }, { + `{"key1":{"key2": "foo", "key3": "bar"}}`, + `{"key1":[]}`, + false, // key has wrong type + }, { + `{"key1":{"key2": "foo", "key3": "bar"}}`, + `{"key1":{"key4": "foo"}}`, + false, // key does not exist in data source + }, { + `{"key1":{"key2": "foo", "key3": "bar"}}`, + `{"key1":{"key2": "bar"}}`, + false, // key has wrong value + }, { + `{"key1":[1, 2, 3]}`, + `{"key1":[4]}`, + false, // list value does not exist in parent + }, { + `{"key1":[{"key2": "foo"}]}`, + `{"key1":[{"key3": "foo"}]}`, + false, // list value does not exist in parent + }, { + `{"key1":[{"key2": "foo"}]}`, + `{"key1":[{"key2": "bar"}]}`, + false, // list value does not exist in parent + }, +} + +func TestVerifyTargets(t *testing.T) { + for _, test := range tests { + err := verifyTargetsExistInMap( + jsonToMap(t, test.dataSourceJSON), + jsonToMap(t, test.searchTargetsJSON)) + + // the test should pass but there was an error + if test.shouldPass && err != nil { + t.Errorf("Search Targets `%s` were unexpectedly not found in Data Source `%s`. %s", + test.searchTargetsJSON, + test.dataSourceJSON, + err) + } + + // the test should not pass but there was no error + if !test.shouldPass && err == nil { + t.Errorf("Search Targets `%s` were unexpectedly found in Data Source `%s`", + test.searchTargetsJSON, + test.dataSourceJSON) + } + } +} + +func jsonToMap(t *testing.T, jsonStr string) map[string]interface{} { + var theMap map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &theMap); err != nil { + t.Errorf("Unable to parse JSON `%s`. Error = `%s`", jsonStr, err) + } + return theMap +} diff --git a/test-harness/magefile.go b/test-harness/magefile.go index 0704685..7fbf517 100644 --- a/test-harness/magefile.go +++ b/test-harness/magefile.go @@ -23,10 +23,16 @@ func RunAllTargets() { mg.Deps(CleanAll) mg.Deps(LintCheckGo) mg.Deps(LintCheckTerraform) + mg.Deps(RunTestHarnessUnitTests) mg.Deps(RunUnitTests) mg.Deps(RunIntegrationTests) } +// RunTestHarnessUnitTests run unit test for the test harness itself +func RunTestHarnessUnitTests() error { + return sh.RunV("go", "test", "github.com/microsoft/cobalt/test-harness/infratests") +} + // RunUnitTests A build step that runs unit tests func RunUnitTests() error { fmt.Println("INFO: Running unit tests...")