chemtrail 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +7 -1
- data/examples/lib/templates/config/load_balancer.yml +1 -0
- data/examples/lib/templates/config/opsworks.yml +1 -0
- data/examples/lib/templates/config/private_network.yml +4 -1
- data/examples/lib/templates/config/stack.yml +0 -1
- data/examples/lib/templates/opsworks_vpc/nat_device.rb +1 -1
- data/examples/lib/templates/opsworks_vpc/private_network.rb +3 -3
- data/examples/lib/templates/opsworks_vpc/public_network.rb +4 -4
- data/examples/lib/templates/opsworks_vpc/public_network_acl.rb +1 -1
- data/examples/lib/templates/opsworks_vpc_template.rb +5 -5
- data/examples/spec/integration/parity_spec.rb +12 -0
- data/examples/spec/lib/templates/opsworks_vpc/nat_device_spec.rb +1 -1
- data/examples/spec/lib/templates/opsworks_vpc/public_network_spec.rb +5 -0
- data/examples/spec/spec_helper.rb +1 -0
- data/examples/spec/support/OpsWorksinVPC.template +394 -0
- data/lib/chemtrail/cli.rb +25 -3
- data/lib/chemtrail/version.rb +1 -1
- data/spec/lib/chemtrail/cli_spec.rb +33 -1
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9cea4ac78802e46bcfa27fd2d3ce436f104dbd89
|
4
|
+
data.tar.gz: 35c9eeaf91b64f21d96299b1833a968176ce7c92
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1554bfd2d565f01113e4c2461320d74994dfd1a65afdcc2b6a41edb5545d78b04ea1fdb649cc84a568296341cb5f6e6d9521d15da6ab55472e9bbcc31aa91a0
|
7
|
+
data.tar.gz: bd66df7c9d4448ce81e6e12d7d8771072a2374bb9a74bcd84c52aa61c8c897c84e3f813deac044025c926ccb181e8ef8e2302441f001d5a9414d4fc7ede1af99
|
data/README.md
CHANGED
@@ -33,7 +33,9 @@ Or install it yourself as:
|
|
33
33
|
Usage
|
34
34
|
-----
|
35
35
|
|
36
|
-
See the `examples/` directory for
|
36
|
+
See the `examples/` directory for an example of test-driving the
|
37
|
+
[OpsWorks VPC](http://docs.aws.amazon.com/opsworks/latest/userguide/workingstacks-vpc.html)
|
38
|
+
CloudFormation template.
|
37
39
|
|
38
40
|
Listing all available templates in `lib/templates`:
|
39
41
|
|
@@ -47,6 +49,10 @@ Building a template:
|
|
47
49
|
|
48
50
|
$ chemtrail build crazy:cat:pants
|
49
51
|
|
52
|
+
Validating a template with Amazon (note that you will need to set the environment variables `AWS_REGION`, `AWS_ACCESS_KEY_ID` and `AWS_SECRET_KEY`):
|
53
|
+
|
54
|
+
$ chemtrail validate tangy:socks
|
55
|
+
|
50
56
|
|
51
57
|
Contributing
|
52
58
|
------------
|
@@ -25,14 +25,14 @@ module OpsworksVpc
|
|
25
25
|
@subnet ||= Chemtrail::Resource.new("PrivateSubnet", "AWS::EC2::Subnet", resources_config["PrivateSubnet"]).tap do |config|
|
26
26
|
config.properties["VpcId"] = vpc
|
27
27
|
config.properties["CidrBlock"] = subnet_config.find("Private", "CIDR")
|
28
|
-
config.properties["Tags"]
|
28
|
+
config.properties["Tags"].unshift(stack_name.as_tag("Application"))
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
32
|
def route_table
|
33
33
|
@route_table ||= Chemtrail::Resource.new("PrivateRouteTable", "AWS::EC2::RouteTable", resources_config["PrivateRouteTable"]).tap do |config|
|
34
34
|
config.properties["VpcId"] = vpc
|
35
|
-
config.properties["Tags"]
|
35
|
+
config.properties["Tags"].unshift(stack_name.as_tag("Application"))
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
@@ -53,7 +53,7 @@ module OpsworksVpc
|
|
53
53
|
def network_acl
|
54
54
|
@network_acl ||= Chemtrail::Resource.new("PrivateNetworkAcl", "AWS::EC2::NetworkAcl", resources_config["PrivateNetworkAcl"]).tap do |config|
|
55
55
|
config.properties["VpcId"] = vpc
|
56
|
-
config.properties["Tags"]
|
56
|
+
config.properties["Tags"].unshift(stack_name.as_tag("Application"))
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
@@ -24,13 +24,13 @@ module OpsworksVpc
|
|
24
24
|
@subnet ||= Chemtrail::Resource.new("PublicSubnet", "AWS::EC2::Subnet", resources_config["PublicSubnet"]).tap do |config|
|
25
25
|
config.properties["VpcId"] = vpc
|
26
26
|
config.properties["CidrBlock"] = subnet_config.find("Public", "CIDR")
|
27
|
-
config.properties["Tags"]
|
27
|
+
config.properties["Tags"].unshift(stack_name.as_tag("Application"))
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
31
|
def internet_gateway
|
32
32
|
@internet_gateway ||= Chemtrail::Resource.new("InternetGateway", "AWS::EC2::InternetGateway", resources_config["InternetGateway"]).tap do |config|
|
33
|
-
config.properties["Tags"]
|
33
|
+
config.properties["Tags"].unshift(stack_name.as_tag("Application"))
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
@@ -44,14 +44,14 @@ module OpsworksVpc
|
|
44
44
|
def route_table
|
45
45
|
@route_table ||= Chemtrail::Resource.new("PublicRouteTable", "AWS::EC2::RouteTable", resources_config["PublicRouteTable"]).tap do |config|
|
46
46
|
config.properties["VpcId"] = vpc
|
47
|
-
config.properties["Tags"]
|
47
|
+
config.properties["Tags"].unshift(stack_name.as_tag("Application"))
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
51
|
def route
|
52
52
|
@route ||= Chemtrail::Resource.new("PublicRoute", "AWS::EC2::Route", resources_config["PublicRoute"]).tap do |config|
|
53
53
|
config.properties["RouteTableId"] = route_table
|
54
|
-
config.properties["GatewayId"] =
|
54
|
+
config.properties["GatewayId"] = internet_gateway
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
@@ -22,7 +22,7 @@ module OpsworksVpc
|
|
22
22
|
def network_acl
|
23
23
|
@network_acl ||= Chemtrail::Resource.new("PublicNetworkAcl", "AWS::EC2::NetworkAcl", resources_config["PublicNetworkAcl"]).tap do |config|
|
24
24
|
config.properties["VpcId"] = vpc
|
25
|
-
config.properties["Tags"]
|
25
|
+
config.properties["Tags"].unshift(stack_name.as_tag("Application"))
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
@@ -34,10 +34,10 @@ module OpsworksVpc
|
|
34
34
|
|
35
35
|
def outputs
|
36
36
|
[
|
37
|
-
Chemtrail::Output.new("VPC", vpc),
|
38
|
-
Chemtrail::Output.new("PrivateSubnets", private_network.subnet),
|
39
|
-
Chemtrail::Output.new("PublicSubnets", public_network.subnet),
|
40
|
-
Chemtrail::Output.new("LoadBalancer", load_balancer.elb),
|
37
|
+
Chemtrail::Output.new("VPC", vpc, "VPC"),
|
38
|
+
Chemtrail::Output.new("PrivateSubnets", private_network.subnet, "Private Subnet"),
|
39
|
+
Chemtrail::Output.new("PublicSubnets", public_network.subnet, "Public Subnet"),
|
40
|
+
Chemtrail::Output.new("LoadBalancer", load_balancer.elb, "Load Balancer"),
|
41
41
|
]
|
42
42
|
end
|
43
43
|
|
@@ -56,7 +56,7 @@ module OpsworksVpc
|
|
56
56
|
def vpc
|
57
57
|
@vpc ||= Chemtrail::Resource.new("VPC", "AWS::EC2::VPC", stack_config["VPC"]).tap do |config|
|
58
58
|
config.properties["CidrBlock"] = subnet_config.find("VPC", "CIDR")
|
59
|
-
config.properties["Tags"]
|
59
|
+
config.properties["Tags"].unshift(stack_name.as_tag("Application"))
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "parity with cloudformation" do
|
4
|
+
let(:template_path) { File.expand_path("../../support/OpsWorksinVPC.template", __FILE__) }
|
5
|
+
let(:template_contents) { File.read(template_path) }
|
6
|
+
let(:template) { JSON.parse(template_contents) }
|
7
|
+
let(:generated) { OpsworksVpc::Stack.new.to_hash }
|
8
|
+
|
9
|
+
it "maintains parity with cloudformation" do
|
10
|
+
template.should == generated
|
11
|
+
end
|
12
|
+
end
|
@@ -27,6 +27,11 @@ describe OpsworksVpc::PublicNetwork do
|
|
27
27
|
its(:gateway_to_internet) { should have_property("InternetGatewayId").with_reference("InternetGateway") }
|
28
28
|
end
|
29
29
|
|
30
|
+
describe "PublicRoute" do
|
31
|
+
its(:route) { should have_property("RouteTableId").with_reference("PublicRouteTable") }
|
32
|
+
its(:route) { should have_property("GatewayId").with_reference("InternetGateway") }
|
33
|
+
end
|
34
|
+
|
30
35
|
describe "PublicRouteTable" do
|
31
36
|
its(:route_table) { should have_property("VpcId").with_reference("VPC") }
|
32
37
|
its(:route_table) { should have_tag("Application").with_reference("AWS::StackName") }
|
@@ -0,0 +1,394 @@
|
|
1
|
+
{
|
2
|
+
"AWSTemplateFormatVersion" : "2010-09-09",
|
3
|
+
|
4
|
+
"Description" : "Sample template showing how to create a VPC environment for AWS OpsWorks. The stack contains 2 subnets: the first subnet is public and contains the load balancer, a NAT device for internet access from the private subnet. The second subnet is private. You will be billed for the AWS resources used if you create a stack from this template.",
|
5
|
+
|
6
|
+
"Parameters" : {
|
7
|
+
|
8
|
+
"NATInstanceType" : {
|
9
|
+
"Description" : "NAT Device EC2 instance type",
|
10
|
+
"Type" : "String",
|
11
|
+
"Default" : "m1.small",
|
12
|
+
"AllowedValues" : [ "t1.micro","m1.small","m1.medium","m1.large","m1.xlarge","m2.xlarge","m2.2xlarge","m2.4xlarge","c1.medium","c1.xlarge","cc1.4xlarge","cc2.8xlarge","cg1.4xlarge"],
|
13
|
+
"ConstraintDescription" : "must be a valid EC2 instance type."
|
14
|
+
}
|
15
|
+
},
|
16
|
+
|
17
|
+
"Mappings" : {
|
18
|
+
"AWSNATAMI" : {
|
19
|
+
"us-east-1" : { "AMI" : "ami-c6699baf" },
|
20
|
+
"us-west-2" : { "AMI" : "ami-52ff7262" },
|
21
|
+
"us-west-1" : { "AMI" : "ami-3bcc9e7e" },
|
22
|
+
"eu-west-1" : { "AMI" : "ami-0b5b6c7f" },
|
23
|
+
"ap-southeast-1" : { "AMI" : "ami-02eb9350" },
|
24
|
+
"ap-southeast-2" : { "AMI" : "ami-ab990e91" },
|
25
|
+
"ap-northeast-1" : { "AMI" : "ami-14d86d15" },
|
26
|
+
"sa-east-1" : { "AMI" : "ami-0439e619" }
|
27
|
+
},
|
28
|
+
|
29
|
+
"AWSInstanceType2Arch" : {
|
30
|
+
"t1.micro" : { "Arch" : "64" },
|
31
|
+
"m1.small" : { "Arch" : "64" },
|
32
|
+
"m1.medium" : { "Arch" : "64" },
|
33
|
+
"m1.large" : { "Arch" : "64" },
|
34
|
+
"m1.xlarge" : { "Arch" : "64" },
|
35
|
+
"m2.xlarge" : { "Arch" : "64" },
|
36
|
+
"m2.2xlarge" : { "Arch" : "64" },
|
37
|
+
"m2.4xlarge" : { "Arch" : "64" },
|
38
|
+
"c1.medium" : { "Arch" : "64" },
|
39
|
+
"c1.xlarge" : { "Arch" : "64" },
|
40
|
+
"cc1.4xlarge" : { "Arch" : "64Cluster" },
|
41
|
+
"cc2.8xlarge" : { "Arch" : "64Cluster" },
|
42
|
+
"cg1.4xlarge" : { "Arch" : "64GPU" }
|
43
|
+
},
|
44
|
+
|
45
|
+
"SubnetConfig" : {
|
46
|
+
"VPC" : { "CIDR" : "10.0.0.0/16" },
|
47
|
+
"Public" : { "CIDR" : "10.0.0.0/24" },
|
48
|
+
"Private" : { "CIDR" : "10.0.1.0/24" }
|
49
|
+
}
|
50
|
+
},
|
51
|
+
|
52
|
+
"Resources" : {
|
53
|
+
|
54
|
+
"VPC" : {
|
55
|
+
"Type" : "AWS::EC2::VPC",
|
56
|
+
"Properties" : {
|
57
|
+
"CidrBlock" : { "Fn::FindInMap" : [ "SubnetConfig", "VPC", "CIDR" ]},
|
58
|
+
"Tags" : [
|
59
|
+
{ "Key" : "Application", "Value" : { "Ref" : "AWS::StackName" } },
|
60
|
+
{ "Key" : "Network", "Value" : "Public" }
|
61
|
+
]
|
62
|
+
}
|
63
|
+
},
|
64
|
+
|
65
|
+
"PublicSubnet" : {
|
66
|
+
"Type" : "AWS::EC2::Subnet",
|
67
|
+
"Properties" : {
|
68
|
+
"VpcId" : { "Ref" : "VPC" },
|
69
|
+
"CidrBlock" : { "Fn::FindInMap" : [ "SubnetConfig", "Public", "CIDR" ]},
|
70
|
+
"Tags" : [
|
71
|
+
{ "Key" : "Application", "Value" : { "Ref" : "AWS::StackName" } },
|
72
|
+
{ "Key" : "Network", "Value" : "Public" }
|
73
|
+
]
|
74
|
+
}
|
75
|
+
},
|
76
|
+
|
77
|
+
"InternetGateway" : {
|
78
|
+
"Type" : "AWS::EC2::InternetGateway",
|
79
|
+
"Properties" : {
|
80
|
+
"Tags" : [
|
81
|
+
{ "Key" : "Application", "Value" : { "Ref" : "AWS::StackName" } },
|
82
|
+
{ "Key" : "Network", "Value" : "Public" }
|
83
|
+
]
|
84
|
+
}
|
85
|
+
},
|
86
|
+
|
87
|
+
"GatewayToInternet" : {
|
88
|
+
"Type" : "AWS::EC2::VPCGatewayAttachment",
|
89
|
+
"Properties" : {
|
90
|
+
"VpcId" : { "Ref" : "VPC" },
|
91
|
+
"InternetGatewayId" : { "Ref" : "InternetGateway" }
|
92
|
+
}
|
93
|
+
},
|
94
|
+
|
95
|
+
"PublicRouteTable" : {
|
96
|
+
"Type" : "AWS::EC2::RouteTable",
|
97
|
+
"Properties" : {
|
98
|
+
"VpcId" : { "Ref" : "VPC" },
|
99
|
+
"Tags" : [
|
100
|
+
{ "Key" : "Application", "Value" : { "Ref" : "AWS::StackName" } },
|
101
|
+
{ "Key" : "Network", "Value" : "Public" }
|
102
|
+
]
|
103
|
+
}
|
104
|
+
},
|
105
|
+
|
106
|
+
"PublicRoute" : {
|
107
|
+
"Type" : "AWS::EC2::Route",
|
108
|
+
"Properties" : {
|
109
|
+
"RouteTableId" : { "Ref" : "PublicRouteTable" },
|
110
|
+
"DestinationCidrBlock" : "0.0.0.0/0",
|
111
|
+
"GatewayId" : { "Ref" : "InternetGateway" }
|
112
|
+
}
|
113
|
+
},
|
114
|
+
|
115
|
+
"PublicSubnetRouteTableAssociation" : {
|
116
|
+
"Type" : "AWS::EC2::SubnetRouteTableAssociation",
|
117
|
+
"Properties" : {
|
118
|
+
"SubnetId" : { "Ref" : "PublicSubnet" },
|
119
|
+
"RouteTableId" : { "Ref" : "PublicRouteTable" }
|
120
|
+
}
|
121
|
+
},
|
122
|
+
|
123
|
+
"PublicNetworkAcl" : {
|
124
|
+
"Type" : "AWS::EC2::NetworkAcl",
|
125
|
+
"Properties" : {
|
126
|
+
"VpcId" : { "Ref" : "VPC" },
|
127
|
+
"Tags" : [
|
128
|
+
{ "Key" : "Application", "Value" : { "Ref" : "AWS::StackName" } },
|
129
|
+
{ "Key" : "Network", "Value" : "Public" }
|
130
|
+
]
|
131
|
+
}
|
132
|
+
},
|
133
|
+
|
134
|
+
"InboundHTTPPublicNetworkAclEntry" : {
|
135
|
+
"Type" : "AWS::EC2::NetworkAclEntry",
|
136
|
+
"Properties" : {
|
137
|
+
"NetworkAclId" : { "Ref" : "PublicNetworkAcl" },
|
138
|
+
"RuleNumber" : "100",
|
139
|
+
"Protocol" : "6",
|
140
|
+
"RuleAction" : "allow",
|
141
|
+
"Egress" : "false",
|
142
|
+
"CidrBlock" : "0.0.0.0/0",
|
143
|
+
"PortRange" : { "From" : "80", "To" : "80" }
|
144
|
+
}
|
145
|
+
},
|
146
|
+
|
147
|
+
"InboundHTTPSPublicNetworkAclEntry" : {
|
148
|
+
"Type" : "AWS::EC2::NetworkAclEntry",
|
149
|
+
"Properties" : {
|
150
|
+
"NetworkAclId" : { "Ref" : "PublicNetworkAcl" },
|
151
|
+
"RuleNumber" : "101",
|
152
|
+
"Protocol" : "6",
|
153
|
+
"RuleAction" : "allow",
|
154
|
+
"Egress" : "false",
|
155
|
+
"CidrBlock" : "0.0.0.0/0",
|
156
|
+
"PortRange" : { "From" : "443", "To" : "443" }
|
157
|
+
}
|
158
|
+
},
|
159
|
+
|
160
|
+
"InboundSSHPublicNetworkAclEntry" : {
|
161
|
+
"Type" : "AWS::EC2::NetworkAclEntry",
|
162
|
+
"Properties" : {
|
163
|
+
"NetworkAclId" : { "Ref" : "PublicNetworkAcl" },
|
164
|
+
"RuleNumber" : "102",
|
165
|
+
"Protocol" : "6",
|
166
|
+
"RuleAction" : "allow",
|
167
|
+
"Egress" : "false",
|
168
|
+
"CidrBlock" : "0.0.0.0/0",
|
169
|
+
"PortRange" : { "From" : "22", "To" : "22" }
|
170
|
+
}
|
171
|
+
},
|
172
|
+
|
173
|
+
"InboundEmphemeralPublicNetworkAclEntry" : {
|
174
|
+
"Type" : "AWS::EC2::NetworkAclEntry",
|
175
|
+
"Properties" : {
|
176
|
+
"NetworkAclId" : { "Ref" : "PublicNetworkAcl" },
|
177
|
+
"RuleNumber" : "103",
|
178
|
+
"Protocol" : "6",
|
179
|
+
"RuleAction" : "allow",
|
180
|
+
"Egress" : "false",
|
181
|
+
"CidrBlock" : "0.0.0.0/0",
|
182
|
+
"PortRange" : { "From" : "1024", "To" : "65535" }
|
183
|
+
}
|
184
|
+
},
|
185
|
+
|
186
|
+
"OutboundPublicNetworkAclEntry" : {
|
187
|
+
"Type" : "AWS::EC2::NetworkAclEntry",
|
188
|
+
"Properties" : {
|
189
|
+
"NetworkAclId" : { "Ref" : "PublicNetworkAcl" },
|
190
|
+
"RuleNumber" : "100",
|
191
|
+
"Protocol" : "6",
|
192
|
+
"RuleAction" : "allow",
|
193
|
+
"Egress" : "true",
|
194
|
+
"CidrBlock" : "0.0.0.0/0",
|
195
|
+
"PortRange" : { "From" : "0", "To" : "65535" }
|
196
|
+
}
|
197
|
+
},
|
198
|
+
|
199
|
+
"PublicSubnetNetworkAclAssociation" : {
|
200
|
+
"Type" : "AWS::EC2::SubnetNetworkAclAssociation",
|
201
|
+
"Properties" : {
|
202
|
+
"SubnetId" : { "Ref" : "PublicSubnet" },
|
203
|
+
"NetworkAclId" : { "Ref" : "PublicNetworkAcl" }
|
204
|
+
}
|
205
|
+
},
|
206
|
+
|
207
|
+
"PrivateSubnet" : {
|
208
|
+
"Type" : "AWS::EC2::Subnet",
|
209
|
+
"Properties" : {
|
210
|
+
"VpcId" : { "Ref" : "VPC" },
|
211
|
+
"CidrBlock" : { "Fn::FindInMap" : [ "SubnetConfig", "Private", "CIDR" ]},
|
212
|
+
"Tags" : [
|
213
|
+
{ "Key" : "Application", "Value" : { "Ref" : "AWS::StackName" } },
|
214
|
+
{ "Key" : "Name", "Value" : "Private" }
|
215
|
+
]
|
216
|
+
}
|
217
|
+
},
|
218
|
+
|
219
|
+
"PrivateRouteTable" : {
|
220
|
+
"Type" : "AWS::EC2::RouteTable",
|
221
|
+
"Properties" : {
|
222
|
+
"VpcId" : { "Ref" : "VPC" },
|
223
|
+
"Tags" : [
|
224
|
+
{ "Key" : "Application", "Value" : { "Ref" : "AWS::StackName" } },
|
225
|
+
{ "Key" : "Network", "Value" : "Private" }
|
226
|
+
]
|
227
|
+
}
|
228
|
+
},
|
229
|
+
|
230
|
+
"PrivateSubnetRouteTableAssociation" : {
|
231
|
+
"Type" : "AWS::EC2::SubnetRouteTableAssociation",
|
232
|
+
"Properties" : {
|
233
|
+
"SubnetId" : { "Ref" : "PrivateSubnet" },
|
234
|
+
"RouteTableId" : { "Ref" : "PrivateRouteTable" }
|
235
|
+
}
|
236
|
+
},
|
237
|
+
|
238
|
+
"PrivateRoute" : {
|
239
|
+
"Type" : "AWS::EC2::Route",
|
240
|
+
"Properties" : {
|
241
|
+
"RouteTableId" : { "Ref" : "PrivateRouteTable" },
|
242
|
+
"DestinationCidrBlock" : "0.0.0.0/0",
|
243
|
+
"InstanceId" : { "Ref" : "NATDevice" }
|
244
|
+
}
|
245
|
+
},
|
246
|
+
|
247
|
+
"PrivateNetworkAcl" : {
|
248
|
+
"Type" : "AWS::EC2::NetworkAcl",
|
249
|
+
"Properties" : {
|
250
|
+
"VpcId" : { "Ref" : "VPC" },
|
251
|
+
"Tags" : [
|
252
|
+
{ "Key" : "Application", "Value" : { "Ref" : "AWS::StackName" } },
|
253
|
+
{ "Key" : "Network", "Value" : "Private" }
|
254
|
+
]
|
255
|
+
}
|
256
|
+
},
|
257
|
+
|
258
|
+
"InboundPrivateNetworkAclEntry" : {
|
259
|
+
"Type" : "AWS::EC2::NetworkAclEntry",
|
260
|
+
"Properties" : {
|
261
|
+
"NetworkAclId" : { "Ref" : "PrivateNetworkAcl" },
|
262
|
+
"RuleNumber" : "100",
|
263
|
+
"Protocol" : "6",
|
264
|
+
"RuleAction" : "allow",
|
265
|
+
"Egress" : "false",
|
266
|
+
"CidrBlock" : "0.0.0.0/0",
|
267
|
+
"PortRange" : { "From" : "0", "To" : "65535" }
|
268
|
+
}
|
269
|
+
},
|
270
|
+
|
271
|
+
"OutBoundPrivateNetworkAclEntry" : {
|
272
|
+
"Type" : "AWS::EC2::NetworkAclEntry",
|
273
|
+
"Properties" : {
|
274
|
+
"NetworkAclId" : { "Ref" : "PrivateNetworkAcl" },
|
275
|
+
"RuleNumber" : "100",
|
276
|
+
"Protocol" : "6",
|
277
|
+
"RuleAction" : "allow",
|
278
|
+
"Egress" : "true",
|
279
|
+
"CidrBlock" : "0.0.0.0/0",
|
280
|
+
"PortRange" : { "From" : "0", "To" : "65535" }
|
281
|
+
}
|
282
|
+
},
|
283
|
+
|
284
|
+
"PrivateSubnetNetworkAclAssociation" : {
|
285
|
+
"Type" : "AWS::EC2::SubnetNetworkAclAssociation",
|
286
|
+
"Properties" : {
|
287
|
+
"SubnetId" : { "Ref" : "PrivateSubnet" },
|
288
|
+
"NetworkAclId" : { "Ref" : "PrivateNetworkAcl" }
|
289
|
+
}
|
290
|
+
},
|
291
|
+
|
292
|
+
"NATIPAddress" : {
|
293
|
+
"Type" : "AWS::EC2::EIP",
|
294
|
+
"Properties" : {
|
295
|
+
"Domain" : "vpc",
|
296
|
+
"InstanceId" : { "Ref" : "NATDevice" }
|
297
|
+
}
|
298
|
+
},
|
299
|
+
|
300
|
+
"NATDevice" : {
|
301
|
+
"Type" : "AWS::EC2::Instance",
|
302
|
+
"Properties" : {
|
303
|
+
"InstanceType" : { "Ref" : "NATInstanceType" },
|
304
|
+
"SubnetId" : { "Ref" : "PublicSubnet" },
|
305
|
+
"SourceDestCheck" : "false",
|
306
|
+
"ImageId" : { "Fn::FindInMap" : [ "AWSNATAMI", { "Ref" : "AWS::Region" }, "AMI" ]},
|
307
|
+
"SecurityGroupIds" : [{ "Ref" : "NATSecurityGroup" }]
|
308
|
+
}
|
309
|
+
},
|
310
|
+
|
311
|
+
"NATSecurityGroup" : {
|
312
|
+
"Type" : "AWS::EC2::SecurityGroup",
|
313
|
+
"Properties" : {
|
314
|
+
"GroupDescription" : "Enable internal access to the NAT device",
|
315
|
+
"VpcId" : { "Ref" : "VPC" },
|
316
|
+
"SecurityGroupIngress" : [
|
317
|
+
{ "IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "SourceSecurityGroupId" : { "Ref" : "OpsWorksSecurityGroup" }} ,
|
318
|
+
{ "IpProtocol" : "tcp", "FromPort" : "9418", "ToPort" : "9418", "SourceSecurityGroupId" : { "Ref" : "OpsWorksSecurityGroup" }} ,
|
319
|
+
{ "IpProtocol" : "tcp", "FromPort" : "443", "ToPort" : "443", "SourceSecurityGroupId" : { "Ref" : "OpsWorksSecurityGroup" } } ],
|
320
|
+
"SecurityGroupEgress" : [
|
321
|
+
{ "IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "CidrIp" : "0.0.0.0/0" } ,
|
322
|
+
{ "IpProtocol" : "tcp", "FromPort" : "9418", "ToPort" : "9418", "CidrIp" : "0.0.0.0/0" } ,
|
323
|
+
{ "IpProtocol" : "tcp", "FromPort" : "443", "ToPort" : "443", "CidrIp" : "0.0.0.0/0" } ]
|
324
|
+
}
|
325
|
+
},
|
326
|
+
|
327
|
+
|
328
|
+
"OpsWorksSecurityGroup" : {
|
329
|
+
"Type" : "AWS::EC2::SecurityGroup",
|
330
|
+
"Properties" : {
|
331
|
+
"GroupDescription" : "Allow the OpsWorks instances to access the NAT device",
|
332
|
+
"VpcId" : { "Ref" : "VPC" },
|
333
|
+
"SecurityGroupIngress" : [
|
334
|
+
{ "IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "SourceSecurityGroupId" : { "Ref" : "LoadBalancerSecurityGroup" }} ]
|
335
|
+
}
|
336
|
+
},
|
337
|
+
|
338
|
+
"ElasticLoadBalancer" : {
|
339
|
+
"Type" : "AWS::ElasticLoadBalancing::LoadBalancer",
|
340
|
+
"Properties" : {
|
341
|
+
"SecurityGroups" : [ { "Ref" : "LoadBalancerSecurityGroup" } ],
|
342
|
+
"Subnets" : [ { "Ref" : "PublicSubnet" } ],
|
343
|
+
"Listeners" : [ { "LoadBalancerPort" : "80", "InstancePort" : "80", "Protocol" : "HTTP" } ],
|
344
|
+
"HealthCheck" : {
|
345
|
+
"Target" : "HTTP:80/",
|
346
|
+
"HealthyThreshold" : "3",
|
347
|
+
"UnhealthyThreshold" : "5",
|
348
|
+
"Interval" : "90",
|
349
|
+
"Timeout" : "60"
|
350
|
+
}
|
351
|
+
}
|
352
|
+
},
|
353
|
+
|
354
|
+
"LoadBalancerSecurityGroup" : {
|
355
|
+
"Type" : "AWS::EC2::SecurityGroup",
|
356
|
+
"Properties" : {
|
357
|
+
"GroupDescription" : "Enable HTTP access on port 80",
|
358
|
+
"VpcId" : { "Ref" : "VPC" },
|
359
|
+
"SecurityGroupIngress" : [ { "IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "CidrIp" : "0.0.0.0/0" } ],
|
360
|
+
"SecurityGroupEgress" : [ { "IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "CidrIp" : "0.0.0.0/0"} ]
|
361
|
+
}
|
362
|
+
}
|
363
|
+
|
364
|
+
|
365
|
+
|
366
|
+
|
367
|
+
|
368
|
+
|
369
|
+
|
370
|
+
},
|
371
|
+
|
372
|
+
"Outputs" : {
|
373
|
+
|
374
|
+
"VPC" : {
|
375
|
+
"Description" : "VPC",
|
376
|
+
"Value" : {"Ref" : "VPC"}
|
377
|
+
},
|
378
|
+
|
379
|
+
"PublicSubnets" : {
|
380
|
+
"Description" : "Public Subnet",
|
381
|
+
"Value" : {"Ref" : "PublicSubnet" }
|
382
|
+
},
|
383
|
+
|
384
|
+
"PrivateSubnets" : {
|
385
|
+
"Description" : "Private Subnet",
|
386
|
+
"Value" : {"Ref" : "PrivateSubnet" }
|
387
|
+
},
|
388
|
+
|
389
|
+
"LoadBalancer" : {
|
390
|
+
"Description" : "Load Balancer",
|
391
|
+
"Value" : {"Ref" : "ElasticLoadBalancer" }
|
392
|
+
}
|
393
|
+
}
|
394
|
+
}
|
data/lib/chemtrail/cli.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
require "thor"
|
2
2
|
require "json"
|
3
3
|
require "chemtrail"
|
4
|
+
require "aws-sdk-core"
|
4
5
|
|
5
6
|
class Chemtrail::Cli < Thor
|
7
|
+
attr_writer :cloud_formation
|
8
|
+
|
6
9
|
default_task :list
|
7
10
|
|
8
11
|
desc "list", "Lists all available templates"
|
@@ -15,14 +18,33 @@ class Chemtrail::Cli < Thor
|
|
15
18
|
desc "build TEMPLATE", "Builds the selected template"
|
16
19
|
method_option :path, :default => File.expand_path("lib/templates")
|
17
20
|
def build(template_name)
|
18
|
-
|
19
|
-
template_class = fetch_template_class_named(template_name)
|
20
|
-
template_json = JSON.pretty_generate(template_class.new.to_hash)
|
21
|
+
template_json = extract_template_json(template_name, options[:path])
|
21
22
|
Kernel.puts(template_json)
|
22
23
|
end
|
23
24
|
|
25
|
+
desc "validate TEMPLATE", "Validates the selected template with AWS"
|
26
|
+
method_option :path, :default => File.expand_path("lib/templates")
|
27
|
+
def validate(template_name)
|
28
|
+
template_json = extract_template_json(template_name, options[:path])
|
29
|
+
cloud_formation.validate_template(template_body: template_json)
|
30
|
+
Kernel.puts("Template #{template_name} is valid")
|
31
|
+
rescue Aws::CloudFormation::Errors::ValidationError => e
|
32
|
+
raise Thor::Error.new(e)
|
33
|
+
end
|
34
|
+
|
24
35
|
protected
|
25
36
|
|
37
|
+
def extract_template_json(template_name, template_path)
|
38
|
+
require_templates_from(template_path)
|
39
|
+
template_class = fetch_template_class_named(template_name)
|
40
|
+
template_instance = template_class.new
|
41
|
+
JSON.pretty_generate(template_instance.to_hash)
|
42
|
+
end
|
43
|
+
|
44
|
+
def cloud_formation
|
45
|
+
@cloud_formation ||= Aws::CloudFormation.new
|
46
|
+
end
|
47
|
+
|
26
48
|
def require_templates_from(path)
|
27
49
|
Dir.glob(File.expand_path("**/*_template.rb", path)).each { |t| require t }
|
28
50
|
end
|
data/lib/chemtrail/version.rb
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe Chemtrail::Cli do
|
4
|
+
let(:taco_json) { JSON.pretty_generate(Tacos.new.to_hash) }
|
5
|
+
let(:fake_cloud_formation) { double(:cloud_formation) }
|
6
|
+
|
4
7
|
subject(:cli) { Chemtrail::Cli.new }
|
5
8
|
|
9
|
+
before { cli.cloud_formation = fake_cloud_formation }
|
10
|
+
|
6
11
|
describe "#list" do
|
7
12
|
it "lists available templates" do
|
8
13
|
got_tacos = false
|
@@ -13,7 +18,7 @@ describe Chemtrail::Cli do
|
|
13
18
|
|
14
19
|
describe "#build" do
|
15
20
|
it "builds the specified template" do
|
16
|
-
Kernel.should_receive(:puts).with(
|
21
|
+
Kernel.should_receive(:puts).with(taco_json)
|
17
22
|
cli.build("tacos")
|
18
23
|
end
|
19
24
|
|
@@ -23,4 +28,31 @@ describe Chemtrail::Cli do
|
|
23
28
|
end
|
24
29
|
end
|
25
30
|
end
|
31
|
+
|
32
|
+
describe "#validate" do
|
33
|
+
before { Kernel.stub(:puts) }
|
34
|
+
|
35
|
+
it "validates verifies the specified template" do
|
36
|
+
fake_cloud_formation.should_receive(:validate_template).with(template_body: taco_json)
|
37
|
+
cli.validate("tacos")
|
38
|
+
end
|
39
|
+
|
40
|
+
context "when the template does not exist" do
|
41
|
+
it "blows up" do
|
42
|
+
expect { cli.build("an toenails") }.to raise_error(Thor::Error)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "when the template validation blows up" do
|
47
|
+
before do
|
48
|
+
fake_cloud_formation.stub(:validate_template) do
|
49
|
+
raise Aws::CloudFormation::Errors::ValidationError.new("ugh swans")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
it "blows up" do
|
54
|
+
expect { cli.build("sustainable hookahs") }.to raise_error(Thor::Error)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
26
58
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chemtrail
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Doc Ritezel
|
@@ -115,6 +115,7 @@ files:
|
|
115
115
|
- examples/lib/templates/opsworks_vpc/public_network.rb
|
116
116
|
- examples/lib/templates/opsworks_vpc/public_network_acl.rb
|
117
117
|
- examples/lib/templates/opsworks_vpc_template.rb
|
118
|
+
- examples/spec/integration/parity_spec.rb
|
118
119
|
- examples/spec/lib/templates/opsworks_vpc/load_balancer_spec.rb
|
119
120
|
- examples/spec/lib/templates/opsworks_vpc/nat_device_spec.rb
|
120
121
|
- examples/spec/lib/templates/opsworks_vpc/opsworks_spec.rb
|
@@ -123,6 +124,7 @@ files:
|
|
123
124
|
- examples/spec/lib/templates/opsworks_vpc/public_network_spec.rb
|
124
125
|
- examples/spec/lib/templates/opsworks_vpc_template_spec.rb
|
125
126
|
- examples/spec/spec_helper.rb
|
127
|
+
- examples/spec/support/OpsWorksinVPC.template
|
126
128
|
- lib/chemtrail.rb
|
127
129
|
- lib/chemtrail/class_name_inflector.rb
|
128
130
|
- lib/chemtrail/cli.rb
|