sparkle_formation 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +2 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +23 -0
- data/README.md +262 -0
- data/examples/allinone/cloudformation/ec2_example.rb +59 -0
- data/examples/allinone/parse.rb +12 -0
- data/examples/ami_component/cloudformation/components/ami.rb +21 -0
- data/examples/ami_component/cloudformation/ec2_example.rb +41 -0
- data/examples/ami_component/parse.rb +12 -0
- data/lib/sparkle_formation/sparkle_attribute.rb +84 -0
- data/lib/sparkle_formation/sparkle_formation.rb +137 -0
- data/lib/sparkle_formation/utils.rb +17 -0
- data/lib/sparkle_formation/version.rb +5 -0
- data/lib/sparkle_formation.rb +2 -0
- data/sparkle_formation.gemspec +14 -0
- metadata +76 -0
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
sparkle_formation (0.1.0)
|
5
|
+
attribute_struct (~> 0.1.6)
|
6
|
+
|
7
|
+
PATH
|
8
|
+
remote: /home/spox/Projects/chrisroberts/attribute_struct
|
9
|
+
specs:
|
10
|
+
attribute_struct (0.1.7)
|
11
|
+
hashie (>= 2.0.0)
|
12
|
+
|
13
|
+
GEM
|
14
|
+
remote: https://rubygems.org/
|
15
|
+
specs:
|
16
|
+
hashie (2.0.5)
|
17
|
+
|
18
|
+
PLATFORMS
|
19
|
+
ruby
|
20
|
+
|
21
|
+
DEPENDENCIES
|
22
|
+
attribute_struct!
|
23
|
+
sparkle_formation!
|
data/README.md
ADDED
@@ -0,0 +1,262 @@
|
|
1
|
+
# SparkleFormation
|
2
|
+
|
3
|
+
AWS CloudFormation template building tools for Ruby. Yay!
|
4
|
+
|
5
|
+
## What's it do?
|
6
|
+
|
7
|
+
Provides a very loose DSL to describe an AWS CloudFormation
|
8
|
+
in Ruby.
|
9
|
+
|
10
|
+
## Is that it?
|
11
|
+
|
12
|
+
Yes. Well, kinda. It also has some extra features, like defining
|
13
|
+
components, dynamics, merging, AWS builtin function helpers, and
|
14
|
+
conjouring magic (to get unicorns).
|
15
|
+
|
16
|
+
## What's it look like?
|
17
|
+
|
18
|
+
Lets use one of the example CF templates that creates an EC2 instance. First
|
19
|
+
we can just convert it into a single file (ec2_example.rb):
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
SparkleFormation.new('ec2_example') do
|
23
|
+
description "AWS CloudFormation Sample Template EC2InstanceSample: Create an Amazon EC2 instance running the Amazon Linux AMI. The AMI is chosen based on the region in which the stack is run. This example uses the default security group, so to SSH to the new instance using the KeyPair you enter, you will need to have port 22 open in your default security group. **WARNING** This template an Amazon EC2 instances. You will be billed for the AWS resources used if you create a stack from this template."
|
24
|
+
|
25
|
+
parameters do
|
26
|
+
key_name do
|
27
|
+
description 'Name of an existing EC2 KeyPair to enable SSH access to the instance'
|
28
|
+
type 'String'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
mappings.region_map do
|
33
|
+
_set('us-east-1', :ami => 'ami-7f418316')
|
34
|
+
_set('us-east-1', :ami => 'ami-7f418316')
|
35
|
+
_set('us-west-1', :ami => 'ami-951945d0')
|
36
|
+
_set('us-west-2', :ami => 'ami-16fd7026')
|
37
|
+
_set('eu-west-1', :ami => 'ami-24506250')
|
38
|
+
_set('sa-east-1', :ami => 'ami-3e3be423')
|
39
|
+
_set('ap-southeast-1', :ami => 'ami-74dda626')
|
40
|
+
_set('ap-northeast-1', :ami => 'ami-dcfa4edd')
|
41
|
+
end
|
42
|
+
|
43
|
+
resources do
|
44
|
+
my_instance do
|
45
|
+
type 'AWS::EC2::Instance'
|
46
|
+
properties do
|
47
|
+
key_name _cf_ref(:key_name)
|
48
|
+
image_id _cf_map(:region_map, 'AWS::Region', :ami)
|
49
|
+
user_data _cf_base64('80')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
outputs do
|
55
|
+
instance_id do
|
56
|
+
description 'InstanceId of the newly created EC2 instance'
|
57
|
+
value _cf_ref(:my_instance)
|
58
|
+
end
|
59
|
+
az do
|
60
|
+
description 'Availability Zone of the newly created EC2 instance'
|
61
|
+
value _cf_attr(:my_instance, :availability_zone)
|
62
|
+
end
|
63
|
+
public_ip do
|
64
|
+
description 'Public IP address of the newly created EC2 instance'
|
65
|
+
value _cf_attr(:my_instance, :public_ip)
|
66
|
+
end
|
67
|
+
private_ip do
|
68
|
+
description 'Private IP address of the newly created EC2 instance'
|
69
|
+
value _cf_attr(:my_instance, :private_ip)
|
70
|
+
end
|
71
|
+
public_dns do
|
72
|
+
description 'Public DNSName of the newly created EC2 instance'
|
73
|
+
value _cf_attr(:my_instance, :public_dns_name)
|
74
|
+
end
|
75
|
+
private_dns do
|
76
|
+
description 'Private DNSName of the newly created EC2 instance'
|
77
|
+
value _cf_attr(:my_instance, :private_dns_name)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
```
|
82
|
+
|
83
|
+
And once compiled we get a nice Hash that we can then convert to JSON which
|
84
|
+
is ready for AWS. To print:
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
require 'sparkle_formation'
|
88
|
+
require 'json'
|
89
|
+
|
90
|
+
puts JSON.pretty_generate(
|
91
|
+
SparkleFormation.compile('ec2_example.rb')
|
92
|
+
)
|
93
|
+
```
|
94
|
+
|
95
|
+
Easy!
|
96
|
+
|
97
|
+
## Why not just write JSON?
|
98
|
+
|
99
|
+
Because, who in their right mind would want to write all of that in JSON? Also,
|
100
|
+
we can start applying some of the underlying features in `SparkleFormation` to
|
101
|
+
make this easier to maintain.
|
102
|
+
|
103
|
+
# Components
|
104
|
+
|
105
|
+
Lets say we have a handful of CF templates we want to maintain, and all of those
|
106
|
+
templates use the same AMI. Instead of copying that information into all the
|
107
|
+
templates, lets create an AMI component instead, and then load it into the actual
|
108
|
+
templates.
|
109
|
+
|
110
|
+
First, create the component (components/ami.rb):
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
SparkleFormation.build do
|
114
|
+
|
115
|
+
parameters do
|
116
|
+
key_name do
|
117
|
+
description 'Name of an existing EC2 KeyPair to enable SSH access to the instance'
|
118
|
+
type 'String'
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
mappings.region_map do
|
123
|
+
_set('us-east-1', :ami => 'ami-7f418316')
|
124
|
+
_set('us-east-1', :ami => 'ami-7f418316')
|
125
|
+
_set('us-west-1', :ami => 'ami-951945d0')
|
126
|
+
_set('us-west-2', :ami => 'ami-16fd7026')
|
127
|
+
_set('eu-west-1', :ami => 'ami-24506250')
|
128
|
+
_set('sa-east-1', :ami => 'ami-3e3be423')
|
129
|
+
_set('ap-southeast-1', :ami => 'ami-74dda626')
|
130
|
+
_set('ap-northeast-1', :ami => 'ami-dcfa4edd')
|
131
|
+
end
|
132
|
+
end
|
133
|
+
```
|
134
|
+
|
135
|
+
Now, we can modify our initial example to use this component (ec2_example.rb):
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
SparkleFormation.new('ec2_example').load(:ami).overrides do
|
139
|
+
|
140
|
+
description "AWS CloudFormation Sample Template EC2InstanceSample: Create an Amazon EC2 instance running the Amazon Linux AMI. The AMI is chosen based on the region in which the stack is run. This example uses the default security group, so to SSH to the new instance using the KeyPair you enter, you will need to have port 22 open in your default security group. **WARNING** This template an Amazon EC2 instances. You will be billed for the AWS resources used if you create a stack from this template."
|
141
|
+
|
142
|
+
resources do
|
143
|
+
my_instance do
|
144
|
+
type 'AWS::EC2::Instance'
|
145
|
+
properties do
|
146
|
+
key_name _cf_ref(:key_name)
|
147
|
+
image_id _cf_map(:region_map, 'AWS::Region', :ami)
|
148
|
+
user_data _cf_base64('80')
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
outputs do
|
154
|
+
instance_id do
|
155
|
+
description 'InstanceId of the newly created EC2 instance'
|
156
|
+
value _cf_ref(:my_instance)
|
157
|
+
end
|
158
|
+
az do
|
159
|
+
description 'Availability Zone of the newly created EC2 instance'
|
160
|
+
value _cf_attr(:my_instance, :availability_zone)
|
161
|
+
end
|
162
|
+
public_ip do
|
163
|
+
description 'Public IP address of the newly created EC2 instance'
|
164
|
+
value _cf_attr(:my_instance, :public_ip)
|
165
|
+
end
|
166
|
+
private_ip do
|
167
|
+
description 'Private IP address of the newly created EC2 instance'
|
168
|
+
value _cf_attr(:my_instance, :private_ip)
|
169
|
+
end
|
170
|
+
public_dns do
|
171
|
+
description 'Public DNSName of the newly created EC2 instance'
|
172
|
+
value _cf_attr(:my_instance, :public_dns_name)
|
173
|
+
end
|
174
|
+
private_dns do
|
175
|
+
description 'Private DNSName of the newly created EC2 instance'
|
176
|
+
value _cf_attr(:my_instance, :private_dns_name)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
```
|
181
|
+
|
182
|
+
Now a few things have changed. Instead of passing a block directly to the
|
183
|
+
instance instantiation, we are loading a component (the `ami` component)
|
184
|
+
into the formation, and then applying an override block on top of the `ami`
|
185
|
+
component. The result is the same as the initial example, but now we have
|
186
|
+
a DRY component to use. Great!
|
187
|
+
|
188
|
+
## Dynamics
|
189
|
+
|
190
|
+
Okay, so lets say we want to have two ec2 instances. We could duplicate the
|
191
|
+
resource and outputs, renaming where required. This would get ugly quick,
|
192
|
+
especially as more instances are added. Making a component for the ec2 resource
|
193
|
+
won't really help since components are static, used to apply the same common
|
194
|
+
parts to multiple templates. So what do we use?
|
195
|
+
|
196
|
+
Enter `dynamics`. These are much like components, except that instead of simply
|
197
|
+
being merged, they allow passing of arguments which makes them reusable to create
|
198
|
+
unique resources. So, from our last example, lets move the ec2 related items
|
199
|
+
into a dynamic (dynamics/ec2.rb):
|
200
|
+
|
201
|
+
```ruby
|
202
|
+
SparkleFormation.dynamic(:ec2) do |_name|
|
203
|
+
resources("#{_name}_instance".to_sym)
|
204
|
+
type 'AWS::EC2::Instance'
|
205
|
+
properties do
|
206
|
+
key_name _cf_ref(:key_name)
|
207
|
+
image_id _cf_map(:region_map, 'AWS::Region', :ami)
|
208
|
+
user_data _cf_base64('80')
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
outputs("#{_name}_instance_id".to_sym) do
|
213
|
+
description 'InstanceId of the newly created EC2 instance'
|
214
|
+
value _cf_ref("#{_name}_instance".to_sym)
|
215
|
+
end
|
216
|
+
outputs("#{_name}_az".to_sym) do
|
217
|
+
description 'Availability Zone of the newly created EC2 instance'
|
218
|
+
value _cf_attr("#{_name}_instance".to_sym, :availability_zone)
|
219
|
+
end
|
220
|
+
outputs("#{_name}_public_ip".to_sym) do
|
221
|
+
description 'Public IP address of the newly created EC2 instance'
|
222
|
+
value _cf_attr("#{_name}_instance".to_sym, :public_ip)
|
223
|
+
end
|
224
|
+
outputs("#{_name}_private_ip".to_sym) do
|
225
|
+
description 'Private IP address of the newly created EC2 instance'
|
226
|
+
value _cf_attr("#{_name}_instance".to_sym, :private_ip)
|
227
|
+
end
|
228
|
+
outputs("#{_name}_public_dns".to_sym) do
|
229
|
+
description 'Public DNSName of the newly created EC2 instance'
|
230
|
+
value _cf_attr("#{_name}_instance".to_sym, :public_dns_name)
|
231
|
+
end
|
232
|
+
outputs("#{_name}_private_dns".to_sym) do
|
233
|
+
description 'Private DNSName of the newly created EC2 instance'
|
234
|
+
value _cf_attr("#{_name}_instance".to_sym, :private_dns_name)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
```
|
238
|
+
|
239
|
+
Now we can put all of these together, and create multiple ec2 instance
|
240
|
+
resource easily:
|
241
|
+
|
242
|
+
```ruby
|
243
|
+
SparkleFormation.new('ec2_example').load(:ami).overrides do
|
244
|
+
|
245
|
+
description "AWS CloudFormation Sample Template EC2InstanceSample: Create an Amazon EC2 instance running the Amazon Linux AMI. The AMI is chosen based on the region in which the stack is run. This example uses the default security group, so to SSH to the new instance using the KeyPair you enter, you will need to have port 22 open in your default security group. **WARNING** This template an Amazon EC2 instances. You will be billed for the AWS resources used if you create a stack from this template."
|
246
|
+
|
247
|
+
[:node1, :node2, :node3].each do |_node_name|
|
248
|
+
SparkleFormation.insert(:ec2, self, _node_name)
|
249
|
+
end
|
250
|
+
|
251
|
+
end
|
252
|
+
```
|
253
|
+
|
254
|
+
## TODO
|
255
|
+
* Add information about symbol importance
|
256
|
+
* Add examples of camel case control
|
257
|
+
* Add examples of complex merge strategies
|
258
|
+
* Add examples of accessing parent hash elements
|
259
|
+
|
260
|
+
# Infos
|
261
|
+
* Repository: https://github.com/heavywater/sparkle_formation
|
262
|
+
* IRC: Freenode @ #heavywater
|
@@ -0,0 +1,59 @@
|
|
1
|
+
SparkleFormation.new('ec2_example') do
|
2
|
+
description "AWS CloudFormation Sample Template EC2InstanceSample: Create an Amazon EC2 instance running the Amazon Linux AMI. The AMI is chosen based on the region in which the stack is run. This example uses the default security group, so to SSH to the new instance using the KeyPair you enter, you will need to have port 22 open in your default security group. **WARNING** This template an Amazon EC2 instances. You will be billed for the AWS resources used if you create a stack from this template."
|
3
|
+
|
4
|
+
parameters do
|
5
|
+
key_name do
|
6
|
+
description 'Name of an existing EC2 KeyPair to enable SSH access to the instance'
|
7
|
+
type 'String'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
mappings.region_map do
|
12
|
+
_set('us-east-1', :ami => 'ami-7f418316')
|
13
|
+
_set('us-east-1', :ami => 'ami-7f418316')
|
14
|
+
_set('us-west-1', :ami => 'ami-951945d0')
|
15
|
+
_set('us-west-2', :ami => 'ami-16fd7026')
|
16
|
+
_set('eu-west-1', :ami => 'ami-24506250')
|
17
|
+
_set('sa-east-1', :ami => 'ami-3e3be423')
|
18
|
+
_set('ap-southeast-1', :ami => 'ami-74dda626')
|
19
|
+
_set('ap-northeast-1', :ami => 'ami-dcfa4edd')
|
20
|
+
end
|
21
|
+
|
22
|
+
resources do
|
23
|
+
my_instance do
|
24
|
+
type 'AWS::EC2::Instance'
|
25
|
+
properties do
|
26
|
+
key_name _cf_ref(:key_name)
|
27
|
+
image_id _cf_map(:region_map, 'AWS::Region', :ami)
|
28
|
+
user_data _cf_base64('80')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
outputs do
|
34
|
+
instance_id do
|
35
|
+
description 'InstanceId of the newly created EC2 instance'
|
36
|
+
value _cf_ref(:my_instance)
|
37
|
+
end
|
38
|
+
az do
|
39
|
+
description 'Availability Zone of the newly created EC2 instance'
|
40
|
+
value _cf_attr(:my_instance, :availability_zone)
|
41
|
+
end
|
42
|
+
public_ip do
|
43
|
+
description 'Public IP address of the newly created EC2 instance'
|
44
|
+
value _cf_attr(:my_instance, :public_ip)
|
45
|
+
end
|
46
|
+
private_ip do
|
47
|
+
description 'Private IP address of the newly created EC2 instance'
|
48
|
+
value _cf_attr(:my_instance, :private_ip)
|
49
|
+
end
|
50
|
+
public_dns do
|
51
|
+
description 'Public DNSName of the newly created EC2 instance'
|
52
|
+
value _cf_attr(:my_instance, :public_dns_name)
|
53
|
+
end
|
54
|
+
private_dns do
|
55
|
+
description 'Private DNSName of the newly created EC2 instance'
|
56
|
+
value _cf_attr(:my_instance, :private_dns_name)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
SparkleFormation.build do
|
2
|
+
|
3
|
+
parameters do
|
4
|
+
key_name do
|
5
|
+
description 'Name of an existing EC2 KeyPair to enable SSH access to the instance'
|
6
|
+
type 'String'
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
mappings.region_map do
|
11
|
+
_set('us-east-1', :ami => 'ami-7f418316')
|
12
|
+
_set('us-east-1', :ami => 'ami-7f418316')
|
13
|
+
_set('us-west-1', :ami => 'ami-951945d0')
|
14
|
+
_set('us-west-2', :ami => 'ami-16fd7026')
|
15
|
+
_set('eu-west-1', :ami => 'ami-24506250')
|
16
|
+
_set('sa-east-1', :ami => 'ami-3e3be423')
|
17
|
+
_set('ap-southeast-1', :ami => 'ami-74dda626')
|
18
|
+
_set('ap-northeast-1', :ami => 'ami-dcfa4edd')
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
SparkleFormation.new('ec2_example').load(:ami).overrides do
|
2
|
+
description "AWS CloudFormation Sample Template EC2InstanceSample: Create an Amazon EC2 instance running the Amazon Linux AMI. The AMI is chosen based on the region in which the stack is run. This example uses the default security group, so to SSH to the new instance using the KeyPair you enter, you will need to have port 22 open in your default security group. **WARNING** This template an Amazon EC2 instances. You will be billed for the AWS resources used if you create a stack from this template."
|
3
|
+
|
4
|
+
resources do
|
5
|
+
my_instance do
|
6
|
+
type 'AWS::EC2::Instance'
|
7
|
+
properties do
|
8
|
+
key_name _cf_ref(:key_name)
|
9
|
+
image_id _cf_map(:region_map, 'AWS::Region', :ami)
|
10
|
+
user_data _cf_base64('80')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
outputs do
|
16
|
+
instance_id do
|
17
|
+
description 'InstanceId of the newly created EC2 instance'
|
18
|
+
value _cf_ref(:my_instance)
|
19
|
+
end
|
20
|
+
az do
|
21
|
+
description 'Availability Zone of the newly created EC2 instance'
|
22
|
+
value _cf_attr(:my_instance, :availability_zone)
|
23
|
+
end
|
24
|
+
public_ip do
|
25
|
+
description 'Public IP address of the newly created EC2 instance'
|
26
|
+
value _cf_attr(:my_instance, :public_ip)
|
27
|
+
end
|
28
|
+
private_ip do
|
29
|
+
description 'Private IP address of the newly created EC2 instance'
|
30
|
+
value _cf_attr(:my_instance, :private_ip)
|
31
|
+
end
|
32
|
+
public_dns do
|
33
|
+
description 'Public DNSName of the newly created EC2 instance'
|
34
|
+
value _cf_attr(:my_instance, :public_dns_name)
|
35
|
+
end
|
36
|
+
private_dns do
|
37
|
+
description 'Private DNSName of the newly created EC2 instance'
|
38
|
+
value _cf_attr(:my_instance, :private_dns_name)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'attribute_struct'
|
2
|
+
|
3
|
+
module SparkleAttribute
|
4
|
+
|
5
|
+
def _cf_join(*args)
|
6
|
+
options = args.detect{|i| i.is_a?(Hash) && i[:options]} || {:options => {}}
|
7
|
+
args.delete(options)
|
8
|
+
unless(args.size == 1)
|
9
|
+
args = [args]
|
10
|
+
end
|
11
|
+
{'Fn::Join' => [options[:options][:delimiter] || '', *args]}
|
12
|
+
end
|
13
|
+
|
14
|
+
def _cf_ref(thing)
|
15
|
+
thing = _process_key(thing, :force) if thing.is_a?(Symbol)
|
16
|
+
{'Ref' => thing}
|
17
|
+
end
|
18
|
+
alias_method :_ref, :_cf_ref
|
19
|
+
|
20
|
+
def _cf_map(thing, key, *suffix)
|
21
|
+
suffix = suffix.map do |item|
|
22
|
+
if(item.is_a?(Symbol))
|
23
|
+
_process_key(item, :force)
|
24
|
+
else
|
25
|
+
item
|
26
|
+
end
|
27
|
+
end
|
28
|
+
thing = _process_key(thing, :force) if thing.is_a?(Symbol)
|
29
|
+
key = _process_key(key, :force) if key.is_a?(Symbol)
|
30
|
+
{'Fn::FindInMap' => [_process_key(thing), {'Ref' => _process_key(key)}, *suffix]}
|
31
|
+
end
|
32
|
+
alias_method :_cf_find_in_map, :_cf_map
|
33
|
+
|
34
|
+
def _cf_attr(*args)
|
35
|
+
args = args.map do |thing|
|
36
|
+
if(thing.is_a?(Symbol))
|
37
|
+
_process_key(thing, :force)
|
38
|
+
else
|
39
|
+
thing
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
{'Fn::GetAtt' => args}
|
44
|
+
end
|
45
|
+
alias_method :_cf_get_att, :_cf_attr
|
46
|
+
|
47
|
+
def _cf_base64(arg)
|
48
|
+
{'Fn::Base64' => arg}
|
49
|
+
end
|
50
|
+
|
51
|
+
def _cf_get_azs(region=nil)
|
52
|
+
region = case region
|
53
|
+
when Symbol
|
54
|
+
_cf_ref(region)
|
55
|
+
when NilClass
|
56
|
+
''
|
57
|
+
else
|
58
|
+
region
|
59
|
+
end
|
60
|
+
{'Fn::GetAZs' => region}
|
61
|
+
end
|
62
|
+
|
63
|
+
def _cf_select(index, item)
|
64
|
+
item = _cf_ref(item) if item.is_a?(Symbol)
|
65
|
+
{'Fn::Select', [index.to_i.to_s, item]}
|
66
|
+
end
|
67
|
+
|
68
|
+
def rhel?
|
69
|
+
!!@platform[:rhel]
|
70
|
+
end
|
71
|
+
|
72
|
+
def debian?
|
73
|
+
!!@platform[:debian]
|
74
|
+
end
|
75
|
+
|
76
|
+
def _platform=(plat)
|
77
|
+
@platform || __hashish
|
78
|
+
@platform.clear
|
79
|
+
@platform[plat.to_sym] = true
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
AttributeStruct.send(:include, SparkleAttribute)
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'attribute_struct'
|
2
|
+
require 'sparkle_formation/sparkle_attribute'
|
3
|
+
require 'sparkle_formation/utils'
|
4
|
+
|
5
|
+
AttributeStruct.camel_keys = true
|
6
|
+
|
7
|
+
class SparkleFormation
|
8
|
+
|
9
|
+
include SparkleFormation::Utils::AnimalStrings
|
10
|
+
|
11
|
+
class << self
|
12
|
+
|
13
|
+
attr_reader :dynamics
|
14
|
+
attr_reader :components_path
|
15
|
+
attr_reader :dynamics_path
|
16
|
+
|
17
|
+
def custom_paths
|
18
|
+
@_paths ||= {}
|
19
|
+
@_paths
|
20
|
+
end
|
21
|
+
|
22
|
+
def components_path=(path)
|
23
|
+
custom_paths[:sparkle_path] = path
|
24
|
+
end
|
25
|
+
|
26
|
+
def dynamics_path=(path)
|
27
|
+
custom_paths[:dynamics_directory] = path
|
28
|
+
end
|
29
|
+
|
30
|
+
def compile(path)
|
31
|
+
formation = self.instance_eval(IO.read(path), path, 1)
|
32
|
+
formation.compile._dump
|
33
|
+
end
|
34
|
+
|
35
|
+
def build(&block)
|
36
|
+
struct = AttributeStruct.new
|
37
|
+
struct.instance_exec(&block)
|
38
|
+
struct
|
39
|
+
end
|
40
|
+
|
41
|
+
def load_component(path)
|
42
|
+
self.instance_eval(IO.read(path), path, 1)
|
43
|
+
end
|
44
|
+
|
45
|
+
def load_dynamics!(directory)
|
46
|
+
@loaded_dynamics ||= []
|
47
|
+
Dir.glob(File.join(directory, '*.rb')).each do |dyn|
|
48
|
+
dyn = File.expand_path(dyn)
|
49
|
+
next if @loaded_dynamics.include?(dyn)
|
50
|
+
self.instance_eval(IO.read(dyn), dyn, 1)
|
51
|
+
@loaded_dynamics << dyn
|
52
|
+
end
|
53
|
+
@loaded_dynamics.uniq!
|
54
|
+
true
|
55
|
+
end
|
56
|
+
|
57
|
+
def dynamic(name, &block)
|
58
|
+
@dynamics ||= Mash.new
|
59
|
+
@dynamics[name] = block
|
60
|
+
end
|
61
|
+
|
62
|
+
def insert(dynamic_name, struct, *args)
|
63
|
+
if(@dynamics && @dynamics[dynamic_name])
|
64
|
+
struct.instance_exec(*args, &@dynamics[dynamic_name])
|
65
|
+
struct
|
66
|
+
else
|
67
|
+
raise "Failed to locate requested dynamic block for insertion: #{dynamic_name} (valid: #{@dynamics.keys.sort.join(', ')})"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def from_hash(hash)
|
72
|
+
struct = AttributeStruct.new
|
73
|
+
struct._camel_keys_set(:auto_discovery)
|
74
|
+
struct._load(hash)
|
75
|
+
struct._camel_keys_set(nil)
|
76
|
+
struct
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
attr_reader :name
|
81
|
+
attr_reader :sparkle_path
|
82
|
+
attr_reader :components
|
83
|
+
attr_reader :load_order
|
84
|
+
|
85
|
+
def initialize(name, options={}, &block)
|
86
|
+
@name = name
|
87
|
+
@sparkle_path = options[:sparkle_path] ||
|
88
|
+
self.class.custom_paths[:sparkle_path] ||
|
89
|
+
File.join(Dir.pwd, 'cloudformation/components')
|
90
|
+
@dynamics_directory = options[:dynamics_directory] ||
|
91
|
+
self.class.custom_paths[:dynamics_directory] ||
|
92
|
+
File.join(File.dirname(@sparkle_path), 'dynamics')
|
93
|
+
self.class.load_dynamics!(@dynamics_directory)
|
94
|
+
@components = AttributeStruct.hashish.new
|
95
|
+
@load_order = []
|
96
|
+
if(block)
|
97
|
+
load_block(block)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def load_block(block)
|
102
|
+
@components[:__base__] = self.class.build(&block)
|
103
|
+
@load_order << :__base__
|
104
|
+
end
|
105
|
+
|
106
|
+
def load(*args)
|
107
|
+
args.each do |thing|
|
108
|
+
if(thing.is_a?(Symbol))
|
109
|
+
path = File.join(sparkle_path, "#{thing}.rb")
|
110
|
+
else
|
111
|
+
path = thing
|
112
|
+
end
|
113
|
+
key = File.basename(path).sub('.rb', '')
|
114
|
+
components[key] = self.class.load_component(path)
|
115
|
+
@load_order << key
|
116
|
+
end
|
117
|
+
self
|
118
|
+
end
|
119
|
+
|
120
|
+
def overrides(&block)
|
121
|
+
@overrides = self.class.build(&block)
|
122
|
+
self
|
123
|
+
end
|
124
|
+
|
125
|
+
# Returns compiled Mash instance
|
126
|
+
def compile
|
127
|
+
compiled = AttributeStruct.new
|
128
|
+
@load_order.each do |key|
|
129
|
+
compiled._merge!(components[key])
|
130
|
+
end
|
131
|
+
if(@overrides)
|
132
|
+
compiled._merge!(@overrides)
|
133
|
+
end
|
134
|
+
compiled
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class SparkleFormation
|
2
|
+
module Utils
|
3
|
+
|
4
|
+
module AnimalStrings
|
5
|
+
|
6
|
+
def camel(string)
|
7
|
+
string.to_s.split('_').map{|k| "#{k.slice(0,1).upcase}#{k.slice(1,k.length)}"}.join
|
8
|
+
end
|
9
|
+
|
10
|
+
def snake(string)
|
11
|
+
string.to_s.gsub(/([a-z])([A-Z])/, '\1_\2').downcase.to_sym
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__)) + '/lib/'
|
2
|
+
require 'sparkle_formation/version'
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = 'sparkle_formation'
|
5
|
+
s.version = SparkleFormation::VERSION.version
|
6
|
+
s.summary = 'Cloud Formation builder'
|
7
|
+
s.author = 'Chris Roberts'
|
8
|
+
s.email = 'chrisroberts.code@gmail.com'
|
9
|
+
s.homepage = 'http://github.com/heavywater/sparkle_formation'
|
10
|
+
s.description = 'Cloud Formation builder'
|
11
|
+
s.require_path = 'lib'
|
12
|
+
s.add_dependency 'attribute_struct', '~> 0.1.6'
|
13
|
+
s.files = Dir['**/*']
|
14
|
+
end
|
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sparkle_formation
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Chris Roberts
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-10-15 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: attribute_struct
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.1.6
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.1.6
|
30
|
+
description: Cloud Formation builder
|
31
|
+
email: chrisroberts.code@gmail.com
|
32
|
+
executables: []
|
33
|
+
extensions: []
|
34
|
+
extra_rdoc_files: []
|
35
|
+
files:
|
36
|
+
- lib/sparkle_formation/sparkle_attribute.rb
|
37
|
+
- lib/sparkle_formation/version.rb
|
38
|
+
- lib/sparkle_formation/sparkle_formation.rb
|
39
|
+
- lib/sparkle_formation/utils.rb
|
40
|
+
- lib/sparkle_formation.rb
|
41
|
+
- examples/allinone/parse.rb
|
42
|
+
- examples/allinone/cloudformation/ec2_example.rb
|
43
|
+
- examples/ami_component/parse.rb
|
44
|
+
- examples/ami_component/cloudformation/components/ami.rb
|
45
|
+
- examples/ami_component/cloudformation/ec2_example.rb
|
46
|
+
- Gemfile
|
47
|
+
- sparkle_formation.gemspec
|
48
|
+
- README.md
|
49
|
+
- CHANGELOG.md
|
50
|
+
- Gemfile.lock
|
51
|
+
homepage: http://github.com/heavywater/sparkle_formation
|
52
|
+
licenses: []
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options: []
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
requirements: []
|
70
|
+
rubyforge_project:
|
71
|
+
rubygems_version: 1.8.24
|
72
|
+
signing_key:
|
73
|
+
specification_version: 3
|
74
|
+
summary: Cloud Formation builder
|
75
|
+
test_files: []
|
76
|
+
has_rdoc:
|