awsborn 0.1.1 → 0.2.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
@@ -30,6 +30,7 @@ that are not running.
30
30
  security_group 'Basic web'
31
31
  keys 'keys/*.pub'
32
32
  bootstrap_script 'chef-bootstrap.sh'
33
+ monitor true
33
34
  end
34
35
 
35
36
  log_servers = LogServer.cluster do
@@ -179,6 +180,9 @@ attached and the other isn't, one of these things will happen:
179
180
  * Hack RightAws to verify certificates.
180
181
  * Elastic Load Balancing.
181
182
  * Launch servers in parallel.
183
+ * Make `image_id` a hash with different AMIs for different instance types.
184
+ * Make `image_id` overridable per server.
185
+
182
186
 
183
187
  ## Note on Patches/Pull Requests
184
188
 
data/Rakefile CHANGED
@@ -10,7 +10,7 @@ begin
10
10
  gem.email = "david@icehouse.se"
11
11
  gem.homepage = "http://github.com/icehouse/awsborn"
12
12
  gem.authors = ["David Vrensk"]
13
- gem.add_dependency "right_aws", ">= 1.10.0"
13
+ gem.add_dependency "icehouse-right_aws", ">= 1.11.0"
14
14
  gem.add_development_dependency "rspec", ">= 1.2.9"
15
15
  gem.add_development_dependency "webmock", ">= 0.9.1"
16
16
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.2.0
@@ -1,12 +1,13 @@
1
1
  module Awsborn
2
2
  class SecurityError < StandardError ; end
3
+ class ServerError < StandardError ; end
3
4
 
4
5
  class << self
5
6
  attr_writer :access_key_id, :secret_access_key, :logger
6
7
  attr_accessor :verbose
7
-
8
+
8
9
  Awsborn.verbose = true
9
-
10
+
10
11
  def access_key_id
11
12
  @access_key_id ||= ENV['AMAZON_ACCESS_KEY_ID']
12
13
  end
data/lib/awsborn/ec2.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  module Awsborn
2
2
  class Ec2
3
-
3
+ extend Forwardable
4
+ def_delegators :Awsborn, :logger
5
+
4
6
  attr_accessor :instance_id
5
7
 
6
8
  def connection
@@ -45,17 +47,12 @@ module Awsborn
45
47
  def delete_key_pair (key_pair)
46
48
  connection.delete_key_pair(key_pair.name)
47
49
  end
48
-
49
- def volume_has_instance? (volume_id)
50
+
51
+ def instance_id_for_volume (volume_id)
50
52
  response = connection.describe_volumes(volume_id).first
51
- if response[:aws_status] == 'in-use'
52
- self.instance_id = response[:aws_instance_id]
53
- true
54
- else
55
- false
56
- end
53
+ response[:aws_status] == 'in-use' ? response[:aws_instance_id] : nil
57
54
  end
58
-
55
+
59
56
  IP4_REGEXP = /^(\d{1,3}\.){3}\d{1,3}$/
60
57
 
61
58
  def associate_address (address)
@@ -83,5 +80,20 @@ module Awsborn
83
80
  def attach_volume (volume, device)
84
81
  connection.attach_volume(volume, instance_id, device)
85
82
  end
83
+
84
+ def monitoring?
85
+ %w[enabled pending].include?(describe_instance[:monitoring_state])
86
+ end
87
+
88
+ def monitor
89
+ logger.debug "Activating monitoring for #{instance_id}"
90
+ connection.monitor_instances(instance_id)
91
+ end
92
+
93
+ def unmonitor
94
+ logger.debug "Deactivating monitoring for #{instance_id}"
95
+ connection.unmonitor_instances(instance_id)
96
+ end
97
+
86
98
  end
87
99
  end
@@ -36,6 +36,10 @@ module Awsborn
36
36
  @bootstrap_script = args.first unless args.empty?
37
37
  @bootstrap_script
