convection 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rubocop.yml +16 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE +23 -0
  6. data/README.md +224 -0
  7. data/Rakefile +2 -0
  8. data/Thorfile +5 -0
  9. data/convection.gemspec +27 -0
  10. data/example/iam_role.rb +63 -0
  11. data/example/s3.rb +13 -0
  12. data/example/vpc.rb +85 -0
  13. data/lib/convection.rb +18 -0
  14. data/lib/convection/control/stack.rb +165 -0
  15. data/lib/convection/dsl/helpers.rb +15 -0
  16. data/lib/convection/dsl/intrinsic_functions.rb +79 -0
  17. data/lib/convection/model/mixin/cidr_block.rb +17 -0
  18. data/lib/convection/model/mixin/conditional.rb +21 -0
  19. data/lib/convection/model/mixin/taggable.rb +48 -0
  20. data/lib/convection/model/template.rb +127 -0
  21. data/lib/convection/model/template/mapping.rb +42 -0
  22. data/lib/convection/model/template/output.rb +37 -0
  23. data/lib/convection/model/template/parameter.rb +44 -0
  24. data/lib/convection/model/template/resource.rb +64 -0
  25. data/lib/convection/model/template/resource/aws_ec2_instance.rb +69 -0
  26. data/lib/convection/model/template/resource/aws_ec2_internet_gateway.rb +55 -0
  27. data/lib/convection/model/template/resource/aws_ec2_route.rb +55 -0
  28. data/lib/convection/model/template/resource/aws_ec2_route_table.rb +60 -0
  29. data/lib/convection/model/template/resource/aws_ec2_security_group.rb +104 -0
  30. data/lib/convection/model/template/resource/aws_ec2_subnet.rb +66 -0
  31. data/lib/convection/model/template/resource/aws_ec2_subnet_route_table_association.rb +39 -0
  32. data/lib/convection/model/template/resource/aws_ec2_vpc.rb +116 -0
  33. data/lib/convection/model/template/resource/aws_ec2_vpc_gateway_attachment.rb +43 -0
  34. data/lib/convection/model/template/resource/aws_iam_policy.rb +45 -0
  35. data/lib/convection/model/template/resource/aws_iam_role.rb +45 -0
  36. data/lib/convection/model/template/resource/aws_s3_bucket.rb +67 -0
  37. data/lib/convection/model/template/resource/aws_s3_bucket_policy.rb +40 -0
  38. data/lib/convection/version.rb +6 -0
  39. metadata +375 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c0e40b87f41fe55c9ae72164fb2f4bfd6a65b7e6
