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 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 keys. When the servers are running,
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
- See `rake -T` for more options.
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.3.9
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
@@ -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 = [File.dirname(File.expand_path($0)), '/tmp'].find { |d| File.writable?(d) }
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 < 5
29
+ if tries < 8
30
30
  logger.debug e.message
31
- logger.debug "Sleeping, try #{tries}"
32
- sleep([2**tries, 15].min)
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 :default => [:start, :chef]
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
- default_cluster.launch
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 => [:check_syntax] do
20
- default_cluster.each do |server|
21
- server.cook
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
- desc "Check your cookbooks and config files for syntax errors"
27
- task :check_syntax do
28
- Dir["**/*.rb"].each do |recipe|
29
- RakeFileUtils.verbose(false) do
30
- sh %{ruby -c #{recipe} > /dev/null} do |ok, res|
31
- raise "Syntax error in #{recipe}" if not ok
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
- desc "Create a new cookbook (with cookbook=name)"
38
- task :new_cookbook do
39
- create_cookbook("cookbooks")
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)
@@ -57,7 +57,7 @@ module Awsborn
57
57
 
58
58
  def running?
59
59
  map = {}
60
- disk.values.each { |vol_id| map[vol_id] = ec2.instance_id_for_volume(vol_id) }
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@#{elastic_ip}:/tmp"
157
- system "ssh root@#{elastic_ip} 'cd /tmp && chmod 700 #{basename} && ./#{basename}'"
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, volume|
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, :host_name, :logger
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
- running, missing = @instances.partition { |e| e.running? }
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
- - 3
8
- - 9
9
- version: 0.3.9
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-06-09 00:00:00 +02:00
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