rudy 0.7.1 → 0.7.3

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES.txt CHANGED
@@ -8,6 +8,13 @@ RUDY, CHANGES
8
8
  * TODO: Tests for AWS HTTPS
9
9
 
10
10
 
11
+ #### 0.7.2 (2009-04-04) ###############################
12
+
13
+ * FIXED: cli/routine.rb release method wasn't sending command alias (which broke rerelease)
14
+ * ADDED: global.offline for being cool when Internet is down
15
+ * ADDED: Better handling in aws/sdb when call returns nil (Internet is down)
16
+
17
+
11
18
  #### 0.7.1 (2009-04-04) ###############################
12
19
 
13
20
  * FIXED: rudy wasn't honouring -C option for specifying a config file
data/Rudyfile CHANGED
@@ -123,7 +123,7 @@ routines do
123
123
 
124
124
  shutdown do # $ rudy shutdown
125
125
  before :root do # Run remote SSH commands before shutdown
126
- mysqld_initd
126
+ #mysqld_initd
127
127
  end
128
128
 
129
129
  disks do
data/bin/rudy-ec2 CHANGED
@@ -23,6 +23,8 @@ require 'drydock'
23
23
  module RudyCLI_EC2
24
24
  extend Drydock
25
25
 
26
+ debug :off
27
+ default :instances
26
28
 
27
29
  # ----------------------------------- AMAZON EC2 COMMANDS --------
28
30
  # ------------------------------------------------------------------
@@ -47,6 +49,8 @@ module RudyCLI_EC2
47
49
 
48
50
  about "Amazon EC2 instance console output"
49
51
  usage "rudy-ec2 console [-g group] [instance ID]"
52
+ usage "rudy-ec2 [-k path/2/privatekey] console [instance ID]"
53
+ usage "NOTE: Private key is required only for Windows instances"
50
54
  option :g, :group, String, "A security group name"
51
55
  argv :awsid
52
56
  command :consoles => Rudy::CLI::AWS::EC2::Instances
@@ -54,8 +58,8 @@ module RudyCLI_EC2
54
58
  command_alias :consoles, :c
55
59
 
56
60
  about "Copy files to or from machines."
57
- usage "rudy-ec2 copy [-p] [-r] [-u user] [-k path/2/privatekey] source target"
58
- usage "rudy-ec2 upload -k path/2/privatekey -u username local-source target"
61
+ usage "rudy-ec2 copy [-p] [-r] source target"
62
+ usage "rudy-ec2 [-u user] [-k path/2/privatekey] upload local-source target"
59
63
  usage "rudy-ec2 download remote-source target"
60
64
  usage "NOTE: Use quotes when using a tilda or asterisk in remote paths ('~/')."
61
65
  usage "rudy-ec2 download '~/*' /tmp/"
@@ -207,12 +211,7 @@ module RudyCLI_EC2
207
211
  command_alias :zones, :zone
208
212
  command_alias :zones, :z
209
213
 
210
-
211
- # -------------------------------- RUDY-EC2 MISCELLANEOUS --------
212
- # ------------------------------------------------------------------
213
-
214
- default :instances
215
- debug :off
214
+
216
215
 
217
216
  end
218
217
 
data/lib/annoy.rb CHANGED
@@ -186,9 +186,12 @@ class Annoy
186
186
  begin
187
187
  success = Timeout::timeout(period || @@period) do
188
188
  regexp &&= Regexp.new regexp
189
- writer.print msg
190
- writer.flush if writer.respond_to?(:flush)
191
- response = Annoy.get_response
189
+ highline = HighLine.new
190
+ response = highline.ask(msg) { |q|
191
+ q.echo = '*' # Don't display response
192
+ q.overwrite = true # Erase the question afterwards
193
+ q.whitespace = :strip # Remove whitespace from the response
194
+ }
192
195
  regexp.match(response)
193
196
  end
194
197
  rescue Timeout::Error => ex
