aws-cfn-compiler 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e475a82e8e4ec0c15474b19670a80d0248cdb438
4
+ data.tar.gz: 68511f24b75c51d805292ca3a3843944d064c0d0
5
+ SHA512:
6
+ metadata.gz: 9f34e56e832af14e2153713f10d2e2b7193aa68f75b416100141c40214f59ae4fc48fdd1a1cca06996e9a51f43118594055baebbb964740ae22e466bd86757b6
7
+ data.tar.gz: 46dfbb1fde0098468d40778996324c8a5b7a734ad94be1d3e8044784f33e65c72bd12599978eea50943ee91fe145803cc0b146da3ee7239591f0ef5d2b5d6ec4
data/.gitignore ADDED
@@ -0,0 +1,24 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
23
+ compiled.json
24
+ Gemfile.lock
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ aws-cfn-compile
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in aws-cfn-compiler.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Christo DeLange
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ aws-cfn-compiler
2
+ ================
3
+
4
+ A simple script to compile and perform some validation for CloudFormation scripts. The idea is to create a folder structure to better manage pieces of a CloudFormation deployment. Additionally, writing in JSON is hard, so the compiler takes YAML files as well.
5
+
6
+
7
+ Installation
8
+ ------------
9
+
10
+ gem install bundler
11
+ bundle install
12
+
13
+ Usage
14
+ -----
15
+
16
+ ```
17
+ ./compile.rb -d ROOT_DIRECTORY -o OUTPUT_JSON_FILE
18
+ ```
19
+
20
+ Directory Structure
21
+ -------------------
22
+
23
+ The pieces of the CloudFormation script is split into four groups:
24
+
25
+ * Parameters
26
+ * Mappings
27
+ * Resources
28
+ * Outputs
29
+
30
+ For each group, you can define a single file at the root directory with that name (i.e. outputs.json or outputs.yml) or a directory with that name containing any structure of JSON or YAML files (i.e. resources/nat.yml or resources/app/hello.json). The script is responsible for combining everything into one JSON file.
31
+
32
+ Reference Validation
33
+ --------------------
34
+
35
+ After all the pieces are stiched together, the system runs through the file finding references to names and then attempt to validate that those names exist in the file.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'aws/cfn/compiler/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "aws-cfn-compiler"
8
+ spec.version = Aws::Cfn::Compiler::VERSION
9
+ spec.authors = ["PKinney"]
10
+ spec.email = ["pkinney@github.com"]
11
+ spec.summary = %q{A simple script to compile and perform some validation for CloudFormation scripts.}
12
+ spec.description = %q{The idea is to create a folder structure to better manage pieces of a CloudFormation deployment. Additionally, writing in JSON is hard, so the compiler takes YAML files as well.}
13
+ spec.homepage = "https://github.com/dldinternet/aws-cfn-compiler"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "awesome_print"
22
+ spec.add_dependency "slop"
23
+ spec.add_dependency "psych"
24
+ spec.add_dependency "json"
25
+
26
+ spec.add_development_dependency 'bundler', "~> 1.6"
27
+ spec.add_development_dependency 'rake'
28
+ end
@@ -0,0 +1,25 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="RUBY_MODULE" version="4">
3
+ <component name="CompassSettings">
4
+ <option name="compassSupportEnabled" value="true" />
5
+ </component>
6
+ <component name="FacetManager">
7
+ <facet type="gem" name="Ruby Gem">
8
+ <configuration>
9
+ <option name="GEM_APP_ROOT_PATH" value="" />
10
+ <option name="GEM_APP_TEST_PATH" value="" />
11
+ <option name="GEM_APP_LIB_PATH" value="" />
12
+ </configuration>
13
+ </facet>
14
+ </component>
15
+ <component name="NewModuleRootManager" inherit-compiler-output="true">
16
+ <exclude-output />
17
+ <content url="file://$MODULE_DIR$" />
18
+ <orderEntry type="jdk" jdkName="RVM: ruby-2.1.2" jdkType="RUBY_SDK" />
19
+ <orderEntry type="sourceFolder" forTests="false" />
20
+ <orderEntry type="library" scope="PROVIDED" name="awesome_print (v1.2.0, RVM: ruby-2.1.2) [gem]" level="application" />
21
+ <orderEntry type="library" scope="PROVIDED" name="bundler (v1.6.2, RVM: ruby-2.1.2) [gem]" level="application" />
22
+ <orderEntry type="library" scope="PROVIDED" name="slop (v3.5.0, RVM: ruby-2.1.2) [gem]" level="application" />
23
+ </component>
24
+ </module>
25
+
data/bin/cfn-compiler ADDED
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+
5
+ # require 'safe_yaml'
6
+ # SafeYAML::OPTIONS[:default_mode] = :safe
7
+
8
+ # Borrowing from "whiches" gem ...
9
+ cmd = 'json_pp'
10
+ exes = []
11
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
12
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
13
+ exts.each { |ext|
14
+ exe = File.join(path, "#{cmd}#{ext}")
15
+ exes << exe if File.executable? exe
16
+ }
17
+ end
18
+ path = if exes.size > 0
19
+ File.dirname(exes[0])
20
+ else
21
+ File.dirname(__FILE__)
22
+ end
23
+
24
+ add_path = File.expand_path(File.join(path, "..", "lib"))
25
+ $:.unshift(add_path)
26
+
27
+ require 'aws/cfn/compiler'
28
+ Aws::Cfn::Compiler::Main.new().run
@@ -0,0 +1,11 @@
1
+ {
2
+ "AWSRegionArch2AMI" : {
3
+ "us-east-1" : { "64" : "ami-1624987f" },
4
+ "us-west-1" : { "64" : "ami-1bf9de5e" },
5
+ "us-west-2" : { "64" : "ami-2a31bf1a" },
6
+ "eu-west-1" : { "64" : "ami-c37474b7" },
7
+ "sa-east-1" : { "64" : "ami-1e08d103" },
8
+ "ap-southeast-1" : { "64" : "ami-a6a7e7f4" },
9
+ "ap-northeast-1" : { "64" : "ami-4e6cd34f" }
10
+ }
11
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "AWSInstanceType2Arch" : {
3
+ "t1.micro" : { "Arch" : "64" },
4
+ "m1.small" : { "Arch" : "64" },
5
+ "m1.medium" : { "Arch" : "64" },
6
+ "m1.large" : { "Arch" : "64" },
7
+ "m1.xlarge" : { "Arch" : "64" },
8
+ "m2.xlarge" : { "Arch" : "64" },
9
+ "m2.2xlarge" : { "Arch" : "64" },
10
+ "m2.4xlarge" : { "Arch" : "64" },
11
+ "c1.medium" : { "Arch" : "64" },
12
+ "c1.xlarge" : { "Arch" : "64" }
13
+ }
14
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "AWSRegionArch2AMINAT" : {
3
+ "us-east-1" : { "64" : "ami-f619c29f" },
4
+ "us-west-1" : { "64" : "ami-3bcc9e7e" },
5
+ "us-west-2" : { "64" : "ami-52ff7262" },
6
+ "eu-west-1" : { "64" : "ami-e5e2d991" },
7
+ "sa-east-1" : { "64" : "ami-0039e61d" },
8
+ "ap-southeast-1" : { "64" : "ami-02eb9350" },
9
+ "ap-northeast-1" : { "64" : "ami-14d86d15" }
10
+ }
11
+ }
@@ -0,0 +1,16 @@
1
+ VpcId:
2
+ Value:
3
+ Ref: VPC
4
+ Description: ID of newly created VPC
5
+
6
+ AccessIP:
7
+ Value:
8
+ Ref: AccessIP
9
+ Description: NAT Instance ID
10
+
11
+ VPCCidrIP:
12
+ Value:
13
+ "Fn::GetAtt":
14
+ - VPC
15
+ - CidrBlock
16
+ Description: Cidr IP of the VPC
@@ -0,0 +1,36 @@
1
+ { "VPCPrefix" : {
2
+ "Description" : "IP Prefix for VPC (xxx.xxx)",
3
+ "Type" : "String",
4
+ "MinLength": "1",
5
+ "MaxLength": "64",
6
+ "AllowedPattern" : "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)",
7
+ "ConstraintDescription" : "First two numbers for an IP"
8
+ },
9
+
10
+ "URLSubfix" : {
11
+ "Description" : "Additional component of the URL: app.[URLSubfix.][hostedZoneName]",
12
+ "Type" : "String",
13
+ "MinLength": "0",
14
+ "MaxLength": "64",
15
+ "AllowedPattern" : "([a-z0-9_\-]+\.|)",
16
+ "ConstraintDescription" : "Must be alphanumerics, underscore, or dash and end in a dot or may be blank"
17
+ },
18
+
19
+ "Route53HostedZoneName" : {
20
+ "Description" : "Name of the hosted zone (i.e. myapp.com)",
21
+ "Type" : "String",
22
+ "MinLength": "3",
23
+ "MaxLength": "64",
24
+ "AllowedPattern" : "[a-z0-9_\-\.]+",
25
+ "ConstraintDescription" : "Must be alphanumerics, underscores, dashes, or dots"
26
+ },
27
+
28
+ "KeyName" : {
29
+ "Description" : "Name of an existing EC2 KeyPair to enable SSH access to the instances",
30
+ "Type" : "String",
31
+ "MinLength": "1",
32
+ "MaxLength": "64",
33
+ "AllowedPattern" : "[-_ a-zA-Z0-9]*",
34
+ "ConstraintDescription" : "can contain only alphanumeric characters, spaces, dashes and underscores."
35
+ }
36
+ }
@@ -0,0 +1,18 @@
1
+ { "InternetGateway" : {
2
+ "Type" : "AWS::EC2::InternetGateway",
3
+ "Properties" : {
4
+ "Tags" : [
5
+ {"Key" : "Application", "Value" : { "Ref" : "AWS::StackName"} },
6
+ {"Key" : "Network", "Value" : "Public" }
7
+ ]
8
+ }
9
+ },
10
+
11
+ "AttachGateway" : {
12
+ "Type" : "AWS::EC2::VPCGatewayAttachment",
13
+ "Properties" : {
14
+ "VpcId" : { "Ref" : "VPC" },
15
+ "InternetGatewayId" : { "Ref" : "InternetGateway" }
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,15 @@
1
+ AppServer:
2
+ Type: AWS::EC2::Instance
3
+ Properties:
4
+ InstanceType: t1.micro
5
+ KeyName:
6
+ Ref: KeyName
7
+ SubnetId:
8
+ Ref: PublicASubnet
9
+ ImageId:
10
+ "Fn::FindInMap":
11
+ - AWSRegionArch2AMI
12
+ - Ref: AWS::Region
13
+ - 64
14
+ SecurityGroupIds:
15
+ - Ref: AppSG
@@ -0,0 +1,20 @@
1
+ { "AccessIP" : {
2
+ "Type" : "AWS::EC2::EIP",
3
+ "Properties" : {
4
+ "Domain" : "vpc",
5
+ "InstanceId" : { "Ref" : "AccessA1" }
6
+ }
7
+ },
8
+
9
+ "AccessA1" : {
10
+ "Type" : "AWS::EC2::Instance",
11
+
12
+ "Properties" : {
13
+ "InstanceType" : "m1.small",
14
+ "ImageId" : { "Fn::FindInMap" : [ "AWSRegionArch2AMI", { "Ref" : "AWS::Region" }, "64" ]},
15
+ "SecurityGroupIds" : [{ "Ref" : "AccessSG" }],
16
+ "SubnetId" : { "Ref" : "PublicASubnet" },
17
+ "KeyName" : { "Ref" : "KeyName" }
18
+ }
19
+ }
20
+ }
@@ -0,0 +1,12 @@
1
+ { "NATDevice" : {
2
+ "Type" : "AWS::EC2::Instance",
3
+ "Properties" : {
4
+ "InstanceType" : "t1.micro",
5
+ "KeyName" : { "Ref" : "KeyName" },
6
+ "SubnetId" : { "Ref" : "PublicASubnet" },
7
+ "SourceDestCheck" : "false",
8
+ "ImageId" : { "Fn::FindInMap" : [ "AWSRegionArch2AMINAT", { "Ref" : "AWS::Region" }, "64" ]},
9
+ "SecurityGroupIds" : [{ "Ref" : "NATSG" }]
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,16 @@
1
+ { "Route53" : {
2
+ "Type" : "AWS::Route53::RecordSetGroup",
3
+ "Properties" : {
4
+ "HostedZoneName" : {"Ref" : "Route53HostedZoneName"},
5
+ "RecordSets" : [
6
+ { "Type" : "AWS::Route53::RecordSet",
7
+ "Properties" : {
8
+ "Name" : {"Fn::Join" : [ "", "app.", [{"Ref" : "URLSubfix"}] ]},
9
+ "Type" : "A",
10
+ "AliasTarget" : "AppELB"
11
+ }
12
+ }
13
+ ]
14
+ }
15
+ }
16
+ }
@@ -0,0 +1,32 @@
1
+ { "PublicRouteTable" : {
2
+ "Type" : "AWS::EC2::RouteTable",
3
+ "Properties" : {
4
+ "VpcId" : {"Ref" : "VPC"}
5
+ }
6
+ },
7
+
8
+ "PublicRoute" : {
9
+ "Type" : "AWS::EC2::Route",
10
+ "Properties" : {
11
+ "RouteTableId" : { "Ref" : "PublicRouteTable" },
12
+ "DestinationCidrBlock" : "0.0.0.0/0",
13
+ "GatewayId" : { "Ref" : "InternetGateway" }
14
+ }
15
+ },
16
+
17
+ "PrivateRouteTable" : {
18
+ "Type" : "AWS::EC2::RouteTable",
19
+ "Properties" : {
20
+ "VpcId" : {"Ref" : "VPC"}
21
+ }
22
+ },
23
+
24
+ "PrivateRoute" : {
25
+ "Type" : "AWS::EC2::Route",
26
+ "Properties" : {
27
+ "RouteTableId" : { "Ref" : "PrivateRouteTable" },
28
+ "DestinationCidrBlock" : "0.0.0.0/0",
29
+ "InstanceId" : { "Ref" : "NATDevice" }
30
+ }
31
+ }
32
+ }
@@ -0,0 +1,54 @@
1
+ { "AccessSG" : {
2
+ "Type" : "AWS::EC2::SecurityGroup",
3
+ "Properties" : {
4
+ "VpcId" : { "Ref" : "VPC" },
5
+ "GroupDescription" : "Enable SSH access via port 22",
6
+ "SecurityGroupIngress" : [ { "IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "CidrIp" : "0.0.0.0/0" } ]
7
+ }
8
+ },
9
+
10
+ "NATSG" : {
11
+ "Type" : "AWS::EC2::SecurityGroup",
12
+ "Properties" : {
13
+ "GroupDescription" : "Enable internal access to the NAT device",
14
+ "VpcId" : { "Ref" : "VPC" },
15
+ "SecurityGroupIngress" : [
16
+ { "IpProtocol" : "tcp", "FromPort" : "0", "ToPort" : "65535", "CidrIp" : {"Fn::Join" : [ ".", [{"Ref" : "VPCPrefix"}, "0", "0/16"] ]} } ,
17
+ { "IpProtocol" : "udp", "FromPort" : "0", "ToPort" : "65535", "CidrIp" : {"Fn::Join" : [ ".", [{"Ref" : "VPCPrefix"}, "0", "0/16"] ]} } ,
18
+ { "IpProtocol" : "icmp", "FromPort" : "-1", "ToPort" : "-1", "CidrIp" : {"Fn::Join" : [ ".", [{"Ref" : "VPCPrefix"}, "0", "0/16"] ]} }
19
+ ],
20
+ "SecurityGroupEgress" : [
21
+ { "IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "CidrIp" : "0.0.0.0/0" } ,
22
+ { "IpProtocol" : "tcp", "FromPort" : "443", "ToPort" : "443", "CidrIp" : "0.0.0.0/0" },
23
+ { "IpProtocol" : "tcp", "FromPort" : "0", "ToPort" : "65535", "CidrIp" : {"Fn::Join" : [ ".", [{"Ref" : "VPCPrefix"}, "0", "0/16"] ]} },
24
+ { "IpProtocol" : "icmp", "FromPort" : "-1", "ToPort" : "-1", "CidrIp" : "0.0.0.0/0" }
25
+ ]
26
+ }
27
+ },
28
+
29
+ "AppSG" : {
30
+ "Type" : "AWS::EC2::SecurityGroup",
31
+ "Properties" : {
32
+ "GroupDescription" : "Application Server Security Group",
33
+ "VpcId" : { "Ref" : "VPC" },
34
+ "SecurityGroupIngress" : [
35
+ { "IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "SourceSecurityGroupName" : "AppELBSG" },
36
+ { "IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "SourceSecurityGroupName" : "AccessSG" }
37
+ ]
38
+ }
39
+ },
40
+
41
+ "AppELBSG" : {
42
+ "Type" : "AWS::EC2::SecurityGroup",
43
+ "Properties" : {
44
+ "VpcId" : { "Ref" : "VPC" },
45
+ "GroupDescription" : "Elastic Load Balancing for App Servers",
46
+ "SecurityGroupIngress" : [
47
+ { "IpProtocol" : "tcp", "FromPort" : "443", "ToPort" : "443", "CidrIp" : "0.0.0.0/0" }
48
+ ],
49
+ "SecurityGroupEgress" : [
50
+ { "IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "SourceSecurityGroupName" : "AppSG" }
51
+ ]
52
+ }
53
+ }
54
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "PublicASubnet" : {
3
+ "Type" : "AWS::EC2::Subnet",
4
+ "Properties" : {
5
+ "VpcId" : { "Ref" : "VPC" },
6
+ "AvailabilityZone" : "us-east-1a",
7
+ "CidrBlock" : {"Fn::Join" : [ ".", [{"Ref" : "VPCPrefix"}, "1", "0/24"] ]}
8
+ }
9
+ },
10
+
11
+ "PrivateASubnet" : {
12
+ "Type" : "AWS::EC2::Subnet",
13
+ "Properties" : {
14
+ "VpcId" : { "Ref" : "VPC" },
15
+ "AvailabilityZone" : "us-east-1a",
16
+ "CidrBlock" : {"Fn::Join" : [ ".", [{"Ref" : "VPCPrefix"}, "101", "0/24"] ]}
17
+ }
18
+ },
19
+
20
+ "PublicSubnetARouteTableAssociation" : {
21
+ "Type" : "AWS::EC2::SubnetRouteTableAssociation",
22
+ "Properties" : {
23
+ "SubnetId" : { "Ref" : "PublicASubnet" },
24
+ "RouteTableId" : { "Ref" : "PublicRouteTable" }
25
+ }
26
+ },
27
+
28
+ "PrivateSubnetARouteTableAssociation" : {
29
+ "Type" : "AWS::EC2::SubnetRouteTableAssociation",
30
+ "Properties" : {
31
+ "SubnetId" : { "Ref" : "PrivateASubnet" },
32
+ "RouteTableId" : { "Ref" : "PrivateRouteTable" }
33
+ }
34
+ }
35
+ }
@@ -0,0 +1,11 @@
1
+ { "VPC" : {
2
+ "Type" : "AWS::EC2::VPC",
3
+ "Properties" : {
4
+ "CidrBlock" : {"Fn::Join" : [ ".", [{"Ref" : "VPCPrefix"}, "0.0/16"] ]},
5
+ "Tags" : [
6
+ {"Key" : "Application", "Value" : { "Ref" : "AWS::StackName"} },
7
+ {"Key" : "Network", "Value" : "Public" }
8
+ ]
9
+ }
10
+ }
11
+ }
@@ -0,0 +1,141 @@
1
+ require "aws/cfn/compiler/version"
2
+
3
+ require 'json'
4
+ require 'ap'
5
+ require 'yaml'
6
+ require 'slop'
7
+
8
+ module Aws
9
+ module Cfn
10
+ module Compiler
11
+ class Main
12
+ attr_accessor :items
13
+ attr_accessor :opts
14
+
15
+ def initialize
16
+ @items = {}
17
+ end
18
+
19
+ def run ()
20
+
21
+ @opts = Slop.parse(help: true) do
22
+ on :d, :directory=, 'The directory to look in', as: String
23
+ on :o, :output=, 'The JSON file to output', as: String
24
+ end
25
+
26
+ unless @opts[:directory]
27
+ puts @opts
28
+ exit
29
+ end
30
+
31
+ load
32
+
33
+ compiled = {
34
+ AWSTemplateFormatVersion: "2010-09-09",
35
+ Description: "Description goes here",
36
+ Parameters: @items['params'],
37
+ Mappings: @items['mappings'],
38
+ Resources: @items['resources'],
39
+ Outputs: @items['outputs'],
40
+ }
41
+
42
+ output_file = @opts[:output] || "compiled.json"
43
+ puts
44
+ puts "Writing compiled file to #{output_file}..."
45
+ save(compiled, output_file)
46
+
47
+ puts
48
+ puts "Validating compiled file..."
49
+
50
+ validate(compiled)
51
+
52
+ puts
53
+ puts "*** Compiled Successfully ***"
54
+ end
55
+
56
+ def validate(compiled)
57
+ names = compiled["Resources"].keys + compiled["Parameters"].keys
58
+ refs = find_refs(compiled).select { |a| !(a =~ /^AWS::/) }
59
+
60
+ unless (refs-names).empty?
61
+ puts "!!! Unknown references !!!"
62
+ (refs-names).each do |name|
63
+ puts " #{name}"
64
+ end
65
+ abort!
66
+ end
67
+ puts " References validated"
68
+ end
69
+
70
+ def save(compiled, output_file)
71
+ begin
72
+ File.open output_file, 'w' do |f|
73
+ f.write JSON.pretty_generate(compiled)
74
+ end
75
+ puts " Compiled file written."
76
+ rescue
77
+ puts "!!! Could not write compiled file: #{$!}"
78
+ abort!
79
+ end
80
+ end
81
+
82
+ def load
83
+ %w{params mappings resources outputs}.each do |dir|
84
+ load_dir(dir)
85
+ end
86
+ end
87
+
88
+ protected
89
+
90
+ def abort!
91
+ puts "!!! Aborting !!!"
92
+ exit
93
+ end
94
+
95
+ def find_refs(hash)
96
+ if hash.is_a? Hash
97
+ tr = []
98
+ hash.keys.collect do |key|
99
+ if %w{Ref SourceSecurityGroupName CacheSecurityGroupNames SecurityGroupNames}.include? key
100
+ hash[key]
101
+ elsif "Fn::GetAtt" == key
102
+ hash[key].first
103
+ else
104
+ find_refs(hash[key])
105
+ end
106
+ end.flatten.compact.uniq
107
+ elsif hash.is_a? Array
108
+ hash.collect{|a| find_refs(a)}.flatten.compact.uniq
109
+ end
110
+ end
111
+
112
+ def load_dir(dir)
113
+ puts "Loading #{dir}..."
114
+ @items[dir] = {}
115
+ (Dir[File.join(@opts[:directory], "#{dir}.*")] | Dir[File.join(@opts[:directory], dir, "**", "*")]).collect do |filename|
116
+ next unless filename =~ /\.(json|ya?ml)\z/i
117
+ begin
118
+ puts " reading #{filename}"
119
+ content = File.read(filename)
120
+ next if content.size==0
121
+
122
+ if filename =~ /\.json\z/i
123
+ item = JSON.parse(content)
124
+ elsif filename =~ /\.ya?ml\z/i
125
+ item = YAML.load(content)
126
+ else
127
+ next
128
+ end
129
+ item.keys.each { |key| raise "Duplicate item: #{key}" if @items[dir].has_key?(key) }
130
+ @items[dir].merge! item
131
+ rescue
132
+ puts " !! error: #{$!}"
133
+ abort!
134
+ end
135
+ end
136
+ end
137
+
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,7 @@
1
+ module Aws
2
+ module Cfn
3
+ module Compiler
4
+ VERSION = "0.0.3"
5
+ end
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,158 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: aws-cfn-compiler
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - PKinney
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-06-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: awesome_print
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: slop
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: psych
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: json
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.6'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.6'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: The idea is to create a folder structure to better manage pieces of a
98
+ CloudFormation deployment. Additionally, writing in JSON is hard, so the compiler
99
+ takes YAML files as well.
100
+ email:
101
+ - pkinney@github.com
102
+ executables:
103
+ - cfn-compiler
104
+ extensions: []
105
+ extra_rdoc_files: []
106
+ files:
107
+ - ".gitignore"
108
+ - ".ruby-gemset"
109
+ - ".ruby-version"
110
+ - Gemfile
111
+ - LICENSE.txt
112
+ - README.md
113
+ - Rakefile
114
+ - aws-cfn-compiler.gemspec
115
+ - aws-cfn-compiler.iml
116
+ - bin/cfn-compiler
117
+ - example/mappings/alinux.json
118
+ - example/mappings/instance_types.json
119
+ - example/mappings/nat.json
120
+ - example/outputs.yml
121
+ - example/params.json
122
+ - example/resources/gateway.json
123
+ - example/resources/instances/app.yml
124
+ - example/resources/instances/bastion.json
125
+ - example/resources/instances/nat.json
126
+ - example/resources/route53.json
127
+ - example/resources/routing.json
128
+ - example/resources/security_groups.json
129
+ - example/resources/subnets.json
130
+ - example/resources/vpc.json
131
+ - lib/aws/cfn/compiler.rb
132
+ - lib/aws/cfn/compiler/version.rb
133
+ homepage: https://github.com/dldinternet/aws-cfn-compiler
134
+ licenses:
135
+ - MIT
136
+ metadata: {}
137
+ post_install_message:
138
+ rdoc_options: []
139
+ require_paths:
140
+ - lib
141
+ required_ruby_version: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ required_rubygems_version: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ requirements: []
152
+ rubyforge_project:
153
+ rubygems_version: 2.2.2
154
+ signing_key:
155
+ specification_version: 4
156
+ summary: A simple script to compile and perform some validation for CloudFormation
157
+ scripts.
158
+ test_files: []