lono 0.2.1 → 0.2.2
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.
- data/.gitignore +1 -0
- data/Guardfile +3 -3
- data/README.md +27 -40
- data/lib/lono.rb +1 -0
- data/lib/lono/cli.rb +9 -3
- data/lib/lono/dsl.rb +8 -49
- data/lib/lono/task.rb +12 -12
- data/lib/lono/template.rb +66 -0
- data/lib/lono/version.rb +1 -1
- data/lib/{files → starter_project}/Guardfile +0 -0
- data/{spec/project → lib/starter_project}/config/lono.rb +6 -5
- data/lib/{files/config/lono.rb → starter_project/config/lono/api.rb} +15 -18
- data/{spec/project → lib/starter_project}/templates/app.json.erb +1 -3
- data/lib/starter_project/templates/db.json.erb +211 -0
- data/{spec/project → lib/starter_project}/templates/partial/host_record.json.erb +1 -1
- data/lib/starter_project/templates/partial/server.json.erb +42 -0
- data/{spec/project → lib/starter_project}/templates/user_data/app.sh.erb +0 -0
- data/lib/starter_project/templates/user_data/db.sh.erb +27 -0
- data/spec/lib/lono_spec.rb +57 -24
- data/spec/spec_helper.rb +14 -1
- metadata +12 -15
- data/lib/files/templates/app.json.erb +0 -424
- data/spec/project/config/lono/api.rb +0 -20
@@ -0,0 +1,211 @@
|
|
1
|
+
{
|
2
|
+
"AWSTemplateFormatVersion": "2010-09-09",
|
3
|
+
"Description": "<%= @app.capitalize %> <%= @role %>",
|
4
|
+
"Outputs": {
|
5
|
+
"DBHostname": {
|
6
|
+
"Description": "Hostname for Redis",
|
7
|
+
"Value": {
|
8
|
+
"Fn::Join": [
|
9
|
+
"",
|
10
|
+
[
|
11
|
+
"",
|
12
|
+
{
|
13
|
+
"Fn::GetAtt": [
|
14
|
+
"server",
|
15
|
+
"PublicDnsName"
|
16
|
+
]
|
17
|
+
}
|
18
|
+
]
|
19
|
+
]
|
20
|
+
}
|
21
|
+
}
|
22
|
+
},
|
23
|
+
"Parameters": {
|
24
|
+
"Ami": {
|
25
|
+
"Default": "<%= @ami %>",
|
26
|
+
"Description": "deploy ami",
|
27
|
+
"Type": "String"
|
28
|
+
},
|
29
|
+
"Application": {
|
30
|
+
"Default": "<%= @app %>",
|
31
|
+
"Description": "foo, bar, etc",
|
32
|
+
"Type": "String"
|
33
|
+
},
|
34
|
+
"Environment": {
|
35
|
+
"Default": "<%= @env %>",
|
36
|
+
"Description": "stag, prod etc",
|
37
|
+
"Type": "String"
|
38
|
+
},
|
39
|
+
"InstanceType": {
|
40
|
+
"AllowedValues": [
|
41
|
+
"t1.micro",
|
42
|
+
"m1.small",
|
43
|
+
"m1.medium",
|
44
|
+
"m1.large",
|
45
|
+
"m1.xlarge",
|
46
|
+
"m2.xlarge",
|
47
|
+
"m2.2xlarge",
|
48
|
+
"m2.4xlarge",
|
49
|
+
"c1.medium",
|
50
|
+
"c1.xlarge",
|
51
|
+
"cc1.4xlarge",
|
52
|
+
"cc2.8xlarge",
|
53
|
+
"cg1.4xlarge"
|
54
|
+
],
|
55
|
+
"ConstraintDescription": "must be a valid EC2 instance type.",
|
56
|
+
"Default": "<%= @instance_type %>",
|
57
|
+
"Description": "server EC2 instance type",
|
58
|
+
"Type": "String"
|
59
|
+
},
|
60
|
+
"KeyName": {
|
61
|
+
"AllowedPattern": "[-_ a-zA-Z0-9]*",
|
62
|
+
"ConstraintDescription": "can contain only alphanumeric characters, spaces, dashes and underscores.",
|
63
|
+
"Default": "default",
|
64
|
+
"Description": "Name of an existing EC2 KeyPair to enable SSH access to the instances",
|
65
|
+
"MaxLength": "64",
|
66
|
+
"MinLength": "1",
|
67
|
+
"Type": "String"
|
68
|
+
},
|
69
|
+
"Role": {
|
70
|
+
"Default": "<%= @role %>",
|
71
|
+
"Description": "redis, psql, app, etc",
|
72
|
+
"Type": "String"
|
73
|
+
},
|
74
|
+
"StackNumber": {
|
75
|
+
"Default": "<%= @stack_number %>",
|
76
|
+
"Description": "s1, s2, s3, etc",
|
77
|
+
"Type": "String"
|
78
|
+
},
|
79
|
+
"VolumeSize": {
|
80
|
+
"ConstraintDescription": "must be between 5 and 1024 Gb.",
|
81
|
+
"Default": "<%= @volume_size %>",
|
82
|
+
"Description": "Size of Volume",
|
83
|
+
"MaxValue": "1024",
|
84
|
+
"MinValue": "5",
|
85
|
+
"Type": "Number"
|
86
|
+
}
|
87
|
+
},
|
88
|
+
"Resources": {
|
89
|
+
"CfnUser": {
|
90
|
+
"Properties": {
|
91
|
+
"Path": "/",
|
92
|
+
"Policies": [
|
93
|
+
{
|
94
|
+
"PolicyDocument": {
|
95
|
+
"Statement": [
|
96
|
+
{
|
97
|
+
"Action": "cloudformation:DescribeStackResource",
|
98
|
+
"Effect": "Allow",
|
99
|
+
"Resource": "*"
|
100
|
+
}
|
101
|
+
]
|
102
|
+
},
|
103
|
+
"PolicyName": "root"
|
104
|
+
}
|
105
|
+
]
|
106
|
+
},
|
107
|
+
"Type": "AWS::IAM::User"
|
108
|
+
},
|
109
|
+
"DataVolume": {
|
110
|
+
"DeletionPolicy": "Snapshot",
|
111
|
+
"Properties": {
|
112
|
+
"AvailabilityZone": {
|
113
|
+
"Fn::GetAtt": [
|
114
|
+
"server",
|
115
|
+
"AvailabilityZone"
|
116
|
+
]
|
117
|
+
},
|
118
|
+
"Size": {
|
119
|
+
"Ref": "VolumeSize"
|
120
|
+
},
|
121
|
+
"Tags": [
|
122
|
+
{
|
123
|
+
"Key": "Usage",
|
124
|
+
"Value": "Data Volume"
|
125
|
+
}
|
126
|
+
]
|
127
|
+
},
|
128
|
+
"Type": "AWS::EC2::Volume"
|
129
|
+
},
|
130
|
+
"HostKeys": {
|
131
|
+
"Properties": {
|
132
|
+
"UserName": {
|
133
|
+
"Ref": "CfnUser"
|
134
|
+
}
|
135
|
+
},
|
136
|
+
"Type": "AWS::IAM::AccessKey"
|
137
|
+
},
|
138
|
+
"HostRecord": {
|
139
|
+
"Properties": {
|
140
|
+
"Comment": "DNS name for my stack.",
|
141
|
+
"HostedZoneName": ".mydomain.net.",
|
142
|
+
"Name": {
|
143
|
+
"Fn::Join": [
|
144
|
+
"",
|
145
|
+
[
|
146
|
+
{
|
147
|
+
"Ref": "AWS::StackName"
|
148
|
+
},
|
149
|
+
".mydomain.net."
|
150
|
+
]
|
151
|
+
]
|
152
|
+
},
|
153
|
+
"ResourceRecords": [
|
154
|
+
{
|
155
|
+
"Fn::GetAtt": [
|
156
|
+
"server",
|
157
|
+
"PublicDnsName"
|
158
|
+
]
|
159
|
+
}
|
160
|
+
],
|
161
|
+
"TTL": "60",
|
162
|
+
"Type": "CNAME"
|
163
|
+
},
|
164
|
+
"Type": "AWS::Route53::RecordSet"
|
165
|
+
},
|
166
|
+
"MountPoint": {
|
167
|
+
"Properties": {
|
168
|
+
"Device": "/dev/sdf",
|
169
|
+
"InstanceId": {
|
170
|
+
"Ref": "server"
|
171
|
+
},
|
172
|
+
"VolumeId": {
|
173
|
+
"Ref": "DataVolume"
|
174
|
+
}
|
175
|
+
},
|
176
|
+
"Type": "AWS::EC2::VolumeAttachment"
|
177
|
+
},
|
178
|
+
"ServiceSecurityGroup": {
|
179
|
+
"Properties": {
|
180
|
+
"GroupDescription": "Enable SSH access.",
|
181
|
+
"SecurityGroupIngress": [
|
182
|
+
{
|
183
|
+
"CidrIp": "0.0.0.0/0",
|
184
|
+
"FromPort": "22",
|
185
|
+
"IpProtocol": "tcp",
|
186
|
+
"ToPort": "22"
|
187
|
+
}
|
188
|
+
]
|
189
|
+
},
|
190
|
+
"Type": "AWS::EC2::SecurityGroup"
|
191
|
+
},
|
192
|
+
"WaitCondition": {
|
193
|
+
"DependsOn": "MountPoint",
|
194
|
+
"Metadata": {
|
195
|
+
"Comment1": "Note that the WaitCondition is dependent on the volume mount point allowing the volume to be created and attached to the EC2 instance",
|
196
|
+
"Comment2": "The instance bootstrap script waits for the volume to be attached to the instance prior to signalling completion."
|
197
|
+
},
|
198
|
+
"Properties": {
|
199
|
+
"Handle": {
|
200
|
+
"Ref": "WaitHandle"
|
201
|
+
},
|
202
|
+
"Timeout": "3000"
|
203
|
+
},
|
204
|
+
"Type": "AWS::CloudFormation::WaitCondition"
|
205
|
+
},
|
206
|
+
"WaitHandle": {
|
207
|
+
"Type": "AWS::CloudFormation::WaitConditionHandle"
|
208
|
+
},
|
209
|
+
<%= partial("server.json.erb") %>
|
210
|
+
}
|
211
|
+
}
|
@@ -0,0 +1,42 @@
|
|
1
|
+
"server": {
|
2
|
+
"Properties": {
|
3
|
+
"AvailabilityZone": "<%= @availability_zone %>",
|
4
|
+
"ImageId": {
|
5
|
+
"Ref": "Ami"
|
6
|
+
},
|
7
|
+
"InstanceType": {
|
8
|
+
"Ref": "InstanceType"
|
9
|
+
},
|
10
|
+
"KeyName": {
|
11
|
+
"Ref": "KeyName"
|
12
|
+
},
|
13
|
+
"SecurityGroups": [
|
14
|
+
"global",
|
15
|
+
{
|
16
|
+
"Fn::Join": [
|
17
|
+
"-",
|
18
|
+
[
|
19
|
+
{
|
20
|
+
"Ref": "Environment"
|
21
|
+
},
|
22
|
+
{
|
23
|
+
"Ref": "Application"
|
24
|
+
}
|
25
|
+
]
|
26
|
+
]
|
27
|
+
},
|
28
|
+
{
|
29
|
+
"Ref": "ServiceSecurityGroup"
|
30
|
+
}
|
31
|
+
],
|
32
|
+
"UserData": {
|
33
|
+
"Fn::Base64": {
|
34
|
+
"Fn::Join": [
|
35
|
+
"",
|
36
|
+
<%= user_data('db.sh.erb') %>
|
37
|
+
]
|
38
|
+
}
|
39
|
+
}
|
40
|
+
},
|
41
|
+
"Type": "AWS::EC2::Instance"
|
42
|
+
}
|
File without changes
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/bin/bash -lexv
|
2
|
+
exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1
|
3
|
+
|
4
|
+
echo <%= ref("AWS::StackName") %> > /tmp/stack_name
|
5
|
+
# Helper function
|
6
|
+
function error_exit
|
7
|
+
{
|
8
|
+
/usr/local/bin/cfn-signal -e 1 -r "$1" '<%= ref("WaitHandle") %>'
|
9
|
+
exit 1
|
10
|
+
}
|
11
|
+
# Wait for the EBS volume to show up
|
12
|
+
while [ ! -e /dev/xvdf ]; do echo Waiting for EBS volume to attach; sleep 1; done
|
13
|
+
/bin/mkdir /media/redis
|
14
|
+
/sbin/mkfs -t ext4 /dev/xvdf
|
15
|
+
echo "/dev/xvdf /media/redis auto defaults 0 0" >> /etc/fstab
|
16
|
+
/bin/mount /media/redis
|
17
|
+
/usr/bin/redis-cli shutdown
|
18
|
+
sleep 10
|
19
|
+
mv /var/lib/redis/* /media/redis/
|
20
|
+
rm -r /var/lib/redis
|
21
|
+
ln -s /media/redis /var/lib/redis
|
22
|
+
chown -R redis:redis /var/lib/redis
|
23
|
+
chown -R redis:redis /media/redis
|
24
|
+
/usr/bin/redis-server
|
25
|
+
# If all is well so signal success
|
26
|
+
/usr/local/bin/cfn-signal -e $? -r "Ready to rock" '<%= ref("WaitHandle") %>'
|
27
|
+
cat /proc/uptime | cut -f1 -d'.' > /tmp/time-to-boot
|
data/spec/lib/lono_spec.rb
CHANGED
@@ -2,36 +2,69 @@ require File.expand_path("../../spec_helper", __FILE__)
|
|
2
2
|
|
3
3
|
describe Lono do
|
4
4
|
before(:each) do
|
5
|
-
@
|
6
|
-
@
|
7
|
-
|
8
|
-
:project_root => @project_root
|
9
|
-
)
|
10
|
-
@dsl.evaluate
|
5
|
+
@project = File.expand_path("../../project", __FILE__)
|
6
|
+
FileUtils.mkdir(@project) unless File.exist?(@project)
|
7
|
+
execute("./bin/lono init -f -q --project-root #{@project}")
|
11
8
|
end
|
12
9
|
|
13
10
|
after(:each) do
|
14
|
-
FileUtils.rm_rf(
|
11
|
+
FileUtils.rm_rf(@project)
|
15
12
|
end
|
16
13
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
14
|
+
describe "ruby specs" do
|
15
|
+
before(:each) do
|
16
|
+
@dsl = Lono::DSL.new(
|
17
|
+
:project_root => @project,
|
18
|
+
:quiet => true
|
19
|
+
)
|
20
|
+
@dsl.run
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should generate cloud formation template" do
|
24
|
+
raw = IO.read("#{@project}/output/prod-api-app.json")
|
25
|
+
json = JSON.load(raw)
|
26
|
+
json['Description'].should == "Api Stack"
|
27
|
+
json['Mappings']['AWSRegionArch2AMI']['us-east-1']['64'].should == 'ami-123'
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should generate db template" do
|
31
|
+
raw = IO.read("#{@project}/output/prod-api-redis.json")
|
32
|
+
json = JSON.load(raw)
|
33
|
+
json['Description'].should == "Api redis"
|
34
|
+
user_data = json['Resources']['server']['Properties']['UserData']['Fn::Base64']['Fn::Join'][1]
|
35
|
+
user_data.should include({"Ref" => "AWS::StackName"})
|
36
|
+
user_data.should include({"Ref" => "WaitHandle"})
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should transform bash script to CF template user_data" do
|
40
|
+
block = Proc.new { }
|
41
|
+
template = Lono::Template.new("foo", block)
|
42
|
+
|
43
|
+
line = 'echo {"Ref"=>"AWS::StackName"} > /tmp/stack_name ; {"Ref"=>"Ami"}'
|
44
|
+
data = template.transform(line)
|
45
|
+
data.should == ["echo ", {"Ref"=>"AWS::StackName"}, " > /tmp/stack_name ; ", {"Ref"=>"Ami"}, "\n"]
|
46
|
+
|
47
|
+
line = 'echo {"Ref"=>"AWS::StackName"} > /tmp/stack_name'
|
48
|
+
data = template.transform(line)
|
49
|
+
data.should == ["echo ", {"Ref"=>"AWS::StackName"}, " > /tmp/stack_name\n"]
|
50
|
+
end
|
51
|
+
|
52
|
+
it "task should generate cloud formation templates" do
|
53
|
+
Lono::Task.generate(
|
54
|
+
:project_root => @project,
|
55
|
+
:quiet => true
|
56
|
+
)
|
57
|
+
raw = IO.read("#{@project}/output/prod-api-app.json")
|
58
|
+
json = JSON.load(raw)
|
59
|
+
json['Description'].should == "Api Stack"
|
60
|
+
json['Mappings']['AWSRegionArch2AMI']['us-east-1']['64'].should == 'ami-123'
|
61
|
+
end
|
24
62
|
end
|
25
63
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
)
|
32
|
-
raw = IO.read("#{@project_root}/output/prod-api-app.json")
|
33
|
-
json = JSON.load(raw)
|
34
|
-
json['Description'].should == "Api Stack"
|
35
|
-
json['Mappings']['AWSRegionArch2AMI']['us-east-1']['64'].should == 'ami-123'
|
64
|
+
describe "cli specs" do
|
65
|
+
it "should generate templates" do
|
66
|
+
out = execute("./bin/lono generate -c --project-root #{@project}")
|
67
|
+
out.should match /Generating Cloud Formation templates/
|
68
|
+
end
|
36
69
|
end
|
37
70
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -5,4 +5,17 @@ Bundler.require(:development)
|
|
5
5
|
|
6
6
|
$root = File.expand_path('../../', __FILE__)
|
7
7
|
|
8
|
-
require "#{$root}/lib/lono"
|
8
|
+
require "#{$root}/lib/lono"
|
9
|
+
|
10
|
+
module Helpers
|
11
|
+
def execute(cmd)
|
12
|
+
puts "Running: #{cmd}" if ENV['DEBUG']
|
13
|
+
out = `#{cmd}`
|
14
|
+
puts out if ENV['DEBUG']
|
15
|
+
out
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
RSpec.configure do |c|
|
20
|
+
c.include Helpers
|
21
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lono
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-03-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -206,21 +206,23 @@ files:
|
|
206
206
|
- Rakefile
|
207
207
|
- bin/lono
|
208
208
|
- lib/ext/hash.rb
|
209
|
-
- lib/files/Guardfile
|
210
|
-
- lib/files/config/lono.rb
|
211
|
-
- lib/files/templates/app.json.erb
|
212
209
|
- lib/lono.rb
|
213
210
|
- lib/lono/cli.rb
|
214
211
|
- lib/lono/dsl.rb
|
215
212
|
- lib/lono/task.rb
|
213
|
+
- lib/lono/template.rb
|
216
214
|
- lib/lono/version.rb
|
215
|
+
- lib/starter_project/Guardfile
|
216
|
+
- lib/starter_project/config/lono.rb
|
217
|
+
- lib/starter_project/config/lono/api.rb
|
218
|
+
- lib/starter_project/templates/app.json.erb
|
219
|
+
- lib/starter_project/templates/db.json.erb
|
220
|
+
- lib/starter_project/templates/partial/host_record.json.erb
|
221
|
+
- lib/starter_project/templates/partial/server.json.erb
|
222
|
+
- lib/starter_project/templates/user_data/app.sh.erb
|
223
|
+
- lib/starter_project/templates/user_data/db.sh.erb
|
217
224
|
- lono.gemspec
|
218
225
|
- spec/lib/lono_spec.rb
|
219
|
-
- spec/project/config/lono.rb
|
220
|
-
- spec/project/config/lono/api.rb
|
221
|
-
- spec/project/templates/app.json.erb
|
222
|
-
- spec/project/templates/partial/host_record.json.erb
|
223
|
-
- spec/project/templates/user_data/app.sh.erb
|
224
226
|
- spec/spec_helper.rb
|
225
227
|
homepage: http://github.com/tongueroo/lono
|
226
228
|
licenses: []
|
@@ -249,9 +251,4 @@ summary: Lono is a Cloud Formation Template ruby generator. Lono generates Clou
|
|
249
251
|
Formation templates based on ERB templates.
|
250
252
|
test_files:
|
251
253
|
- spec/lib/lono_spec.rb
|
252
|
-
- spec/project/config/lono.rb
|
253
|
-
- spec/project/config/lono/api.rb
|
254
|
-
- spec/project/templates/app.json.erb
|
255
|
-
- spec/project/templates/partial/host_record.json.erb
|
256
|
-
- spec/project/templates/user_data/app.sh.erb
|
257
254
|
- spec/spec_helper.rb
|