@@ -197,6 +200,27 @@ class Annoy
197
200
  end
198
201
  end
199
202
 
203
+
204
+ def Annoy.timed_display(msg, writer, period=nil)
205
+ return true unless STDIN.tty? # Only ask a question if there's a human
206
+ if Annoy.skip?
207
+ #writer.puts msg
208
+ return true
209
+ end
210
+ begin
211
+ period ||= @@period
212
+ success = Timeout::timeout(period) do
213
+ writer.puts "Message will display for #{period} seconds"
214
+ writer.print msg
215
+ writer.flush if writer.respond_to?(:flush)
216
+ sleep period+1
217
+ end
218
+ rescue Timeout::Error => ex
219
+ writer.print "\r" << ' '*msg.size
220
+ end
221
+
222
+ true
223
+ end
200
224
 
201
225
  private
202
226
  def Annoy.get_response(writer=STDOUT)
data/lib/rudy.rb CHANGED
@@ -45,7 +45,7 @@ module Rudy
45
45
  unless defined?(MAJOR)
46
46
  MAJOR = 0.freeze
47
47
  MINOR = 7.freeze
48
- TINY = 1.freeze
48
+ TINY = 3.freeze
49
49
  end
50
50
  def self.to_s; [MAJOR, MINOR, TINY].join('.'); end
51
51
  def self.to_f; self.to_s.to_f; end
data/lib/rudy/aws.rb CHANGED
@@ -23,6 +23,7 @@ module Rudy
23
23
  end
24
24
 
25
25
  module ObjectBase
26
+ include Rudy::Huxtable
26
27
 
27
28
  protected
28
29
 
@@ -52,9 +53,9 @@ module Rudy
52
53
  rescue Timeout::Error => ex
53
54
  STDERR.puts "Timeout (#{timeout}): #{ex.message}!"
54
55
  rescue SocketError => ex
55
- raise SocketError, "Check your Internets!"
56
56
  #STDERR.puts ex.message
57
57
  #STDERR.puts ex.backtrace
58
+ raise SocketError, "Check your Internets!" unless @@global.offline
58
59
  ensure
59
60
  response ||= default
60
61
  end
@@ -30,7 +30,14 @@ module Rudy::AWS
30
30
 
31
31
  def to_s(with_title=false)
32
32
  lines = []
33
- lines << "%s (%s)" % [liner_note, @groups.join(', ')]
33
+ if @groups
34
+ gpstr = [@groups].flatten.compact.join(', ')
35
+ gpstr &&= "(#{gpstr})"
36
+ else
37
+ gpstr = ''
38
+ end
39
+
40
+ lines << "%s %s" % [liner_note, gpstr]
34
41
  #if self.running?
35
42
  # k, g = @keyname || 'no-keypair', self.groups.join(', ')
36
43
  # lines << @@sformat % %w{zone size ami keyname groups} if with_title
data/lib/rudy/aws/sdb.rb CHANGED
@@ -98,18 +98,20 @@ module Rudy
98
98
 
99
99
  doc = call(:get, params)
100
100
  results = []
101
- REXML::XPath.each(doc, "//Item") do |item|
102
- name = REXML::XPath.first(item, './Name/text()').to_s
101
+ if doc
102
+ REXML::XPath.each(doc, "//Item") do |item|
103
+ name = REXML::XPath.first(item, './Name/text()').to_s
103
104
 
104
- attributes = {'Name' => name}
105
- REXML::XPath.each(item, "./Attribute") do |attr|
106
- key = REXML::XPath.first(attr, './Name/text()').to_s
107
- value = REXML::XPath.first(attr, './Value/text()').to_s
108
- ( attributes[key] ||= [] ) << value
105
+ attributes = {'Name' => name}
106
+ REXML::XPath.each(item, "./Attribute") do |attr|
107
+ key = REXML::XPath.first(attr, './Name/text()').to_s
108
+ value = REXML::XPath.first(attr, './Value/text()').to_s
109
+ ( attributes[key] ||= [] ) << value
110
+ end
111
+ results << attributes
109
112
  end
