awsborn 0.1.1 → 0.2.0

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