awsborn 0.3.9 → 0.4.0
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/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
|