38
38
  end
39
+ def monitor (*args)
40
+ @monitor = args.first unless args.empty?
41
+ @monitor
42
+ end
39
43
 
40
44
  def cluster (&block)
41
45
  ServerCluster.build self, &block
@@ -45,12 +49,37 @@ module Awsborn
45
49
  end
46
50
  end
47
51
 
48
- def one_of_my_disks_is_attached_to_a_running_instance?
49
- vol_id = disk.values.first
50
- ec2.volume_has_instance?(vol_id)
52
+ def running?
53
+ map = {}
54
+ disk.values.each { |vol_id| map[vol_id] = ec2.instance_id_for_volume(vol_id) }
55
+ ids = map.values.uniq
56
+ if ids.size > 1
57
+ raise ServerError, "Volumes for #{self.class.name}:#{name} are connected to several instances: #{map.inspect}"
58
+ end
59
+ ec2.instance_id = ids.first
51
60
  end
52
- alias :running? :one_of_my_disks_is_attached_to_a_running_instance?
53
61
 
62
+ def refresh
63
+ start_or_stop_monitoring unless monitor.nil?
64
+ associate_address if elastic_ip
65
+
66
+ begin
67
+ update_known_hosts
68
+ install_ssh_keys if keys
69
+ rescue SecurityError => e
70
+ logger.warn "Could not update known_hosts for #{name}:"
71
+ logger.warn e
72
+ end
73
+ end
74
+
75
+ def start_or_stop_monitoring
76
+ if monitor && ! ec2.monitoring?
77
+ ec2.monitor
78
+ elsif ec2.monitoring? && ! monitor
79
+ ec2.unmonitor
80
+ end
81
+ end
82
+
54
83
  def start (key_pair)
55
84
  launch_instance(key_pair)
56
85
 
@@ -71,7 +100,8 @@ module Awsborn
71
100
  :instance_type => constant(instance_type),
72
101
  :availability_zone => constant(zone),
73
102
  :key_name => key_pair.name,
74
- :group_ids => security_group
103
+ :group_ids => security_group,
104
+ :monitor_enabled => monitor
75
105
  )
76
106
  logger.debug @launch_response
77
107
 
@@ -83,33 +113,42 @@ module Awsborn
83
113
  KnownHostsUpdater.update_for_server self
84
114
  end
85
115
 
86
- def install_ssh_keys (temp_key_pair)
87
- cmd = "ssh -i #{temp_key_pair.path} #{sudo_user || 'root'}@#{aws_dns_name} 'cat > .ssh/authorized_keys'"
88
- logger.debug cmd
89
- IO.popen(cmd, "w") do |pipe|
116
+ def install_ssh_keys (temp_key_pair = nil)
117
+ logger.debug "Installing ssh keys on #{name}"
118
+ raise ArgumentError, "No host_name for #{name}" unless host_name
119
+ install_ssh_keys_for_sudo_user_or_root (temp_key_pair)
120
+ copy_sudo_users_keys_to_root if sudo_user
121
+ end
122
+
123
+ def install_ssh_keys_for_sudo_user_or_root (temp_key_pair)
124
+ current_key = "-i #{temp_key_pair.path}" if temp_key_pair
125
+ IO.popen("ssh #{current_key} #{sudo_user || 'root'}@#{host_name} 'cat > .ssh/authorized_keys'", "w") do |pipe|
90
126
  pipe.puts key_data
91
127
  end
92
- if sudo_user
93
- system("ssh #{sudo_user}@#{aws_dns_name} 'sudo cp .ssh/authorized_keys /root/.ssh/authorized_keys'")
94
- end
95
128
  end
96
-
129
+
97
130
  def key_data
98
131
  Dir[*keys].inject([]) do |memo, file_name|
99
132
  memo + File.readlines(file_name).map { |line| line.chomp }
100
133
  end.join("\n")
101
134
  end
102
135
 
