lono 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|