110
- results << attributes
113
+ #return results, REXML::XPath.first(doc, '//NextToken/text()').to_s
111
114
  end
112
- #return results, REXML::XPath.first(doc, '//NextToken/text()').to_s
113
115
 
114
116
  hash_results = {}
115
117
  results.each do |item|
@@ -134,8 +136,10 @@ module Rudy
134
136
 
135
137
  doc = call(:get, params)
136
138
  results = []
137
- REXML::XPath.each(doc, '//ItemName/text()') do |item|
138
- results << item.to_s
139
+ if doc
140
+ REXML::XPath.each(doc, '//ItemName/text()') do |item|
141
+ results << item.to_s
142
+ end
139
143
  end
140
144
 
141
145
  #return results, REXML::XPath.first(doc, '//NextToken/text()').to_s
@@ -159,18 +163,20 @@ module Rudy
159
163
 
160
164
  doc = call(:get, params)
161
165
  results = []
162
- REXML::XPath.each(doc, "//Item") do |item|
163
- name = REXML::XPath.first(item, './Name/text()').to_s
166
+ if doc
167
+ REXML::XPath.each(doc, "//Item") do |item|
168
+ name = REXML::XPath.first(item, './Name/text()').to_s
164
169
 
165
- attributes = {'Name' => name}
166
- REXML::XPath.each(item, "./Attribute") do |attr|
167
- key = REXML::XPath.first(attr, './Name/text()').to_s
168
- value = REXML::XPath.first(attr, './Value/text()').to_s
169
- ( attributes[key] ||= [] ) << value
170
+ attributes = {'Name' => name}
171
+ REXML::XPath.each(item, "./Attribute") do |attr|
172
+ key = REXML::XPath.first(attr, './Name/text()').to_s
173
+ value = REXML::XPath.first(attr, './Value/text()').to_s
174
+ ( attributes[key] ||= [] ) << value
175
+ end
176
+ results << attributes
170
177
  end
171
- results << attributes
178
+ #return results, REXML::XPath.first(doc, '//NextToken/text()').to_s
172
179
  end
173
- #return results, REXML::XPath.first(doc, '//NextToken/text()').to_s
174
180
 
175
181
  hash_results = {}
176
182
  results.each do |item|
@@ -216,10 +222,12 @@ module Rudy
216
222
  }
217
223
  )
218
224
  attributes = {}
219
- REXML::XPath.each(doc, "//Attribute") do |attr|
220
- key = REXML::XPath.first(attr, './Name/text()').to_s
221
- value = REXML::XPath.first(attr, './Value/text()').to_s
222
- ( attributes[key] ||= [] ) << value
225
+ if doc
226
+ REXML::XPath.each(doc, "//Attribute") do |attr|
227
+ key = REXML::XPath.first(attr, './Name/text()').to_s
228
+ value = REXML::XPath.first(attr, './Value/text()').to_s
229
+ ( attributes[key] ||= [] ) << value
230
+ end
223
231
  end
224
232
  attributes = nil if attributes.empty?
225
233
  attributes
data/lib/rudy/cli.rb CHANGED
@@ -154,6 +154,7 @@ module Rudy
154
154
  global :C, :config, String, "Specify another configuration file to read (ie: #{Rudy::CONFIG_FILE})"
155
155
  global :Y, :yes, "Assume a correct answer to confirmation questions"
156
156
  global :q, :quiet, "Run with less output"
157
+ global :O, :offline, "Be cool about the internet being down"
157
158
  global :v, :verbose, "Increase verbosity of output (i.e. -v or -vv or -vvv)" do
158
159
  @verbose ||= 0
159
160
  @verbose += 1
@@ -6,7 +6,7 @@ module AWS; module EC2;
6
6
 
