rudy 0.7.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES.txt CHANGED
@@ -8,7 +8,22 @@ RUDY, CHANGES
8
8
  * TODO: Tests for AWS HTTPS
9
9
 
10
10
 
11
- #### 0.7.0 (2009-04-??) ###############################
11
+ #### 0.7.1 (2009-04-04) ###############################
12
+
13
+ * FIXED: rudy wasn't honouring -C option for specifying a config file
14
+ * FIXED: Was disabling, but not enabling colour
15
+ * FIXED: Symbol errors in 1.8
16
+ * FIXED: Command blocks for root user are always run first now in Routines config.
17
+ * ADDED: "script" keyword to routines config.
18
+ * CHANGE: routines before, after, and script blocks are now processed by Rye::Box.batch as Procs.
19
+ * CHANGE: deny was removed from commands config (it will come back later).
20
+ * ADDED: examples/
21
+ * CHANGE: Rudy now checks the current working directory for machines, commands, etc... configs
22
+ * ADDED: script_local
23
+ * ADDED: Routine now checks whether there are any remote tasks. If not, it doesn't loop through machines.
24
+
25
+
26
+ #### 0.7.0 (2009-04-02) ###############################
12
27
 
13
28
  * CHANGE: Upgrade to Drydock 0.6, Caesars 0.6, and Rye 0.6
14
29
  * CHANGE: Updated Routines configuration syntax for specifying shell commands
data/README.rdoc CHANGED
@@ -29,7 +29,7 @@ All configuration is organized into the zones, environments, and roles that you
29
29
  * Powerful command-line tools
30
30
  * <tt>$ rudy -u root ssh</tt>
31
31
  * <tt>$ rudy -e testing -r database startup</tt>
32
- * Use _any_ Amazon machine image (AMI)
32
+ * Use _any Linux_ Amazon machine image (AMI) (partial Solaris support)
33
33
  * Complete command-line interface for EC2. See <tt>bin/rudy-ec2</tt>.
34
34
 
35
35
  == Installation
@@ -40,8 +40,8 @@ Via Rubygems, one of:
40
40
  $ sudo gem install solutious-rudy --source http://gems.github.com/
41
41
 
42
42
  or via download:
