convection 0.0.1

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.
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