7
7
  def status_valid?
8
8
  avail = Rudy::Utils.service_available?('status.aws.amazon.com', 80, 5)
9
- raise ServiceUnavailable, 'status.aws.amazon.com' unless avail
9
+ raise ServiceUnavailable, 'status.aws.amazon.com' unless @@global.offline || avail
10
10
  true
11
11
  end
12
12
  def status
@@ -14,12 +14,9 @@ module AWS; module EC2;
14
14
  end
15
15
  def create_groups
16
16
  opts = check_options
17
- puts "Creating #{@argv.name}"
18
-
19
17
  execute_action {
20
18
  @rgroups.create(@argv.name, @option.description, opts[:addresses], opts[:ports], opts[:protocols])
21
19
  }
22
-
23
20
  @rgroups.list(@argv.name) do |group|
24
21
  puts @@global.verbose > 0 ? group.inspect : group.dump(@@global.format)
25
22
  end
@@ -113,6 +113,10 @@ module AWS; module EC2;
113
113
 
114
114
  def consoles_valid?
115
115
  @rinst = Rudy::AWS::EC2::Instances.new(@@global.accesskey, @@global.secretkey, @@global.region)
116
+ if @@global.pkey
117
+ raise "Cannot find file #{@@global.pkey}" unless File.exists?(@@global.pkey)
118
+ raise "Insecure permissions for #{@@global.pkey}" unless (File.stat(@@global.pkey).mode & 600) == 0
119
+ end
116
120
  raise "No instances" unless @rinst.any?
117
121
  true
118
122
  end
@@ -123,11 +127,35 @@ module AWS; module EC2;
123
127
  opts[:id] &&= [opts[:id]].flatten
124
128
 
125
129
  lt = @rinst.list_group(opts[:group], :any, opts[:id]) do |inst|
126
- puts '-'*50
127
- puts "Console for: #{inst.liner_note}", $/
130
+ puts instance_separator(inst.dns_public || inst.state, inst.awsid)
128
131
  console = @rinst.console(inst.awsid)
129
132
  output = console ? Base64.decode64(console) : "Unavailable"
130
- puts output.noansi # Remove color and clear, etc...
133
+
134
+ # The linux console can include ANSI escape codes for color,
135
+ # clear screen etc... We strip them out to get rid of the
136
+ # clear specifically. Otherwise the display is messed!
137
+ output &&= output.noansi
138
+
139
+ puts output
140
+
141
+ if output.match(/<Password>(.+)<\/Password>/m) # /m, match multiple lines
142
+ puts
143
+ if @@global.pkey
144
+ encrtypted_text = ($1 || '').strip
145
+ k = Rye::Key.from_file(@@global.pkey)
146
+ pword = k.decrypt(encrtypted_text)
147
+ ret = Annoy.pose_question("Display password?\a ", /yes|y|ya|sure|you bet!/i, STDERR)
148
+ if ret
149
+ answer = "%s: %s" % ['password', pword]
150
+ Annoy.timed_display(answer, STDERR, 10)
151
+ end
152
+ puts
153
+ else
154
+ puts "Please supply a private key path to decode the administrator password"
155
+ puts "rudy-ec2 -k path/2/privatekey console [-g group] [instance ID]"
156
+ end
157
+ end
158
+
131
159
  end
132
160
 
133
161
  end
@@ -184,6 +212,9 @@ module AWS; module EC2;
184
212
  status
185
213
  end
186
214
 
215
+ def instance_separator(name, awsid)
216
+ ('%s %-63s awsid: %s ' % [$/, name, awsid]).att(:reverse)
217
+ end
187
218
 
188
219
  end
189
220
 
@@ -12,7 +12,7 @@ module AWS; module EC2;
12
12
  def create_keypairs
13
13
  rkey = Rudy::AWS::EC2::KeyPairs.new(@@global.accesskey, @@global.secretkey, @@global.region)
