sunshine 1.2.2 → 1.2.3

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.
@@ -1,8 +1,7 @@
1
1
  module Sunshine
2
2
 
3
3
  ##
4
- # Instantiated per deploy server and used to pass bindings to the config's
5
- # ERB build method:
4
+ # Create a selective binding. Useful for controlling ERB builds:
6
5
  # binder.set :server_name, "blah.com"
7
6
  # binder.forward :server_method, ...
8
7
  # binder.get_binding
@@ -14,7 +14,7 @@ module Sunshine
14
14
  START_FAILED_CODE = 10
15
15
  STOP_FAILED_CODE = 11
16
16
  RESTART_FAILED_CODE = 12
17
- STATUS_DOWN_CODE = 13
17
+ STATUS_DOWN_CODE = 13
18
18
 
19
19
  ##
20
20
  # Returns an array of method names to assign to the binder
@@ -14,7 +14,7 @@ module Sunshine
14
14
  def initialize app, options={}
15
15
  super
16
16
 
17
- @bin = options[:bin] || 'apachectl'
17
+ @bin = options[:bin] || 'apache2ctl'
18
18
 
19
19
  @sigkill = 'WINCH'
20
20
 
@@ -37,7 +37,7 @@ module Sunshine
37
37
  end
38
38
 
39
39
 
40
- attr_reader :host, :user, :pid
40
+ attr_reader :host, :user, :parent_pid
41
41
  attr_accessor :ssh_flags, :rsync_flags
42
42
 
43
43
 
@@ -69,7 +69,7 @@ module Sunshine
69
69
  @ssh_flags.concat ["-l", @user] if @user
70
70
  @ssh_flags.concat [*options[:ssh_flags]] if options[:ssh_flags]
71
71
 
72
- @pid, @inn, @out, @err = nil
72
+ @parent_pid = nil
73
73
 
74
74
  self.class.register self
75
75
  end
@@ -94,15 +94,15 @@ module Sunshine
94
94
 
95
95
  cmd = ssh_cmd quote_cmd(LOGIN_LOOP), :sudo => false
96
96
 
97
- @pid, @inn, @out, @err = popen4 cmd.join(" ")
98
- @inn.sync = true
97
+ @parent_pid, inn, out, err = popen4 cmd.join(" ")
98
+ inn.sync = true
99
99
 
100
100
  data = ""
101
101
  ready = nil
102
102
  start_time = Time.now.to_i
103
103
 
104
- until ready || @out.eof?
105
- data << @out.readpartial(1024)
104
+ until ready || out.eof?
105
+ data << out.readpartial(1024)
106
106
  ready = data =~ /ready/
107
107
 
108
108
  raise TimeoutError if timed_out?(start_time, LOGIN_TIMEOUT)
@@ -114,8 +114,11 @@ module Sunshine
114
114
  raise ConnectionError, "Can't connect to #{host_info}"
115
115
  end
116
116
 
117
- @inn.close
118
- @pid
117
+ inn.close rescue nil
118
+ out.close rescue nil
119
+ err.close rescue nil
120
+
121
+ @parent_pid
119
122
  end
120
123
 
121
124
 
@@ -123,7 +126,7 @@ module Sunshine
123
126
  # Check if SSH session is open and returns process pid
124
127
 
125
128
  def connected?
126
- Process.kill(0, @pid) && @pid rescue false
129
+ Process.kill(0, @parent_pid) && @parent_pid rescue false
127
130
  end
128
131
 
129
132
 
@@ -131,13 +134,8 @@ module Sunshine
131
134
  # Disconnect from host
132
135
 
133
136
  def disconnect
134
- @inn.close rescue nil
135
- @out.close rescue nil
136
- @err.close rescue nil
137
-
138
- kill_process @pid, "HUP" rescue nil
139
-
140
- @pid = nil
137
+ kill_process @parent_pid, "HUP" rescue nil
138
+ @parent_pid = nil
141
139
  end
142
140
 
143
141
 
@@ -100,7 +100,7 @@ module Sunshine
100
100
  end
101
101
 
102
102
 
103
- NAME_MATCH = /\/([^\/]+)\.git/
103
+ NAME_MATCH = /\/([^\/]+)(\/?)\.git/
104
104
 
105
105
  def name
106
106
  @url.match(NAME_MATCH)[1]
@@ -95,7 +95,7 @@ module Sunshine
95
95
  app_attr :root_path, :checkout_path, :current_path
96
96
  app_attr :deploys_path, :log_path, :shared_path, :scripts_path
97
97
 
98
- attr_accessor :app, :roles, :scripts, :info, :shell, :crontab, :health
98
+ attr_accessor :app, :roles, :scripts, :info, :shell, :crontab
99
99
  attr_writer :pkg_manager
100
100
 
101
101
  ##
@@ -131,7 +131,6 @@ module Sunshine
131
131
  end
132
132
 
133
133
  @crontab = Crontab.new name, @shell
134
- @health = Healthcheck.new shared_path, @shell
135
134
 
136
135
  @all_deploy_names = nil
137
136
  @previous_deploy_name = nil
@@ -180,7 +179,7 @@ module Sunshine
180
179
  write_script name, bash
181
180
  end
182
181
 
183
- symlink_scripts_to_root
182
+ symlink_scripts_to_root @scripts.keys, "env"
184
183
  end
185
184
 
186
185
 
@@ -222,6 +221,7 @@ module Sunshine
222
221
 
223
222
  def deploy_details reload=false
224
223
  return @deploy_details if @deploy_details && !reload
224
+
225
225
  @deploy_details =
226
226
  YAML.load @shell.call("cat #{self.root_path}/info") rescue nil
227
227
 
@@ -259,7 +259,7 @@ module Sunshine
259
259
  # Builds a hash with information about the deploy at hand.
260
260
 
261
261
  def get_deploy_info
262
- { :deployed_at => Time.now.to_s,
262
+ { :deployed_at => @shell.call("date"),
263
263
  :deployed_as => @shell.call("whoami"),
264
264
  :deployed_by => Sunshine.shell.user,
265
265
  :deploy_name => File.basename(self.checkout_path),
@@ -272,29 +272,6 @@ module Sunshine
272
272
  end
273
273
 
274
274
 
275
- ##
276
- # Decrypt a file using gpg. Allows options:
277
- # :output:: str - the path the output file should go to
278
- # :passphrase:: str - the passphrase gpg should use
279
-
280
- def gpg_decrypt gpg_file, options={}
281
- output_file = options[:output] || gpg_file.gsub(/\.gpg$/, '')
282
-
283
- passphrase = options[:passphrase]
284
- passphrase_file = "#{self.root_path}/tmp/gpg_passphrase"
285
-
286
- gpg_cmd = "gpg --batch --no-tty --yes --output #{output_file} "+
287
- "--passphrase-file #{passphrase_file} --decrypt #{gpg_file}"
288
-
289
- @shell.call "mkdir -p #{File.dirname(passphrase_file)}"
290
-
291
- @shell.make_file passphrase_file, passphrase
292
-
293
- @shell.call "cd #{self.checkout_path} && #{gpg_cmd}"
294
- @shell.call "rm -f #{passphrase_file}"
295
- end
296
-
297
-
298
275
  ##
299
276
  # Check if this server app includes the specified roles:
300
277
  # server_app.has_roles? :web
@@ -418,7 +395,7 @@ fi
418
395
  # Adds the app to the deploy server's deployed-apps list
419
396
 
420
397
  def register_as_deployed
421
- AddCommand.exec self.root_path, 'servers' => [@shell]
398
+ AddCommand.exec "#{self.name}:#{self.root_path}", 'servers' => [@shell]
422
399
  end
423
400
 
424
401
 
@@ -523,7 +500,7 @@ fi
523
500
  def run_script! name, options=nil, &block
524
501
  options ||= {}
525
502
 
526
- script_path = File.join self.root_path, name.to_s
503
+ script_path = File.join self.scripts_path, name.to_s
527
504
  @shell.call script_path, options, &block
528
505
  end
529
506
 
@@ -638,15 +615,13 @@ fi
638
615
 
639
616
 
640
617
  ##
641
- # Creates a symlink of every script in the scripts_path dir in the
618
+ # Creates a symlink of every script_name from the scripts_path dir to the
642
619
  # app's root directory for easy access.
643
620
 
644
- def symlink_scripts_to_root
645
- scripts = @shell.call("ls -1 #{self.scripts_path}").split("\n")
646
-
647
- scripts.each do |name|
648
- script_file = File.join self.scripts_path, name
649
- pointer_file = File.join self.root_path, name
621
+ def symlink_scripts_to_root *script_names
622
+ script_names.flatten.each do |name, val|
623
+ script_file = File.join self.scripts_path, name.to_s
624
+ pointer_file = File.join self.root_path, name.to_s
650
625
 
651
626
  @shell.symlink script_file, pointer_file
652
627
  end
@@ -669,45 +644,6 @@ fi
669
644
  end
670
645
 
671
646
 
672
- ##
673
- # Upload common rake tasks from a local path or the sunshine lib.
674
- # app.upload_tasks
675
- # #=> upload all tasks
676
- # app.upload_tasks 'app', 'common', ...
677
- # #=> upload app and common rake files
678
- #
679
- # File paths may also be used instead of the file's base name but
680
- # directory structures will not be followed:
681
- # app.upload_tasks 'lib/common/app.rake', 'lib/do_thing.rake'
682
- #
683
- # Allows options:
684
- # :local_path:: str - the path to get rake tasks from
685
- # :remote_path:: str - the remote absolute path to upload the files to
686
-
687
- def upload_tasks *files
688
- options = Hash === files[-1] ? files.delete_at(-1) : {}
689
- remote_path = options[:remote_path] || "#{self.checkout_path}/lib/tasks"
690
- local_path = options[:local_path] || "#{Sunshine::ROOT}/templates/tasks"
691
-
692
- @shell.call "mkdir -p #{remote_path}"
693
-
694
- files.map! do |file|
695
- if File.basename(file) == file
696
- File.join(local_path, "#{file}.rake")
697
- else
698
- file
699
- end
700
- end
701
-
702
- files = Dir.glob("#{Sunshine::ROOT}/templates/tasks/*") if files.empty?
703
-
704
- files.each do |file|
705
- remote_file = File.join remote_path, File.basename(file)
706
- @shell.upload file, remote_file
707
- end
708
- end
709
-
710
-
711
647
  ##
712
648
  # Write an executable bash script to the app's scripts dir
713
649
  # on the deploy server, and symlink them to the root dir.
@@ -738,7 +674,7 @@ fi
738
674
  @shared_path = "#{@root_path}/shared"
739
675
  @log_path = "#{@shared_path}/log"
740
676
  @checkout_path = "#{@deploys_path}/#{@deploy_name}"
741
- @scripts_path = "#{@checkout_path}/sunshine_scripts"
677
+ @scripts_path = "#{@current_path}/script"
742
678
  end
743
679
  end
744
680
  end
@@ -25,7 +25,7 @@ module Sunshine
25
25
  self.sudo_failed_matcher = /^Sorry, try again./
26
26
  self.sudo_prompt_matcher = /^Password:/
27
27
 
28
- attr_reader :user, :host, :password, :input, :output, :mutex
28
+ attr_reader :user, :host, :password, :input, :output, :mutex, :pid
29
29
  attr_accessor :env, :sudo, :timeout
30
30
 
31
31
  def initialize output = $stdout, options={}
@@ -42,8 +42,9 @@ module Sunshine
42
42
  @password = options[:password]
43
43
 
44
44
  @timeout = options[:timeout] || Sunshine.timeout
45
+ @idle_time = options[:idle_after] || 1
45
46
 
46
- @mutex = nil
47
+ @mutex = @pid = nil
47
48
  end
48
49
 
49
50
 
@@ -149,6 +150,31 @@ module Sunshine
149
150
  end
150
151
 
151
152
 
153
+ ##
154
+ # Checks if timeout occurred.
155
+
156
+ def timed_out? start_time=@cmd_activity, max_time=@timeout
157
+ return unless max_time
158
+ Time.now.to_f - start_time.to_f > max_time
159
+ end
160
+
161
+
162
+ ##
163
+ # Update the time of the last command activity
164
+
165
+ def update_activity
166
+ @cmd_activity = Time.now
167
+ end
168
+
169
+
170
+ ##
171
+ # Checks if shell is still receiving data.
172
+
173
+ def idle? start_time=@cmd_activity, max_time=@idle_time
174
+ timed_out? start_time, max_time
175
+ end
176
+
177
+
152
178
  ##
153
179
  # Start an interactive shell with preset permissions and env.
154
180
  # Optionally pass a command to be run first.
@@ -273,15 +299,6 @@ module Sunshine
273
299
  end
274
300
 
275
301
 
276
- ##
277
- # Checks if timeout occurred.
278
-
279
- def timed_out? start_time, max_time=@timeout
280
- return unless max_time
281
- Time.now.to_i - start_time.to_i > max_time
282
- end
283
-
284
-
285
302
  ##
286
303
  # Execute a block while setting the shell's mutex.
287
304
  # Sets the mutex to its original value on exit.
@@ -336,29 +353,28 @@ module Sunshine
336
353
 
337
354
  def execute cmd
338
355
  cmd = [cmd] unless Array === cmd
339
- pid, inn, out, err = popen4(*cmd)
356
+ @pid, inn, out, err = popen4(*cmd)
340
357
 
341
358
  inn.sync = true
342
359
  log_methods = {out => :debug, err => :error}
343
360
 
344
- result, status = process_streams(pid, out, err) do |stream, data|
361
+ result, status = process_streams(@pid, out, err) do |stream, data|
345
362
  stream_name = :out if stream == out
346
363
  stream_name = :err if stream == err
347
364
  stream_name = :inn if stream == inn
348
365
 
366
+ Sunshine.logger.send log_methods[stream],
367
+ "#{@host}:#{stream_name}", data
349
368
 
350
369
  # User blocks should run with sync threads to avoid badness.
351
370
  sync do
352
- Sunshine.logger.send log_methods[stream],
353
- "#{@host}:#{stream_name}", data
354
-
355
371
  yield(stream_name, data, inn) if block_given?
356
372
  end
357
373
 
358
374
 
359
375
  if password_required?(stream_name, data) then
360
376
 
361
- kill_process(pid) unless Sunshine.interactive?
377
+ kill_process(@pid) unless Sunshine.interactive?
362
378
 
363
379
  send_password_to_stream(inn, data)
364
380
  end
@@ -372,6 +388,7 @@ module Sunshine
372
388
  inn.close rescue nil
373
389
  out.close rescue nil
374
390
  err.close rescue nil
391
+ @pid = nil
375
392
  end
376
393
 
377
394
 
@@ -405,7 +422,7 @@ module Sunshine
405
422
 
406
423
  def process_streams pid, *streams
407
424
  result = Hash.new{|h,k| h[k] = []}
408
- start_time = Time.now
425
+ update_activity
409
426
 
410
427
  # Handle process termination ourselves
411
428
  status = nil
@@ -417,13 +434,14 @@ module Sunshine
417
434
  # don't busy loop
418
435
  selected, = select streams, nil, nil, 0.1
419
436
 
420
- raise TimeoutError if timed_out? start_time
437
+ puts "#{@host} IDLE..." if idle?
438
+ raise TimeoutError if timed_out?
421
439
 
422
440
  next if selected.nil? or selected.empty?
423
441
 
424
442
  selected.each do |stream|
425
443
 
426
- start_time = Time.now
444
+ update_activity
427
445
 
428
446
  if stream.eof? then
429
447
  streams.delete stream if status # we've quit, so no more writing
@@ -1,4 +1,3 @@
1
- LoadModule log_config_module modules/mod_log_config.so
2
1
  LoadModule authz_host_module modules/mod_authz_host.so
3
2
 
4
3
  ErrorLog <%= expand_path log_file(:stderr) %>
@@ -25,7 +24,6 @@ MaxClients <%= connections %>
25
24
 
26
25
  <% if sudo == true || sudo == 'root' -%>
27
26
  User nobody
28
- Group nobody
29
27
  <% end -%>
30
28
 
31
29
  Listen <%= port %>
@@ -92,12 +92,6 @@ namespace :sunshine do
92
92
 
93
93
  # Post-deploy control tasks:
94
94
 
95
- desc "Run db:migrate on remote :db servers"
96
- task :db_migrate => :app do
97
- @app.rake 'db:migrate', :role => :db
98
- end
99
-
100
-
101
95
  desc "Run the remote start script"
102
96
  task :start => :app do
103
97
  @app.start
@@ -129,31 +123,4 @@ namespace :sunshine do
129
123
  task :info => :app do
130
124
  puts @app.deploy_details.to_yaml
131
125
  end
132
-
133
-
134
- desc "Get the health state"
135
- task :health => :app do
136
- puts @app.health.to_yaml
137
- end
138
-
139
-
140
- namespace :health do
141
-
142
- desc "Turn on health check"
143
- task :enable => :app do
144
- puts @app.health(:enable).to_yaml
145
- end
146
-
147
-
148
- desc "Turn off health check"
149
- task :disable => :app do
150
- puts @app.health(:disable).to_yaml
151
- end
152
-
153
-
154
- desc "Remove health check"
155
- task :remove => :app do
156
- puts @app.health(:remove).to_yaml
157
- end
158
- end
159
126
  end