136
+ def copy_sudo_users_keys_to_root
137
+ system("ssh #{sudo_user}@#{host_name} 'sudo cp .ssh/authorized_keys /root/.ssh/authorized_keys'")
138
+ end
139
+
103
140
  def path_relative_to_script (path)
104
141
  File.join(File.dirname(File.expand_path($0)), path)
105
142
  end
106
143
 
107
144
  def associate_address
145
+ logger.debug "Associating address #{elastic_ip} to #{name}"
108
146
  ec2.associate_address(elastic_ip)
109
147
  self.host_name = elastic_ip
110
148
  end
111
149
 
112
150
  def bootstrap
151
+ logger.debug "Bootstrapping #{name}"
113
152
  script = path_relative_to_script(bootstrap_script)
114
153
  basename = File.basename(script)
115
154
  system "scp #{script} root@#{elastic_ip}:/tmp"
@@ -117,6 +156,7 @@ module Awsborn
117
156
  end
118
157
 
119
158
  def attach_volumes
159
+ logger.debug "Attaching volumes #{disk.values.join(', ')} to #{name}"
120
160
  disk.each_pair do |device, volume|
121
161
  device = "/dev/#{device}" if device.is_a?(Symbol) || ! device.match('/')
122
162
  res = ec2.attach_volume(volume, device)
@@ -129,6 +169,10 @@ module Awsborn
129
169
 
130
170
  begin :accessors
131
171
  attr_accessor :name, :host_name, :logger
172
+ def host_name= (string)
173
+ logger.debug "Setting host_name of #{name} to #{string}"
174
+ @host_name = string
175
+ end
132
176
  def zone
133
177
  @options[:zone]
134
178
  end
@@ -153,6 +197,9 @@ module Awsborn
153
197
  def keys
154
198
  @options[:keys] || self.class.keys
155
199
  end
200
+ def monitor
201
+ @options[:monitor] || self.class.monitor
202
+ end
156
203
  def elastic_ip
157
204
  @options[:ip]
158
205
  end
@@ -23,19 +23,19 @@ module Awsborn
23
23
  end
24
24
 
25
25
  def launch
26
- start_missing_instances
26
+ running, missing = @instances.partition { |e| e.running? }
27
+ refresh_running(running) if running.any?
28
+ start_missing_instances(missing) if missing.any?
27
29
  end
28
30
 
29
- def start_missing_instances
30
- to_start = find_missing_instances
31
- return if to_start.empty?
32
- generate_key_pair(to_start)
33
- to_start.each { |e| e.start(@key_pair) }
34
- delete_key_pair(to_start)
31
+ def refresh_running (instances)
32
+ instances.each { |e| e.refresh }
35
33
  end
36
34
 
37
- def find_missing_instances
38
- @instances.reject { |e| e.running? }
35
+ def start_missing_instances (instances)
36
+ generate_key_pair(instances)
37
+ instances.each { |e| e.start(@key_pair) }
38
+ delete_key_pair(instances)
39
39
  end
40
40
 
41
41
  def generate_key_pair (instances)
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 1
8
- - 1
9
- version: 0.1.1
7
+ - 2
8
+ - 0
9
+ version: 0.2.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - David Vrensk
@@ -14,11 +14,11 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-04-13 00:00:00 +02:00
17
+ date: 2010-04-14 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
- name: right_aws
21
+ name: icehouse-right_aws
22
22
  prerelease: false
23
23
  requirement: &id001 !ruby/object:Gem::Requirement
24
24
  requirements:
@@ -26,9 +26,9 @@ dependencies:
26
26
  - !ruby/object:Gem::Version
27
27
  segments:
28
28
  - 1
29
- - 10
29
+ - 11
30
30
  - 0
31
- version: 1.10.0
31
+ version: 1.11.0
32
32
  type: :runtime
33
33
  version_requirements: *id001
34
34
  - !ruby/object:Gem::Dependency