4
+ data.tar.gz: 6c2136c2a50025cbc8ab781362717afbd919bde4
5
+ SHA512:
6
+ metadata.gz: 73e16b10a0ff8accc52f4f50840ce91638d28e83df66b258b6b577f7955733aa471c621054eabd272ac2d62f3dfee6d9c28f4e2494f3cdc948341f7d31f02cf1
7
+ data.tar.gz: 6170446d0c4ccd1cc348b596529c11917017323df2c25f8983f2ea598f3ccc05fed5c37797c4bb1db90bb457096a43bd46b3008de09ef0fb588d88b21d032c46
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+
16
+ keys
17
+ VERSION
data/.rubocop.yml ADDED
@@ -0,0 +1,16 @@
1
+ AllCops:
2
+ Exclude:
3
+ - libraries/**/*
4
+ - spec/**/*
5
+ - metadata.rb
6
+
7
+ Encoding:
8
+ Enabled: false
9
+ LineLength:
10
+ Enabled: false
11
+ HashSyntax:
12
+ Enabled: false
13
+ RescueModifier:
14
+ Enabled: false
15
+ MethodLength:
16
+ Max: 24
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in convection.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2015 John Manero, Rapid7 LLC.
2
+
3
+ MIT License
4
+ ===========
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining
7
+ a copy of this software and associated documentation files (the
8
+ "Software"), to deal in the Software without restriction, including
9
+ without limitation the rights to use, copy, modify, merge, publish,
10
+ distribute, sublicense, and/or sell copies of the Software, and to
11
+ permit persons to whom the Software is furnished to do so, subject to
12
+ the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,224 @@
1
+ # Convection
2
+ _A fully generic, modular DSL for AWS CloudFormation_
3
+
4
+ This gem aims to provide a reusable model for AWS CloudFormation in Ruby. It exposes a DSL for template definition, and a simple, decoupled abstraction of a CloudFormation Stack to compile and apply templates.
5
+
6
+ ## Version 0.0.1
7
+ This is an Alpha release. It is still lacking functionality and testing. We plan to develop/improve features as we begin to use it for our own deployments in the coming months. PRs welcome.
8
+
9
+ ## Installation
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+ gem 'convection'
14
+ ```
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install convection
23
+
24
+ ## Template DSL
25
+ The core DSL provides all of the available JSON primatives of CloudFormation in the form of ruby methods. These primatives are used to compose higher-order methods for commonly used definitions:
26
+
27
+ ```ruby
28
+ require 'convection'
29
+
30
+ ## Create a new instance of Convection::Model::Template
31
+ Convection.template do
32
+ description 'An example template'
33
+
34
+ parameter 'InstanceSize' do
35
+ type 'String'
36
+ description 'Instance Size'
37
+ default 'm3.medium'
38
+
39
+ allow 'm3.medium'
40
+ allow 'm3.large'
41
+ allow 'm3.xlarge'
42
+ end
43
+
44
+ ## The `resource` method can be used to define any resource
45
+ ## supported by CloudFormation: See http://docs.aws.amazon.com/\
46
+ ## AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html
47
+ resource 'AnEC2Instance' do
48
+ type 'AWS::EC2::Instance'
49
+ property 'AvailabilityZone', 'us-east-1a'
50
+ property 'ImageId', 'ami-76e27e1e' ## Ubuntu 14.04 hvm:ebs
51
+ property 'KeyName', 'test'
52
+ property 'SecurityGroupIds', ['sg-dd733c41', 'sg-dd738df3']
53
+ property 'Tags', [{
54
+ 'Key' => 'Name',
55
+ 'Value' => 'test-1'
56
+ }]
57
+
58
+ property 'DisableApiTermination', false
59
+ end
60
+
61
+ ## `ec2_instnce` extends `resource`. The following results in JSON
62
+ ## identical to that of Resource[AnEC2Instance]
63
+ ec2_instance 'AnOtherInstance' do
64
+ availability_zone 'us-east-1a'
65
+ image_id 'ami-76e27e1e'
66
+ key_name 'test'
67
+
68
+ security_group 'sg-dd733c41'
69
+ security_group 'sg-dd738df3'
70
+
71
+ tag 'Name', 'test-2'
72
+
73
+ ## All of the methods of the `resource` primative are available in
74
+ ## its children:
75
+ property 'DisableApiTermination', false
76
+ end
77
+ end.to_json
78
+ ```
79
+
80
+ ### Parameters
81
+ http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html
82
+
83
+ ```ruby
84
+ parameter 'InstanceType' do
85
+ type 'String'
86
+ description 'Set the thing\'s instance flavor'
87
+ default 'm3.medium'
88
+
89
+ allow 'm3.medium'
90
+ allow 'm3.large'
91
+ allow 'm3.xlarge'
92
+ end
93
+ ```
94
+
95
+ ### Mappings
96
+ http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/mappings-section-structure.html
97
+
98
+ ```ruby
99
+ mapping 'RegionalAMIs' do
100
+ item 'us-east-1', 'hvm', 'ami-76e27e1e'
101
+ item 'us-west-1', 'hvm', 'ami-d5180890'
102
+ item 'us-east-1', 'pv', 'ami-64e27e0c'
103
+ item 'us-west-1', 'pv', 'ami-c5180880'
104
+ end
105
+ ```
106
+
107
+ ### Conditions
108
+ http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/conditions-section-structure.html
109
+
110
+ Not implemented yet.
111
+
112
+ ### Resources
113
+ http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html
114
+
115
+ ```ruby
116
+ resource 'AnInstance' do
117
+ type 'AWS::EC2::Instance'
118
+
119
+ ## Optional condition reference
120
+ condition 'SomeCondition'
121
+
122
+ ## Add Resource Properties
123
+ property 'AvailabilityZone', 'us-east-1a'
124
+ property 'ImageId', 'ami-76e27e1e' ## Ubuntu 14.04 hvm:ebs
125
+ property 'KeyName', 'test'
126
+ ...
127
+ end
128
+ ```
129
+
130
+ ### Outputs
131
+ http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/outputs-section-structure.html
132
+
133
+ ```ruby
134
+ output 'SomeName' do
135
+ description 'An Important Attribute'
136
+ value get_att('Resource', 'Attribute')
137
+
138
+ ## Optional condition reference
139
+ condition 'SomeCondition'
140
+ end
141
+ ```
142
+
143
+ ### Intrinsic Functions
144
+ http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html
145
+
146
+ All intrinsic functions are available as helper methods:
147
+
148
+ * base64(content)
149
+ * fn_and(conditions...)
150
+ * fn_equals(value_1, value_2)
151
+ * fn_if(condition, value_true, value_false)
152
+ * fn_not(condition)
153
+ * fn_or(conditions...)
154
+ * find_in_map(map_name, key_1, key_2)
155
+ * get_att(resource, attr_name)
156
+ * get_azs(region)
157
+ * join(delimiter, values...)
158
+ * select(index, objects...)
159
+ * fn_ref(resource)
160
+
161
+ ```ruby
162
+ ec2_instance "TestInstanceFoo#{ i }" do
163
+ image_id find_in_map('RegionalAMIs', fn_ref('AWS::Region'), 'hvm')
164
+ instance_type 'm3.medium'
165
+ key_name find_in_map('RegionalKeys', fn_ref('AWS::Region'), 'test')
166
+ security_group fn_ref('LousySecurityGroup')
167
+ subnet fn_ref("TestSubnet")
168
+ end
169
+ ```
170
+
171
+ ## Stack Control
172
+ The `Stack` class provides a state wrapper for CloudFormation Stacks. It tracks the state of the managed stack, and creates/updates accordingly. `Stack` is also region-aware, and can be used within a template to define resources that depend upon availability-zones or other region-specific neuances that cannot be represented as maps or require iteration.
173
+
174
+ ### Class `Convection::Control::Stack`
175
+ * `.new(name, template, options = {})`
176
+ * _name_ CloudFormation Stack name
177
+ * _template_ Instance of Convection::Model::Template
178
+ * _options_ - Hash
179
+ * _region_ - AWS region, format `us-east-1`. Default us-east-1
180
+ * _credentials_ - Optional instance of AWS::Credentials. See the [AWS-SDK Documentation](http://docs.aws.amazon.com/sdkforruby/api/frames.html)
181
+ * _parameters_ - Stack parameters, as a `Hash` of `{ key => value }`
182
+ * _tags_ - Stack tags, as a `Hash` of `{ key => value }`
183
+ * _on_failure_ - Create failure action. Default `DELETE`
184
+ * _capabilities_ - See the [AWS-SDK Documentation](http://docs.aws.amazon.com/sdkforruby/api/Aws/CloudFormation/Client.html#create_stack-instance_method)
185
+ * Additional options will be passed directly to `create_stack` and `update_stack`
186
+
187
+ * `#status` - Returns the stack status
188
+ * `#exist?` - Returns true if the stack exists and is not in a DELETED state
189
+ * `#complete?`
190
+ * `#rollback?`
191
+ * `#fail?`
192
+ * `#render` - Populates the provided template with any environment data included in the stack (e.g. availability zones). Returns a `Hash`
193
+ * `#to_json` - Render template and transofrm to a pretty-generated JSON `String`
194
+ * `#apply` - Renter template and create/update CloudFormation Stack
195
+ * `#delete` - Delete CloudFormation Stack
196
+ * `#availability_zones(&block)` - Return an array of strings representing the region's availability zones. Provided codeblock will be called for each AZ.
197
+
198
+ ## License
199
+ _Copyright (c) 2015 John Manero, Rapid7 LLC._
200
+
201
+ ```
202
+ MIT License
203
+ ===========
204
+
205
+ Permission is hereby granted, free of charge, to any person obtaining
206
+ a copy of this software and associated documentation files (the
207
+ "Software"), to deal in the Software without restriction, including
208
+ without limitation the rights to use, copy, modify, merge, publish,
209
+ distribute, sublicense, and/or sell copies of the Software, and to
210
+ permit persons to whom the Software is furnished to do so, subject to
211
+ the following conditions:
212
+
213
+ The above copyright notice and this permission notice shall be
214
+ included in all copies or substantial portions of the Software.
215
+
216
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
217
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
218
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
219
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
220
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
221
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
222
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
223
+
224
+ ```
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/Thorfile ADDED
@@ -0,0 +1,5 @@
1
+ # encoding: utf-8
2
+
3
+ require 'bundler'
4
+ require 'bundler/setup'
5
+ require 'thor/scmversion'
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'convection/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'convection'
8
+ spec.version = Convection::VERSION
9
+ spec.authors = ['John Manero']
10
+ spec.email = ['jmanero@rapid7.com']
11
+ spec.summary = Convection::SUMMARY
12
+ spec.description = Convection::DESCRIPTION
13
+ spec.homepage = ''
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(/^(test|spec|features)\//)
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_development_dependency 'bundler', '~> 1.7'
22
+ spec.add_development_dependency 'rake', '~> 10.0'
23
+ spec.add_development_dependency 'thor-scmversion', '= 1.7.0'
24
+
25
+ spec.add_runtime_dependency 'aws-sdk', '< 2'
26
+ spec.add_runtime_dependency 'netaddr', '~> 1.5.0'
27
+ end
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env ruby
2
+ # $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
3
+ require 'convection'
4
+
5
+ ##
6
+ # This is a quick example of building out a cloudformation template without
7
+ # extending the underlying DSL.
8
+ #
9
+ # The reason could be anything from the inability to extend the dsl to a feature
10
+ # in AWS has been made availalble but the DSL will be complex - so this is a
11
+ # quick way to get access to those features.
12
+ ##
13
+
14
+ test_iam_role_template = Convection.template do
15
+ description 'This is an example of a stack representing IAM Roles and Policies.'
16
+
17
+ parameter 'Path' do
18
+ type 'String'
19
+ default '/'
20
+ end
21
+
22
+ iam_policy 'RolePolicy' do
23
+ role fn_ref('NewRole')
24
+ # You can choose between multiple 'role' attributes
25
+ # or build out an array with multiple values.
26
+ name 'NewPolicy'
27
+ # Note the move to fat colons below:
28
+ policy_document({
29
+ "Statement"=> [
30
+ {
31
+ "Effect"=> "Allow",
32
+ "Action"=> [
33
+ "s3:GetObject"
34
+ ],
35
+ "Resource"=> [
36
+ "arn:aws:s3:::some.bucket.name.here/*"
37
+ ]
38
+ }
39
+ ]
40
+ })
41
+ end
42
+
43
+ iam_role 'NewRole' do
44
+ path fn_ref('Path')
45
+ # This is a contrived example of an instance role for aws.
46
+ assume_role_policy_document({
47
+ "Statement" => [
48
+ {
49
+ "Sid" => "",
50
+ "Effect" => "Allow",
51
+ "Principal" => {
52
+ "Service" => "ec2.amazonaws.com"
53
+ },
54
+ "Action" => "sts:AssumeRole"
55
+ }
56
+ ]
57
+ })
58
+ end
59
+
60
+ end
61
+
62
+ puts test_iam_role_template.to_json
63
+ # puts Convection.stack('IAMTestStack', test_iam_role_template, :region => 'us-west-1').apply
data/example/s3.rb ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ require 'convection'
3
+
4
+ s3_template = Convection.template do
5
+ description 'Testing S3 bucket definition'
6
+
7
+ s3_bucket 'TestBucket' do
8
+ bucket_name 'convectiontestbucket'
9
+ end
10
+ end
11
+
12
+ puts s3_template.to_json
13
+ # puts Convection.stack('S3TestStack', s3_template, :region => 'us-west-1').apply
data/example/vpc.rb ADDED
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env ruby
2
+ require 'convection'
3
+
4
+ test_template = Convection.template do
5
+ description 'This is a test stack generated with Convection'
6
+
7
+ parameter 'InstanceSize' do
8
+ type 'String'
9
+ description 'Instance Size'
10
+ default 'm3.medium'
11
+
12
+ allow 'm3.medium'
13
+ allow 'm3.large'
14
+ allow 'm3.xlarge'
15
+ end
16
+
17
+ mapping 'RegionalAMIs' do
18
+ item 'us-east-1', 'hvm', 'ami-76e27e1e'
19
+ item 'us-west-1', 'hvm', 'ami-d5180890'
20
+ item 'us-east-1', 'pv', 'ami-64e27e0c'
21
+ item 'us-west-1', 'pv', 'ami-c5180880'
22
+ end
23
+
24
+ mapping 'RegionalKeys' do
25
+ item 'us-east-1', 'test', 'cf-test-keys'
26
+ item 'us-west-1', 'test', 'cf-test-keys'
27
+ end
28
+
29
+ ## Define the VPC
30
+ ec2_vpc 'TargetVPC' do
31
+ network '100.65.0.0/18'
32
+ subnet_length 25
33
+
34
+ ## Add an InternetGateway
35
+ add_internet_gateway
36
+
37
+ ## Add a default routing table
38
+ public_table = add_route_table('Public', :gateway_route => true)
39
+
40
+ ## Define Subnets and Insatnces in each availability zone
41
+ stack.availability_zones do |zone, i|
42
+ add_subnet "Test#{ i }" do
43
+ availability_zone zone
44
+ associate_route_table public_table
45
+
46
+ tag 'Service', 'Foo'
47
+ end
48
+ end
49
+
50
+ tag 'Name', join('-', 'cf-test-vpc', fn_ref('AWS::StackName'))
51
+ end
52
+
53
+ ec2_security_group 'BetterSecurityGroup' do
54
+ ingress_rule do
55
+ cidr_ip '0.0.0.0/0'
56
+ from 22
57
+ to 22
58
+ protocol 'TCP'
59
+ end
60
+ egress_rule do
61
+ cidr_ip '0.0.0.0/0'
62
+ from 0
63
+ to 65_535
64
+ protocol(-1)
65
+ end
66
+
67
+ description 'Allow SSH traffic from all of the places'
68
+ vpc_id fn_ref('TargetVPC')
69
+
70
+ tag 'Name', join('-', fn_ref('AWS::StackName'), 'BetterSecurityGroup')
71
+ end
72
+ end
73
+
74
+ # puts test_template.render
75
+ # puts test_template.to_json
76
+
77
+ # stack_e1 = Convection.stack('TestStackE1B1', test_template, :region => 'us-east-1')
78
+ stack_w1 = Convection.stack('TestStackW1B2', test_template, :region => 'us-west-1')
79
+
80
+ # puts stack_e1.status
81
+ # puts stack_e1.apply
82
+ puts stack_w1.to_json
83
+
84
+ puts "Status #{ stack_w1.status }"
85
+ # puts stack_w1.apply