43
- * rudy-latest.tar.gz[http://github.com/solutious/rudy/tarball/rudy-latest]
44
- * rudy-latest.zip[http://github.com/solutious/rudy/zipball/rudy-latest]
43
+ * rudy-latest.tar.gz[http://github.com/solutious/rudy/tarball/latest]
44
+ * rudy-latest.zip[http://github.com/solutious/rudy/zipball/latest]
45
45
 
46
46
  NOTE: <em>If you are not installing via RubyGems, you need to make sure the dependencies are in your LOAD_PATH (<tt>$:</tt>). Ryan Tomayko wrote a gist[http://gist.github.com/54177] about it.</em>
47
47
 
data/Rakefile CHANGED
@@ -11,6 +11,8 @@ include FileUtils
11
11
 
12
12
  task :default => :test
13
13
 
14
+
15
+
14
16
  # TESTS ===============================================================
15
17
 
16
18
  Rake::TestTask.new(:test_old) do |t|
data/Rudyfile CHANGED
@@ -81,13 +81,20 @@ end
81
81
 
82
82
 
83
83
  # ----------------------------------------------------------- COMMANDS --------
84
- # The commands block defines shell commands to be allowed or denied from the
85
- # default list defined by Rye::Cmd (Rudy executes all SSH commands via Rye).
86
- # Commands can have any name except for keywords already used by Rudy.
84
+ # The commands block defines shell commands that can be used in routines. The
85
+ # ones defined here are added to the default list defined by Rye::Cmd (Rudy
86
+ # executes all SSH commands via Rye).
87
+ #
88
+ # Usage:
89
+ #
90
+ # allow COMMAND-NAME
91
+ # allow COMMAND-NAME, '/path/2/COMMAND'
92
+ # allow COMMAND-NAME, '/path/2/COMMAND', 'default argument', 'another arg'
93
+ #
87
94
  commands do
95
+ allow :make
88
96
  allow :gem_install, "/usr/bin/gem", "install", :V, "--no-rdoc", "--no-ri"
89
97
  allow :apt_get, "/usr/bin/apt-get", :y, :q
90
- deny :kill
91
98
  end
92
99
 
93
100
 
data/bin/rudy CHANGED
@@ -23,7 +23,7 @@ require 'rudy/cli'
23
23
  # Command-line interface for /bin/rudy
24
24
  class RudyCLI < Rudy::CLI::Base
25
25
 
26
- debug :on
26
+ debug :off
27
27
  default :machines
28
28
  trawler :passthrough
29
29
 
@@ -86,6 +86,10 @@ class RudyCLI < Rudy::CLI::Base
86
86
  usage "rudy shutdown"
87
87
  command :shutdown => Rudy::CLI::Routines
88
88
 
89
+ #about "Restart a machine group"
90
+ #usage "rudy restart"
91
+ #command :restart => Rudy::CLI::Routines
92
+
89
93
  about "Create a release"
90
94
  usage "rudy release"
91
95
  command :release => Rudy::CLI::Routines
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 = 0.freeze
48
+ TINY = 1.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/cli.rb CHANGED
@@ -26,8 +26,7 @@ module Rudy
26
26
  protected
27
27
  def init
28
28
 
29
-
30
- Rudy::Huxtable.update_config
29
+ #Caesars.enable_debug
31
30
 
32
31
  # The CLI wants output!
33
32
  Rudy::Huxtable.update_logger STDOUT
@@ -35,6 +34,16 @@ module Rudy
35
34
  # Send The Huxtables the global values from the command-line
36
35
  Rudy::Huxtable.update_global @global
37
36
 
37
+ # Reload configuration. This must come after update_global
38
+ # so it will catch the @@global.config path (if supplied).
39
+ begin
40
+ Rudy::Huxtable.update_config
41
+ rescue Caesars::SyntaxError => ex
42
+ STDERR.puts ex.message
43
+ STDERR.puts ex.backtrace if @@global.verbose > 0
44
+ exit 81
45
+ end
46
+
38
47
  unless @@global.accesskey && @@global.secretkey
39
48
  STDERR.puts "No AWS credentials. Check your configs!"
40
49
  STDERR.puts "Try: rudy init"
@@ -9,21 +9,25 @@ module Rudy; module CLI;
9
9
  true
10
10
  end
11
11
  def startup
12
-
13
- @rr.execute
14
-
12
+ machines = @rr.execute
15
13
  puts $/, "The following machines are now available:"
16
- rmach = Rudy::Machines.new
17
- rmach.list do |machine|
14
+ machines.each do |machine|
18
15
  puts machine.to_s
19
16
  end
20
-
21
- if @@global.environment == @@config.defaults.environment &&
22
- @@global.role == @@config.defaults.role
23
- #puts
24
- #puts "Login with: rudy -u root ssh"
25
- end
26
-
17
+ end
18
+
19
+ def restart_valid?
20
+ @rr = Rudy::Routines::Restart.new
21
+ @rr.raise_early_exceptions
22
+ true
23
+ end
24
+ def restart
25
+ #machines = @rr.execute
26
+ #puts $/, "The following machines have been restarted:"
27
+ #machines.each do |machine|
28
+ # puts machine.to_s
29
+ #end
30
+ #puts "Restart is disabled"
27
31
  end
28
32
 
29
33
  def release_valid?
data/lib/rudy/config.rb CHANGED
@@ -61,10 +61,13 @@ module Rudy
61
61
  break
62
62
  end
63
63
 
64
+ typelist = self.keys.collect { |g| "#{g}.rb" }.join(',')
65
+
64
66
  # Rudy then looks for the rest of the config in these locations
65
67
  @paths += Dir.glob(File.join(cwd, 'Rudyfile')) || []
66
68
  @paths += Dir.glob(File.join(cwd, 'config', 'rudy', '*.rb')) || []
67
69
  @paths += Dir.glob(File.join(cwd, '.rudy', '*.rb')) || []
70
+ @paths += Dir.glob(File.join(cwd, "{#{typelist}}")) || []
68
71
  @paths += Dir.glob(File.join('/etc', 'rudy', '*.rb')) || []
69
72
  @paths &&= @paths.uniq
70
73
 
@@ -91,21 +91,16 @@ class Rudy::Config
91
91
  arg.is_a?(Symbol) ? ":#{arg}" : "'#{arg}'"
92
92
  end
93
93
  hard_args = args.empty? ? "*args" : "#{args.join(', ')}, *args"
94
-
95
- # Command keywords must be parsed with forced_array. See ScriptHelper.
96
- Rudy::Config::Routines.forced_array cmd
94
+
95
+ # TODO: Use define_method
97
96
  Rye::Cmd.module_eval %Q{
98
97
  def #{cmd}(*args); cmd(:'#{path}', #{hard_args}); end
99
98
  }
99
+
100
100
  end
101
- # We deny commands by telling routines to not parse the given keywords
102
- self.deny.each do |cmd|
103
- Rudy::Config::Routines.forced_ignore cmd.first # cmd is a forced array
104
- # We don't remove the method from Rye:Cmd because we
105
- # may need elsewhere in Rudy. Forced ignore ensures
106
- # the config is not stored anyhow.
107
- end
108
- raise Caesars::Config::ForceRefresh.new(:routines)
101
+ ## NOTE: We now process command blocks as Procs rather than individual commands.
102
+ # There's currently no need to ForceRefresh here
103
+ ##raise Caesars::Config::ForceRefresh.new(:routines)
109
104
  end
110
105
  end
111
106
 
@@ -124,31 +119,26 @@ class Rudy::Config
124
119
  forced_hash :restore
125
120
  forced_hash :mount
126
121
 
127
- # Remote scripts
128
- forced_hash :before
129
- forced_hash :before_local
130
- forced_hash :after
131
- forced_hash :after_local
122
+ # Script blocks
123
+ forced_hash :before
124
+ forced_hash :after
125
+ forced_hash :script_local
126
+ forced_hash :before_local
127
+ forced_hash :after_local # We force hash the script keywords
128
+ forced_hash :script # b/c we want them to store the usernames
129
+ chill :before # as hash keys.
130
+ chill :after # We also chill them b/c we want to execute
131
+ chill :before_local # the command blocks with an instance_eval
132
+ chill :after_local # inside a Rye::Box object.
133
+ chill :script
134
+ chill :script_local
132
135
 
133
136
  # Version control systems
134
137
  forced_hash :git
135
138
  forced_hash :svn
136
139
 
137
- def init
138
-
139
- end
140
-
141
- # Add remote shell commands to the DSL as forced Arrays.
142
- # Example:
143
- # ls :a, :l, "/tmp" # => :ls => [[:a, :l, "/tmp"]]
144
- # ls :o # => :ls => [[:a, :l, "/tmp"], [:o]]
145
- # NOTE: Beware of namespace conflicts in other areas of the DSL,
146
- # specifically shell commands that have the same name as a keyword
147
- # we want to use in the DSL. This includes commands that were added
148
- # to Rye::Cmd before Rudy is 'require'd.
149
- Rye::Cmd.instance_methods.sort.each do |cmd|
150
- forced_array cmd
140
+ def init
151
141
  end
152
-
142
+
153
143
  end
154
144
  end
data/lib/rudy/disks.rb CHANGED
@@ -4,6 +4,7 @@ module Rudy
4
4
  class Disk < Storable
5
5
  include Rudy::MetaData::ObjectBase
6
6
 
7
+
7
8
  field :rtype
8
9
  field :awsid
9
10
  field :status
@@ -20,6 +21,11 @@ class Disk < Storable
20
21
  field :size
21
22
  #field :backups => Array
22
23
 
24
+ # Is the associated volume formatted? One of: true, false, [empty].
25
+ # [empty] means we don't know and it's the default.
26
+ field :raw
27
+
28
+ field :fstype
23
29
  field :mounted
24
30
 
25
31
  def init(path=nil, size=nil, device=nil, position=nil)
@@ -46,7 +52,6 @@ class Disk < Storable
46
52
 
47
53
  def to_s(with_titles=true)
48
54
  update
49
- puts "FUCK" if @mounted
50
55
  mtd = @mounted == true ? "mounted" : @status
51
56
  "%s; %3sGB; %s; %s" % [liner_note, @size, @device, mtd]
52
57
  end
@@ -75,6 +80,7 @@ class Disk < Storable
75
80
  raise "#{name} is already running" if exists?
76
81
  vol = @rvol.create(@size, @zone, snapshot)
77
82
  @awsid = vol.awsid
83
+ @raw = true
78
84
  self.save
79
85
  self
80
86
  end
data/lib/rudy/global.rb CHANGED
@@ -42,7 +42,7 @@ module Rudy
42
42
  postprocess
43
43
  # These attributes MUST have values.
44
44
  @verbose ||= 0
45
- @nocolor = true unless @nocolor == "false" || @nocolor.is_a?(FalseClass)
45
+ @nocolor = true unless @nocolor == "false" || @nocolor == false
46
46
  @quiet ||= false
47
47
  @format ||= :string # as in, to_s
48
48
  @print_header = true if @print_header == nil
@@ -97,9 +97,9 @@ module Rudy
97
97
  @position &&= @position.to_s.rjust(2, '0')
98
98
  @format &&= @format.to_sym rescue nil
99
99
 
100
- String.disable_color if @nocolor
101
- Rudy.enable_quiet if @quiet
102
- Annoy.enable_skip if @yes
100
+ @nocolor ? String.disable_color : String.enable_color
101
+ @quiet ? Rudy.enable_quiet : Rudy.disable_quiet
102
+ @yes ? Annoy.enable_skip : Annoy.disable_skip
103
103
  end
104
104
 
105
105
  def apply_environment_variables
data/lib/rudy/huxtable.rb CHANGED
@@ -38,8 +38,9 @@ module Rudy
38
38
  #def logger; @@logger; end
39
39
 
40
40
  def self.update_config(path=nil)
41
- # nil or otherwise bad paths send to look_and_load are ignored
42
- @@config.look_and_load(path || nil)
41
+ @@config.verbose = (@@global.verbose > 0)
42
+ # nil and bad paths sent to look_and_load are ignored
43
+ @@config.look_and_load(path || @@global.config)
43
44
  @@global.apply_config(@@config)
44
45
  end
45
46
 
data/lib/rudy/machines.rb CHANGED
@@ -144,6 +144,9 @@ module Rudy
144
144
  super
145
145
  end
146
146
 
147
+ def restart
148
+ @ec2inst.restart(@awsid) if running?
149
+ end
147
150
 
148
151
  def Machine.generate_machine_data
149
152
  data = { # Give the machine an identity
@@ -223,6 +226,19 @@ module Rudy
223
226
  end
224
227
  end
225
228
 
229
+
230
+ def restart(&each_mach)
231
+ raise MachineGroupNotDefined, current_machine_group unless known_machine_group?
232
+ raise MachineGroupNotRunning, current_machine_group unless running?
233
+ machines = list
234
+ machines.each do |mach|
235
+ each_mach.call(mach) if each_mach
236
+ puts "Restarting #{mach.name}"
237
+ mach.restart
238
+ end
239
+ machines
240
+ end
241
+
226
242
  def list(more=[], less=[], &each_mach)
227
243
  machines = list_as_hash(more, less, &each_mach)
228
244
  machines &&= machines.values
data/lib/rudy/routines.rb CHANGED
@@ -50,12 +50,23 @@ module Rudy
50
50
 
51
51
  if Rudy::Routines::ScriptHelper.before_local?(@routine) # before_local
52
52
  # Runs "before_local" scripts of routines config.
53
- # NOTE: Does not run "before" scripts b/c there are no remote machines
54
53
  puts task_separator("LOCAL SHELL")
55
54
  Rudy::Routines::ScriptHelper.before_local(@routine, sconf, lbox)
56
55
  end
57
56
 
58
- # Execute the action (create, list, destroy) & apply the block to each
57
+ if Rudy::Routines::ScriptHelper.script_local?(@routine) # before_local
58
+ # Runs "script_local" scripts of routines config.
59
+ # NOTE: This is synonymous with before_local
60
+ puts task_separator("LOCAL SHELL")
61
+ Rudy::Routines::ScriptHelper.script_local(@routine, sconf, lbox)
62
+ end
63
+
64
+ unless has_remote_task?(@routine)
65
+ puts "[no remote tasks]"
66
+ return
67
+ end
68
+
69
+ # Execute the action (create, list, destroy, restart) & apply the block to each
59
70
  rmach.send(machine_action) do |machine|
60
71
  puts machine_separator(machine.name, machine.awsid)
61
72
 
@@ -131,7 +142,21 @@ module Rudy
131
142
 
132
143
  # Startup, shutdown, release, deploy, etc...
133
144
  routine_action.call(machine, rbox) if routine_action
134
-
145
+
146
+ # The "after" blocks are synonymous with "script" blocks.
147
+ # For some routines, like startup, it makes sense to an
148
+ # "after" block b/c "script" is ambiguous. In generic
149
+ # routines, there is no concept of before or after. The
150
+ # definition is the entire routine so we use "script".
151
+ # NOTE: If both after and script are supplied they will
152
+ # both be executed.
153
+ if Rudy::Routines::ScriptHelper.script?(@routine) # script
154
+ puts task_separator("REMOTE SHELL")
155
+ # Runs "after" scripts of routines config
156
+ Rudy::Routines::ScriptHelper.script(@routine, sconf, machine, rbox)
157
+ end
158
+
159
+
135
160
  if Rudy::Routines::ScriptHelper.after?(@routine) # after
136
161
  puts task_separator("REMOTE SHELL")
137
162
  # Runs "after" scripts of routines config
@@ -156,6 +181,19 @@ module Rudy
156
181
 
157
182
  end
158
183
 
184
+ # Does the given +routine+ define any remote tasks?
185
+ def has_remote_task?(routine)
186
+ any = [Rudy::Routines::DiskHelper.disks?(routine),
187
+ Rudy::Routines::ScriptHelper.before?(routine),
188
+ Rudy::Routines::ScriptHelper.after?(routine),
189
+ Rudy::Routines::ScriptHelper.script?(routine),
190
+ Rudy::Routines::UserHelper.authorize?(routine),
191
+ Rudy::Routines::UserHelper.adduser?(routine)]
192
+ # Throw away all false answers (and nil answers)
193
+ any = any.compact.select { |success| success }
194
+ !any.empty? # Returns true if any element contains true
195
+ end
196
+
159
197
  def preliminary_separator(msg)
160
198
  # TODO: Count number messages printed 1/3. ie:
161
199
  # m-us-east-1b-stage-app-01
@@ -7,9 +7,13 @@ module Rudy
7
7
 
8
8
  def execute_rbox_command(ret=nil, &command)
9
9
  begin
10
- ret = command.call
10
+ ret = command.call if command
11
+ return unless ret.is_a?(Rye::Rap)
11
12
  puts ' ' << ret.stdout.join("#{$/} ") if !ret.stdout.empty?
12
13
  print_response(ret)
14
+ rescue IOError => ex
15
+ STDERR.puts " Connection Error (#{ex.message})".color(:red)
16
+ exit 12 unless keep_going?
13
17
  rescue Rye::CommandError => ex
14
18
  print_response(ex)
15
19
  exit 12 unless keep_going?
@@ -39,7 +43,8 @@ module Rudy
39
43
  colour = rap.exit_code != 0 ? :red : :normal
40
44
  [:stderr].each do |sumpin|
41
45
  next if rap.send(sumpin).empty?
42
- STDERR.puts (" #{sumpin.upcase.to_s} " << '-'*38).color(colour).bright
46
+ STDERR.puts
47
+ STDERR.puts((" #{sumpin.to_s.upcase} " << '-'*38).color(colour).bright)
43
48
  STDERR.puts " " << rap.send(sumpin).join("#{$/} ").color(colour)
44
49
  end
45
50
  STDERR.puts " Exit code: #{rap.exit_code}".color(colour) if rap.exit_code != 0
@@ -7,7 +7,7 @@ module Rudy; module Routines;
7
7
 
8
8
  def disks?(routine)
9
9
  (routine.is_a?(Caesars::Hash) && routine.disks &&
10
- routine.disks.is_a?(Caesars::Hash) && !routine.disks.empty?)
10
+ routine.disks.is_a?(Caesars::Hash) && !routine.disks.empty?) ? true : false
11
11
  end
12
12
 
13
13
  def paths(routine)
@@ -25,18 +25,24 @@ module Rudy; module Routines;
25
25
 
26
26
  # We need to add mkfs since it's not enabled by default.
27
27
  # We add it only to this instance we're using.
28
- def @rbox.mkfs(*args); cmd('mkfs', args); end
28
+ # We give it a funny name so we can delete it.
29
+ def @rbox.rudy_mkfs(*args); cmd('mkfs', args); end
29
30
 
30
- return unless disks?(routine)
31
31
 
32
+ return unless disks?(routine)
33
+
34
+ modified = []
32
35
  routine.disks.each_pair do |action, disks|
33
36
  unless DiskHelper.respond_to?(action)
34
37
  STDERR.puts %Q(DiskHelper: unknown action "#{action}")
35
38
  next
36
39
  end
37
40
  send(action, disks) # create, copy, destroy, ...
41
+ modified << disks
38
42
  end
39
43
 
44
+ # TODO: remove rudy_mkfs method
45
+
40
46
  end
41
47
 
42
48
  def create(disks)
@@ -46,17 +52,26 @@ module Rudy; module Routines;
46
52
  disk = Rudy::Disk.new(path, props[:size], props[:device], @machine.position)
47
53
  olddisk = rdisk.get(disk.name)
48
54
  if olddisk && olddisk.exists?
49
- puts "Disk exists: #{olddisk.name}".color(:red)
50
- return
55
+ olddisk.update
56
+ puts "Disk found: #{olddisk.name}"
57
+ if olddisk.attached?
58
+ puts "In use. Skipping...".color(:red)
59
+ return
60
+ else
61
+ disk = olddisk
62
+ end
63
+ else
64
+ puts "Creating #{disk.name} "
65
+ disk.fstype = props[:fstype] || 'ext3'
51
66
  end
52
67
 
53
- puts "Creating #{disk.name} "
54
-
55
- msg = "Creating volume... "
56
- disk.create
57
- Rudy::Utils.waiter(2, 60, STDOUT, msg) {
58
- disk.available?
59
- }
68
+ unless disk.exists? # Checks the EBS volume
69
+ msg = "Creating volume... "
70
+ disk.create
71
+ Rudy::Utils.waiter(2, 60, STDOUT, msg) {
72
+ disk.available?
73
+ }
74
+ end
60
75
 
61
76
  msg = "Attaching #{disk.awsid} to #{@machine.awsid}... "
62
77
  disk.attach(@machine.awsid)
@@ -71,30 +86,40 @@ module Rudy; module Routines;
71
86
 
72
87
  # TODO: Cleanup. See ScriptHelper
73
88
  begin
74
- print "Creating ext3 filesystem for #{disk.device}... "
75
- execute_rbox_command {
76
-
77
- @rbox.mkfs(:t, "ext3", :F, disk.device)
78
- @rbox.mkdir(:p, disk.path)
89
+ if disk.raw == true
90
+ print "Creating #{disk.fstype} filesystem for #{disk.device}... "
91
+ @rbox.rudy_mkfs(:t, disk.fstype, :F, disk.device)
92
+ disk.raw = false
93
+ disk.save
79
94
  puts "done"
80
-
81
- print "Mounting at #{disk.path}... "
82
-
83
- @rbox.mount(:t, 'ext3', disk.device, disk.path)
84
- }
95
+ end
96
+
97
+ @rbox.mkdir(:p, disk.path)
98
+
99
+ print "Mounting at #{disk.path}... "
100
+
101
+ ret = @rbox.mount(:t, disk.fstype, disk.device, disk.path)
102
+ print_response ret
103
+ if ret.exit_code > 0
104
+ STDERR.puts "Error creating disk".color(:red)
105
+ return
106
+ else
107
+ puts "done"
108
+ end
85
109
  disk.mounted = true
86
110
  disk.save
111
+
87
112
  rescue Net::SSH::AuthenticationFailed, Net::SSH::HostKeyMismatch => ex
88
113
  STDERR.puts "Error creating disk".color(:red)
89
114
  STDERR.puts ex.message.color(:red)
90
115
  rescue Rye::CommandNotFound => ex
91
116
  puts " CommandNotFound: #{ex.message}".color(:red)
117
+
92
118
  rescue
93
119
  STDERR.puts "Error creating disk" .color(:red)
94
120
  Rudy::Utils.bug
95
121
  end
96
- puts "done"
97
-
122
+
98
123
  end
99
124
  end
100
125
 
@@ -127,7 +152,7 @@ module Rudy; module Routines;
127
152
  sleep 0.5
128
153
  end
129
154
 
130
- puts "Destroying metadata... "
155
+ puts "Destroying volume and metadata... "
131
156
  disk.destroy
132
157
 
133
158
  end
@@ -8,28 +8,43 @@ module Rudy; module Routines;
8
8
  include Rudy::Routines::HelperBase # TODO: use execute_rbox_command
9
9
  extend self
10
10
 
11
- @@script_types = [:after, :before, :after_local, :before_local]
11
+ @@script_types = [:after, :before, :after_local, :before_local, :script, :script_local]
12
12
  @@script_config_file = "rudy-config.yml"
13
13
 
14
+ # TODO: refactor using this_method
15
+
14
16
  def before_local(routine, sconf, rbox)
15
-
17
+ execute_command(:before_local, routine, sconf, 'localhost', rbox)
18
+ end
19
+ def before_local?(routine)
16
20
  # before_local generally doesn't take a user name like the remote
17
21
  # before block so we add it here (unless the user did specify it)
18
22
  routine[:before_local] = {
19
- rbox.user.to_sym => routine.delete(:before_local)
20
- } unless routine.has_key?(rbox.user.to_sym) # use routine[timing].deepest_point ?
21
- execute_command(:before_local, routine, sconf, 'localhost', rbox)
23
+ Rudy.sysinfo.user.to_sym => routine.delete(:before_local)
24
+ } if routine[:before_local].is_a?(Proc)
25
+ execute_command?(:before_local, routine)
22
26
  end
23
- def before_local?(routine); execute_command?(:before_local, routine); end
24
-
27
+ def script_local(routine, sconf, rbox)
28
+ execute_command(:script_local, routine, sconf, 'localhost', rbox)
29
+ end
30
+ def script_local?(routine)
31
+ # before_local generally doesn't take a user name like the remote
32
+ # before block so we add it here (unless the user did specify it)
33
+ routine[:script_local] = {
34
+ Rudy.sysinfo.user.to_sym => routine.delete(:script_local)
35
+ } if routine[:script_local].is_a?(Proc)
36
+ execute_command?(:script_local, routine)
37
+ end
38
+
25
39
  def after_local(routine, sconf, rbox)
26
- routine[:after_local] = { # See before_local note
27
- rbox.user.to_sym => routine.delete(:after_local)
28
- } unless routine.has_key?(rbox.user.to_sym)
29
40
  execute_command(:after_local, routine, sconf, 'localhost', rbox)
30
41
  end
31
- def after_local?(routine); execute_command?(:after_local, routine); end
32
-
42
+ def after_local?(routine)
43
+ routine[:after_local] = { # See before_local note
44
+ Rudy.sysinfo.user.to_sym => routine.delete(:after_local)
45
+ } if routine[:after_local].is_a?(Proc)
46
+ execute_command?(:after_local, routine)
47
+ end
33
48
 
34
49
  def before(routine, sconf, machine, rbox)
35
50
  raise "ScriptHelper: Not a Rudy::Machine" unless machine.is_a?(Rudy::Machine)
@@ -43,6 +58,12 @@ module Rudy; module Routines;
43
58
  end
44
59
  def after?(routine); execute_command?(:after, routine); end
45
60
 
61
+ def script(routine, sconf, machine, rbox)
62
+ raise "ScriptHelper: Not a Rudy::Machine" unless machine.is_a?(Rudy::Machine)
63
+ execute_command(:script, routine, sconf, machine.name, rbox)
64
+ end
65
+ def script?(routine); execute_command?(:script, routine); end
66
+
46
67
 
47
68
  private
48
69
 
@@ -53,8 +74,9 @@ module Rudy; module Routines;
53
74
  def execute_command?(timing, routine)
54
75
  hasconf = (routine.is_a?(Caesars::Hash) && routine.has_key?(timing))
55
76
  return false unless hasconf
56
- routine[timing].each_pair do |user,conf|
57
- if conf.empty?
77
+ routine[timing].each_pair do |user,proc|
78
+ #p [timing, user, proc].join(', ')
79
+ if proc.nil? || !proc.is_a?(Proc)
58
80
  STDERR.puts "Empty #{timing} config for #{user}"
59
81
  else
60
82
  return true
@@ -77,16 +99,22 @@ module Rudy; module Routines;
77
99
  Rudy::Utils.write_to_file(tf.path, sconf.to_hash.to_yaml, 'w')
78
100
  end
79
101
 
80
- # We need to explicitly add the rm command for rbox so we
81
- # can delete the script config file when we're done. This
82
- # add the method on for the instance of rbox we are using.
83
- def rbox.rm(*args); cmd('rm', args); end
84
-
85
102
  if execute_command?(timing, routine) # i.e. before_local?
103
+
104
+ # We need to explicitly add the rm command for rbox so we
105
+ # can delete the script config file when we're done. This
106
+ # adds the method to this instance of rbox only.
107
+ # We give it a funny so we can delete it knowing we're not
108
+ # deleting a method added somewhere else.
109
+ def rbox.rudy_tmp_rm(*args); cmd('rm', args); end
86
110
 
87
111
  original_user = rbox.user
88
- users = routine[timing] || {}
89
- users.each_pair do |user, commands|
112
+ user_blocks = routine[timing] || {}
113
+ users = user_blocks.keys
114
+ # Root stuff is always run first.
115
+ users.unshift(users.delete(:root)) if users.member?(:root)
116
+ users.each do |user|
117
+ proc = user_blocks[user]
90
118
 
91
119
  begin
92
120
  rbox.switch_user user # does nothing if it's the same user
@@ -108,32 +136,45 @@ module Rudy; module Routines;
108
136
  rbox.upload(conf_str, @@script_config_file)
109
137
  rbox.chmod(600, @@script_config_file)
110
138
  }
111
-
112
- commands.each_pair do |command, calls|
113
- # If a command is only referred to once and it has no arguments
114
- # defined, we force it through by making an array with one element.
115
- calls = [[]] if calls.empty?
116
-
117
- # Force a CommandNotFound exception early
118
- unless rbox.can?(command)
119
- execute_rbox_command { rbox.send(command) }
120
- next
139
+
140
+ begin
141
+ # We define hooks so we can call the script block as a batch.
142
+ # We intentionally set and unset the hooks so the other commands
143
+ # (config file copy) don't get printed.
144
+ #
145
+ # This block gets called for every command method call.
146
+ rbox.pre_command_hook do |cmd, args, user|
147
+ puts command_separator(rbox.preview_command(cmd, args), user)
121
148
  end
122
-
123
- # Execute the command for every set of arguments
124
- calls.each do |args|
125
- puts command_separator(rbox.preview_command(command, args), user)
126
- execute_rbox_command { ret = rbox.send(command, args) }
149
+ # And this one gets called after each command method call.
150
+ rbox.post_command_hook do |ret|
151
+ puts ' ' << ret.stdout.join("#{$/} ") if !ret.stdout.empty?
152
+ print_response(ret)
127
153
  end
154
+
155
+ ### EXECUTE THE COMMANDS BLOCK
156
+ rbox.batch(&proc)
157
+
158
+ rbox.pre_command_hook = nil
159
+ rbox.post_command_hook = nil
160
+ rescue Rye::CommandError => ex
161
+ print_response(ex)
162
+ exit 12 unless keep_going?
163
+ rescue Rye::CommandNotFound => ex
164
+ STDERR.puts " CommandNotFound: #{ex.message}".color(:red)
165
+ STDERR.puts ex.backtrace if Rudy.debug?
166
+ exit 12 unless keep_going?
128
167
  end
129
168
 
130
169
  # I was gettings errors about script_config_file not existing. There
131
170
  # might be a race condition when the rm command is called too quickly.
132
171
  # It's also quite possible I'm off my rocker!
133
- sleep 0.1
172
+ ## NOTE: I believe this was an issue with Rye. I fixed it when I was
173
+ ## noticing the same error in another place. It hasn't repeated.
174
+ ## sleep 0.1
134
175
 
135
176
  rbox.cd # reset to home dir
136
- #rbox.rm(@@script_config_file)
177
+ rbox.rudy_tmp_rm(@@script_config_file)
137
178
  end
138
179
 
139
180
  # Return the borrowed rbox instance to the user it was provided with
@@ -5,7 +5,7 @@ module Rudy; module Routines;
5
5
  extend self
6
6
 
7
7
  def adduser?(routine)
8
- (!routine.adduser.nil? && !routine.adduser.empty?)
8
+ (!routine.adduser.nil? && !routine.adduser.to_s.empty?)
9
9
  end
10
10
  def adduser(routine, machine, rbox)
11
11
 
@@ -13,7 +13,7 @@ module Rudy; module Routines;
13
13
  # explicitly so we do it for linux too for fun.
14
14
  homedir = rbox.guess_user_home(routine.adduser.to_s)
15
15
  args = [:m, :d, homedir, :s, '/bin/bash', routine.adduser.to_s]
16
- puts command_separator(rbox.preview_command(:useradd, args), routine.adduser.to_s)
16
+ puts command_separator(rbox.preview_command(:useradd, args), rbox.user)
17
17
 
18
18
  # NOTE: We'll may to use platform specific code here.
19
19
  # Linux has adduser and useradd commands:
@@ -24,10 +24,10 @@ module Rudy; module Routines;
24
24
  end
25
25
 
26
26
  def authorize?(routine)
27
- (!routine.authorize.nil? && !routine.authorize.empty?)
27
+ (!routine.authorize.nil? && !routine.authorize.to_s.empty?)
28
28
  end
29
29
  def authorize(routine, machine, rbox)
30
- puts command_separator(:authorize_keys_remote, routine.authorize)
30
+ puts command_separator(:authorize_keys_remote, rbox.user)
31
31
  execute_rbox_command { rbox.authorize_keys_remote(routine.authorize) }
32
32
  end
33
33
 
@@ -14,7 +14,7 @@ module Rudy; module Routines;
14
14
  def execute(&each_mach)
15
15
  routine_separator(@routine_name)
16
16
  machines = []
17
- generic_machine_runner(:list) do |machine|
17
+ generic_machine_runner(:list) do |machine,rbox|
18
18
  puts $/ #, "[routine: #{@routine_name}]"
19
19
  machines << machine
20
20
  end
@@ -15,7 +15,7 @@ module Rudy; module Routines;
15
15
  end
16
16
  machines = []
17
17
  generic_machine_runner(:destroy) do |machine,rbox|
18
- #puts task_separator("SHUTDOWN")
18
+ puts $/, "Shutting down...", $/
19
19
  machines << machine
20
20
  end
21
21
  machines
@@ -16,8 +16,12 @@ module Rudy; module Routines;
16
16
  STDERR.puts "[this is a generic startup routine]"
17
17
  @routine = {}
18
18
  end
19
+ machines = []
19
20
  generic_machine_runner(:create) do |machine,rbox|
21
+ puts $/, "Starting up...", $/
22
+ machines << machine
20
23
  end
24
+ machines
21
25
  end
22
26
 
23
27
  # Called by generic_machine_runner
data/lib/rudy/scm/git.rb CHANGED
@@ -17,6 +17,7 @@ module Rudy
17
17
  attr_reader :rtag
18
18
  attr_reader :user
19
19
  attr_reader :pkey
20
+ attr_reader :commit
20
21
 
21
22
  # * +args+ a hash of params from the git block in the routines config
22
23
  #
@@ -26,10 +27,11 @@ module Rudy
26
27
  :remote => :origin,
27
28
  :branch => :master,
28
29
  :user => :root,
30
+ :commit => :enforce,
29
31
  :path => nil
30
32
  }.merge(args)
31
33
  @remote, @branch, @path = args[:remote], args[:branch], args[:path]
32
- @user, @pkey = args[:user], args[:privatekey]
34
+ @user, @pkey, @commit = args[:user], args[:privatekey], args[:commit]
33
35
  @repo = Repo.new(Dir.pwd) if GIT.working_copy?
34
36
  end
35
37
 
@@ -196,7 +198,7 @@ module Rudy
196
198
 
197
199
  def raise_early_exceptions
198
200
  raise NotAWorkingCopy, :git unless working_copy?
199
- #raise DirtyWorkingCopy, :git unless clean_working_copy?
201
+ raise DirtyWorkingCopy, :git unless @commit.to_s == 'ignore' || clean_working_copy?
200
202
  raise NoRemoteURI, "remote.#{@remote}.url not set" if get_remote_uri.nil?
201
203
  raise NoRemotePath, :git if @path.nil?
202
204
  raise PrivateKeyNotFound, @pkey if @pkey && !File.exists?(@pkey)
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.0"
4
+ s.version = "0.7.1"
5
5
  s.summary = "Rudy: Not your grandparents' EC2 deployment tool."
6
6
  s.description = s.summary
7
7
  s.author = "Delano Mandelbaum"
@@ -14,9 +14,9 @@
14
14
  s.require_paths = %w[lib]
15
15
  s.rubygems_version = '1.1.1'
16
16
 
17
- s.add_dependency 'drydock', '>= 0.6.0'
18
- s.add_dependency 'caesars', '>= 0.6.1'
19
- s.add_dependency 'rye', '>= 0.6.3'
17
+ s.add_dependency 'drydock', '>= 0.6.1'
18
+ s.add_dependency 'caesars', '>= 0.6.3'
19
+ s.add_dependency 'rye', '>= 0.6.4'
20
20
 
21
21
  s.add_dependency 'grit'
22
22
  s.add_dependency 'echoe'
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.0
4
+ version: 0.7.1
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-02 00:00:00 -04:00
12
+ date: 2009-05-04 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -20,7 +20,7 @@ dependencies:
20
20
  requirements:
21
21
  - - ">="
22
22
  - !ruby/object:Gem::Version
23
- version: 0.6.0
23
+ version: 0.6.1
24
24
  version:
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: caesars
@@ -30,7 +30,7 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 0.6.1
33
+ version: 0.6.3
34
34
  version:
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: rye
@@ -40,7 +40,7 @@ dependencies:
40
40
  requirements:
41
41
  - - ">="
42
42
  - !ruby/object:Gem::Version
43
- version: 0.6.3
43
+ version: 0.6.4
44
44
  version:
45
45
  - !ruby/object:Gem::Dependency
46
46
  name: grit