awsborn 0.3.9 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.mdown +14 -4
- data/VERSION +1 -1
- data/contrib/chef-bootstrap.sh +24 -0
- data/contrib/cookbooks/ec2-ebs/recipes/default.rb +38 -0
- data/lib/awsborn/awsborn.rb +7 -3
- data/lib/awsborn/known_hosts_updater.rb +4 -3
- data/lib/awsborn/rake.rb +33 -21
- data/lib/awsborn/server.rb +23 -6
- data/lib/awsborn/server_cluster.rb +3 -2
- metadata +6 -4
data/README.mdown
CHANGED
@@ -65,7 +65,7 @@ Servers take five different directives:
|
|
65
65
|
* `image_id` -- a valid EC2 AMI. Specify `:sudo_user` as an option if the AMI
|
66
66
|
does not allow you to log in as root.
|
67
67
|
* `security_group` -- a security group that you own.
|
68
|
-
* `keys` -- one or more globs to public ssh
|
68
|
+
* `keys` -- one or more globs to public ssh key files. When the servers are running,
|
69
69
|
`root` will be able to log in using any one of these keys.
|
70
70
|
* `bootstrap_script` -- path to a script which will be run on each instance as
|
71
71
|
soon as it is started. Use it to bootstrap `chef` and let `chef` take it from
|
@@ -87,7 +87,12 @@ Mandatory keys:
|
|
87
87
|
* `:zone` -- the availability zone for the server. One of `:us_east_1a`, `:us_east_1b`,
|
88
88
|
`:us_east_1c`, `:us_west_1a`, `:us_west_1b`, `:eu_west_1a`, `:eu_west_1b`.
|
89
89
|
* `:disk` -- a hash of `device => volume-id`. Awsborn uses the disks to tell if a server
|
90
|
-
is running or not (see *Launching a cluster*).
|
90
|
+
is running or not (see *Launching a cluster*). `volume-id` can also be an array
|
91
|
+
`[volume-id, :format]`, in which case `the_server.format_disk_on_device?(device)`
|
92
|
+
will return `true`. See `contrib/cookbooks/ec2-ebs` for example usage.
|
93
|
+
|
94
|
+
Optional keys:
|
95
|
+
|
91
96
|
* `:ip` -- a domain name which translates to an elastic ip. If the domain name does not
|
92
97
|
contain a full stop (dot) and `domain` has been specified above, the domain is added.
|
93
98
|
|
@@ -206,6 +211,7 @@ Awsborn integrates with [Chef Solo](http://github.com/opscode/chef). An example
|
|
206
211
|
"ec2-ebs",
|
207
212
|
"git",
|
208
213
|
"gems",
|
214
|
+
"lumberjack"
|
209
215
|
]
|
210
216
|
}
|
211
217
|
end
|
@@ -218,7 +224,12 @@ Just add a `Rakefile` in the same directory:
|
|
218
224
|
require './servers'
|
219
225
|
|
220
226
|
You are now able to run `rake` to start all servers and run Chef on each of them.
|
221
|
-
|
227
|
+
Other rake tasks include:
|
228
|
+
|
229
|
+
* `rake chef` - Run chef on all servers, or the ones specified with `host=name1,name2`.
|
230
|
+
* `rake chef:debug` - Ditto, but with chef's log level set to `debug`.
|
231
|
+
* `rake start` - Start all servers (or host=name1,name2) but don't run `chef`.
|
232
|
+
|
222
233
|
|
223
234
|
## Bugs and surprising features
|
224
235
|
|
@@ -227,7 +238,6 @@ No bugs are known at this time.
|
|
227
238
|
### Untested features
|
228
239
|
|
229
240
|
* Launching without ssh keys. (I suppose certain AMIs would support that.)
|
230
|
-
* Running without elastic ip.
|
231
241
|
|
232
242
|
## To do / Could do
|
233
243
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
echo '------------------'
|
4
|
+
echo 'Bootstrapping Chef'
|
5
|
+
echo
|
6
|
+
|
7
|
+
aptitude -y update
|
8
|
+
aptitude -y install gcc g++ curl build-essential \
|
9
|
+
libxml-ruby libxml2-dev \
|
10
|
+
ruby irb ri rdoc ruby1.8-dev libzlib-ruby libyaml-ruby libreadline-ruby \
|
11
|
+
libruby libruby-extras libopenssl-ruby \
|
12
|
+
libdbm-ruby libdbi-ruby libdbd-sqlite3-ruby \
|
13
|
+
sqlite3 libsqlite3-dev libsqlite3-ruby
|
14
|
+
|
15
|
+
curl -L 'http://rubyforge.org/frs/download.php/69365/rubygems-1.3.6.tgz' | tar zxf -
|
16
|
+
cd rubygems* && ruby setup.rb --no-ri --no-rdoc
|
17
|
+
|
18
|
+
ln -sfv /usr/bin/gem1.8 /usr/bin/gem
|
19
|
+
|
20
|
+
gem install chef ohai --no-ri --no-rdoc
|
21
|
+
|
22
|
+
echo
|
23
|
+
echo 'Bootstrapping Chef - done'
|
24
|
+
echo '-------------------------'
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#
|
2
|
+
# Cookbook Name:: ec2-ebs
|
3
|
+
# Recipe:: default
|
4
|
+
#
|
5
|
+
# Assumes volumes are preformatted by YOU or specified as
|
6
|
+
# # in cluster:
|
7
|
+
# server :log_a, :zone => :eu_west_1a, :disk => {:sdf => ["vol-abcd1234", :format]}
|
8
|
+
# # in chef_dna:
|
9
|
+
# :ebs_volumes => [
|
10
|
+
# {:device => "sdf", :path => "/apps", :format => format_disk_on_device?("sdf")}
|
11
|
+
# ],
|
12
|
+
|
13
|
+
|
14
|
+
for ebs_volume in (node["ebs_volumes"] || [])
|
15
|
+
if (`grep /dev/#{ebs_volume[:device]} /etc/fstab` == "")
|
16
|
+
while not File.exists?("/dev/#{ebs_volume[:device]}")
|
17
|
+
Chef::Log.info("EBS volume device /dev/#{ebs_volume[:device]} not ready...")
|
18
|
+
sleep 5
|
19
|
+
end
|
20
|
+
|
21
|
+
execute "format #{ebs_volume[:device]}" do
|
22
|
+
command "mkfs -t ext3 -F /dev/#{ebs_volume[:device]}"
|
23
|
+
only_if { ebs_volume[:format] }
|
24
|
+
end
|
25
|
+
|
26
|
+
directory ebs_volume[:path] do
|
27
|
+
owner 'root'
|
28
|
+
group 'root'
|
29
|
+
mode 0755
|
30
|
+
end
|
31
|
+
|
32
|
+
mount ebs_volume[:path] do
|
33
|
+
device "/dev/#{ebs_volume[:device]}"
|
34
|
+
fstype "ext3"
|
35
|
+
action [:mount, :enable]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/awsborn/awsborn.rb
CHANGED
@@ -3,7 +3,7 @@ module Awsborn
|
|
3
3
|
class ServerError < StandardError ; end
|
4
4
|
|
5
5
|
class << self
|
6
|
-
attr_writer :access_key_id, :secret_access_key, :logger, :remote_chef_path
|
6
|
+
attr_writer :access_key_id, :secret_access_key, :logger, :remote_chef_path, :chef_log_level
|
7
7
|
attr_accessor :verbose
|
8
8
|
|
9
9
|
Awsborn.verbose = true
|
@@ -44,7 +44,7 @@ module Awsborn
|
|
44
44
|
|
45
45
|
def logger
|
46
46
|
unless defined? @logger
|
47
|
-
dir = [
|
47
|
+
dir = [Dir.pwd, '/tmp'].find { |d| File.writable?(d) }
|
48
48
|
if dir
|
49
49
|
file = File.open(File.join(dir, 'awsborn.log'), 'a')
|
50
50
|
file.sync = true
|
@@ -80,6 +80,10 @@ module Awsborn
|
|
80
80
|
def verbose_output(message)
|
81
81
|
puts message if Awsborn.verbose
|
82
82
|
end
|
83
|
-
|
83
|
+
|
84
|
+
def chef_log_level
|
85
|
+
@chef_log_level || :info
|
86
|
+
end
|
87
|
+
|
84
88
|
end
|
85
89
|
end
|
@@ -26,10 +26,11 @@ module Awsborn
|
|
26
26
|
tries += 1
|
27
27
|
try_update
|
28
28
|
rescue SecurityError => e
|
29
|
-
if tries <
|
29
|
+
if tries < 8
|
30
30
|
logger.debug e.message
|
31
|
-
|
32
|
-
|
31
|
+
sleep_time = [2**tries, 30].min
|
32
|
+
logger.debug "Fingerprint try #{tries} failed, sleeping #{sleep_time} seconds"
|
33
|
+
sleep(sleep_time)
|
33
34
|
retry
|
34
35
|
else
|
35
36
|
raise e
|
data/lib/awsborn/rake.rb
CHANGED
@@ -7,36 +7,48 @@ module Awsborn
|
|
7
7
|
default_klass.clusters.first
|
8
8
|
end
|
9
9
|
|
10
|
-
desc "Start all servers (if needed) and deploy with chef"
|
11
|
-
task :
|
10
|
+
desc "Default: Start all servers (if needed) and deploy with chef."
|
11
|
+
task :all => [:start, "chef:run"]
|
12
|
+
task :default => :all
|
12
13
|
|
13
|
-
desc "Start all servers"
|
14
|
-
task :start do
|
15
|
-
|
14
|
+
desc "Start all servers (or host=name1,name2)."
|
15
|
+
task :start do |t,args|
|
16
|
+
hosts = args[:host] && args[:host].split(',')
|
17
|
+
default_cluster.launch hosts
|
16
18
|
end
|
17
19
|
|
18
|
-
desc "Run chef on all servers"
|
19
|
-
task :chef =>
|
20
|
-
|
21
|
-
|
20
|
+
desc "Run chef on all servers (or host=name1,name2)."
|
21
|
+
task :chef => "chef:run"
|
22
|
+
|
23
|
+
namespace :chef do
|
24
|
+
task :run => [:check_syntax] do |t,args|
|
25
|
+
hosts = args[:host] && args[:host].split(',')
|
26
|
+
default_cluster.each do |server|
|
27
|
+
server.cook if hosts.nil? || hosts.include?(server.name.to_s)
|
28
|
+
end
|
22
29
|
end
|
23
|
-
end
|
24
|
-
task :cook => [:chef]
|
25
30
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
31
|
+
desc "Run chef on all servers with log_level debug."
|
32
|
+
task :debug => [:set_chef_debug, :run]
|
33
|
+
task :set_chef_debug do
|
34
|
+
Awsborn.chef_log_level = :debug
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "Check your cookbooks and config files for syntax errors."
|
38
|
+
task :check_syntax do
|
39
|
+
Dir["**/*.rb"].each do |recipe|
|
40
|
+
RakeFileUtils.verbose(false) do
|
41
|
+
sh %{ruby -c #{recipe} > /dev/null} do |ok, res|
|
42
|
+
raise "Syntax error in #{recipe}" if not ok
|
43
|
+
end
|
32
44
|
end
|
33
45
|
end
|
34
46
|
end
|
35
|
-
end
|
36
47
|
|
37
|
-
|
38
|
-
|
39
|
-
|
48
|
+
desc "Create a new cookbook (with cookbook=name)."
|
49
|
+
task :new_cookbook do
|
50
|
+
create_cookbook("cookbooks")
|
51
|
+
end
|
40
52
|
end
|
41
53
|
|
42
54
|
def create_cookbook(dir)
|
data/lib/awsborn/server.rb
CHANGED
@@ -57,7 +57,7 @@ module Awsborn
|
|
57
57
|
|
58
58
|
def running?
|
59
59
|
map = {}
|
60
|
-
|
60
|
+
disk_volume_ids.each { |vol_id| map[vol_id] = ec2.instance_id_for_volume(vol_id) }
|
61
61
|
ids = map.values.uniq
|
62
62
|
if ids.size > 1
|
63
63
|
raise ServerError, "Volumes for #{self.class.name}:#{name} are connected to several instances: #{map.inspect}"
|
@@ -153,13 +153,14 @@ module Awsborn
|
|
153
153
|
logger.debug "Bootstrapping #{name}"
|
154
154
|
script = bootstrap_script
|
155
155
|
basename = File.basename(script)
|
156
|
-
system "scp #{script} root@#{
|
157
|
-
system "ssh root@#{
|
156
|
+
system "scp #{script} root@#{host_name}:/tmp"
|
157
|
+
system "ssh root@#{host_name} 'cd /tmp && chmod 700 #{basename} && ./#{basename}'"
|
158
158
|
end
|
159
159
|
|
160
160
|
def attach_volumes
|
161
161
|
logger.debug "Attaching volumes #{disk.values.join(', ')} to #{name}"
|
162
|
-
disk.each_pair do |device,
|
162
|
+
disk.each_pair do |device, str_or_ary|
|
163
|
+
volume = str_or_ary.is_a?(Array) ? str_or_ary.first : str_or_ary
|
163
164
|
device = "/dev/#{device}" if device.is_a?(Symbol) || ! device.match('/')
|
164
165
|
res = ec2.attach_volume(volume, device)
|
165
166
|
end
|
@@ -181,7 +182,7 @@ module Awsborn
|
|
181
182
|
def run_chef
|
182
183
|
logger.info "Running chef on #{host_name}"
|
183
184
|
# Absolute path to config files to avoid a nasty irrational bug.
|
184
|
-
sh "ssh root@#{host_name} \"cd #{Awsborn.remote_chef_path}; chef-solo -c #{Awsborn.remote_chef_path}/config/solo.rb -j #{Awsborn.remote_chef_path}/config/dna.json\""
|
185
|
+
sh "ssh root@#{host_name} \"cd #{Awsborn.remote_chef_path}; chef-solo -l #{Awsborn.chef_log_level} -c #{Awsborn.remote_chef_path}/config/solo.rb -j #{Awsborn.remote_chef_path}/config/dna.json\""
|
185
186
|
end
|
186
187
|
|
187
188
|
def ec2
|
@@ -189,17 +190,33 @@ module Awsborn
|
|
189
190
|
end
|
190
191
|
|
191
192
|
begin :accessors
|
192
|
-
attr_accessor :name, :
|
193
|
+
attr_accessor :name, :logger
|
193
194
|
def host_name= (string)
|
194
195
|
logger.debug "Setting host_name of #{name} to #{string}"
|
195
196
|
@host_name = string
|
196
197
|
end
|
198
|
+
def host_name
|
199
|
+
unless @host_name
|
200
|
+
logger.debug 'Looking up DNS name from volume ID'
|
201
|
+
self.host_name = aws_dns_name
|
202
|
+
logger.debug "got DNS name #{@host_name}"
|
203
|
+
update_known_hosts
|
204
|
+
end
|
205
|
+
@host_name
|
206
|
+
end
|
197
207
|
def zone
|
198
208
|
@options[:zone]
|
199
209
|
end
|
200
210
|
def disk
|
201
211
|
@options[:disk]
|
202
212
|
end
|
213
|
+
def disk_volume_ids
|
214
|
+
disk.values.map { |str_or_ary| str_or_ary.is_a?(Array) ? str_or_ary.first : str_or_ary }
|
215
|
+
end
|
216
|
+
def format_disk_on_device? (device)
|
217
|
+
volume = disk[device.to_sym]
|
218
|
+
volume.is_a?(Array) && volume.last == :format
|
219
|
+
end
|
203
220
|
def image_id
|
204
221
|
self.class.image_id
|
205
222
|
end
|
@@ -22,8 +22,9 @@ module Awsborn
|
|
22
22
|
@instances << instance
|
23
23
|
end
|
24
24
|
|
25
|
-
def launch
|
26
|
-
|
25
|
+
def launch (names)
|
26
|
+
requested = names.nil? ? @instances : @instances.select { |s| names.include?(s.name.to_s) }
|
27
|
+
running, missing = requested.partition { |e| e.running? }
|
27
28
|
refresh_running(running) if running.any?
|
28
29
|
start_missing_instances(missing) if missing.any?
|
29
30
|
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 4
|
8
|
+
- 0
|
9
|
+
version: 0.4.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- David Vrensk
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-09-07 00:00:00 +02:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -101,6 +101,8 @@ files:
|
|
101
101
|
- README.mdown
|
102
102
|
- Rakefile
|
103
103
|
- VERSION
|
104
|
+
- contrib/chef-bootstrap.sh
|
105
|
+
- contrib/cookbooks/ec2-ebs/recipes/default.rb
|
104
106
|
- lib/awsborn.rb
|
105
107
|
- lib/awsborn/awsborn.rb
|
106
108
|
- lib/awsborn/ec2.rb
|