14
14
  kp = execute_action { rkey.create(@argv.name) }
15
- if %w[s string].member?(@@global.format)
15
+ if [:s, :string].member?(@@global.format)
16
16
  puts "Name: #{kp.name}"
17
17
  puts "Fingerprint: #{kp.fingerprint}", $/
18
18
  puts "Copy the following private key data into a file."
@@ -31,7 +31,7 @@ module Rudy; module CLI;
31
31
  end
32
32
 
33
33
  def release_valid?
34
- @rr = Rudy::Routines::Release.new
34
+ @rr = Rudy::Routines::Release.new(@alias) # Important: could be rerelease
35
35
  @rr.raise_early_exceptions
36
36
  true
37
37
  end
data/lib/rudy/global.rb CHANGED
@@ -34,6 +34,8 @@ module Rudy
34
34
  field :local_user
35
35
  field :local_hostname
36
36
 
37
+ field :offline
38
+
37
39
  field :config => String
38
40
 
39
41
  attr_accessor :print_header
data/lib/rudy/routines.rb CHANGED
@@ -91,7 +91,6 @@ module Rudy
91
91
  }
92
92
  end
93
93
 
94
-
95
94
  # TODO: trap rbox errors. We could get an authentication error.
96
95
  opts = { :keys => root_keypairpath, :user => 'root', :info => @@global.verbose > 0 }
97
96
  begin
@@ -125,12 +124,12 @@ module Rudy
125
124
  puts task_separator("AUTHORIZE USER")
126
125
  Rudy::Routines::UserHelper.authorize(@routine, machine, rbox)
127
126
  end
128
-
127
+ #puts 1
129
128
  if Rudy::Routines::ScriptHelper.before?(@routine) # before
130
129
  puts task_separator("REMOTE SHELL")
131
130
  Rudy::Routines::ScriptHelper.before(@routine, sconf, machine, rbox)
132
131
  end
133
-
132
+ #puts 2
134
133
  if Rudy::Routines::DiskHelper.disks?(@routine) # disk
135
134
  puts task_separator("DISKS")
136
135
  if rbox.ostype == "sunos"
@@ -139,7 +138,7 @@ module Rudy
139
138
  Rudy::Routines::DiskHelper.execute(@routine, machine, rbox)
140
139
  end
141
140
  end
142
-
141
+
143
142
  # Startup, shutdown, release, deploy, etc...
144
143
  routine_action.call(machine, rbox) if routine_action
145
144
 
@@ -210,8 +209,6 @@ module Rudy
210
209
  end
211
210
 
212
211
  def machine_separator(name, awsid)
213
- dashes = 80 - name.size #
214
- dashes = 0 if dashes < 1
215
212
  ('%s %-63s awsid: %s ' % [$/, name, awsid]).att(:reverse)
216
213
  end
217
214
 
data/lib/rudy/utils.rb CHANGED
@@ -21,7 +21,7 @@ module Rudy
21
21
  ip = /([0-9]{1,3}\.){3}[0-9]{1,3}/.match(ipstr).to_s
22
22
  break if ip && !ip.empty?
23
23
  end
24
- rescue SocketError, Errno::ETIMEDOUT
24
+ rescue SocketError, Errno::ETIMEDOUT => ex
25
25
  STDERR.puts "Connection Error. Check your internets!"
26
26
  end
27
27
  ip += "/32" if ip
data/rudy.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  @spec = Gem::Specification.new do |s|
2
2
  s.name = "rudy"
3
3
  s.rubyforge_project = 'rudy'
4
- s.version = "0.7.1"
4
+ s.version = "0.7.3"
5
5
  s.summary = "Rudy: Not your grandparents' EC2 deployment tool."
6
6
  s.description = s.summary
7
7
  s.author = "Delano Mandelbaum"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rudy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1
4
+ version: 0.7.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Delano Mandelbaum
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-05-04 00:00:00 -04:00
12
+ date: 2009-05-05 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency