simonmenke-shuttle 0.1.07
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/app_generators/engine/engine_generator.rb +39 -0
- data/app_generators/engine/templates/config/routes.rb +2 -0
- data/app_generators/engine/templates/init.rb +1 -0
- data/app_generators/engine/templates/lib/engine.rb +1 -0
- data/app_generators/engine/templates/rails/init.rb +1 -0
- data/bin/shuttle +20 -0
- data/lib/rubygems_plugin.rb +1 -0
- data/lib/shuttle/actor/actions.rb +76 -0
- data/lib/shuttle/actor.rb +23 -0
- data/lib/shuttle/actors/apache_actor.rb +56 -0
- data/lib/shuttle/actors/base_actor.rb +276 -0
- data/lib/shuttle/actors/mysql_actor.rb +20 -0
- data/lib/shuttle/actors/passenger_actor.rb +19 -0
- data/lib/shuttle/actors/plesk_actor.rb +210 -0
- data/lib/shuttle/actors/sqlite3_actor.rb +44 -0
- data/lib/shuttle/app_runner.rb +118 -0
- data/lib/shuttle/apps/dev.rb +27 -0
- data/lib/shuttle/apps/engines.rb +33 -0
- data/lib/shuttle/apps/jobs.rb +35 -0
- data/lib/shuttle/apps/satellite.rb +32 -0
- data/lib/shuttle/apps/server.rb +70 -0
- data/lib/shuttle/client/auth_token.rb +98 -0
- data/lib/shuttle/client.rb +48 -0
- data/lib/shuttle/exception_handler.rb +53 -0
- data/lib/shuttle/extentions/rubygems_plugin.rb +27 -0
- data/lib/shuttle/extentions/thor_extentions.rb +32 -0
- data/lib/shuttle/job_queue.rb +199 -0
- data/lib/shuttle/satellite/actions.rb +35 -0
- data/lib/shuttle/satellite/dependency_loader.rb +79 -0
- data/lib/shuttle/satellite/persistence.rb +50 -0
- data/lib/shuttle/satellite.rb +49 -0
- data/lib/shuttle/server/daemon.rb +85 -0
- data/lib/shuttle/server/proxy.rb +25 -0
- data/lib/shuttle/server/security.rb +113 -0
- data/lib/shuttle/server.rb +113 -0
- data/lib/shuttle/system/config.rb +36 -0
- data/lib/shuttle/system/helper.rb +21 -0
- data/lib/shuttle/system/options.rb +79 -0
- data/lib/shuttle/system/process_user.rb +75 -0
- data/lib/shuttle/system/satellites.rb +44 -0
- data/lib/shuttle/system/shell.rb +80 -0
- data/lib/shuttle/system.rb +159 -0
- data/lib/shuttle/systems/centos_plesk_system.rb +28 -0
- data/lib/shuttle/systems/macports_system.rb +14 -0
- data/lib/shuttle.rb +82 -0
- data/spec/actor/actions_spec.rb +13 -0
- data/spec/spec_helper.rb +1 -0
- metadata +129 -0
@@ -0,0 +1,113 @@
|
|
1
|
+
|
2
|
+
module Shuttle
|
3
|
+
class Server
|
4
|
+
module Security # :nodoc:
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.extend Shuttle::Server::Security::ClassMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
|
12
|
+
def options_for_server
|
13
|
+
|
14
|
+
config = {}
|
15
|
+
if Shuttle.system.use_ssl?
|
16
|
+
install_quick_cert!
|
17
|
+
dump_quick_cert_config!
|
18
|
+
run_quick_cert!
|
19
|
+
|
20
|
+
keypair = Shuttle.system.path('quick_cert', 'shuttle', 'shuttle_keypair.pem')
|
21
|
+
cert = Shuttle.system.path('quick_cert', 'shuttle', 'cert_shuttle.pem')
|
22
|
+
|
23
|
+
config = {
|
24
|
+
:SSLPrivateKey => OpenSSL::PKey::RSA.new(File.read(keypair)),
|
25
|
+
:SSLCertificate => OpenSSL::X509::Certificate.new(File.read(cert)),
|
26
|
+
:SSLVerifyMode => OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT,
|
27
|
+
:SSLCACertificateFile => Shuttle.system.path('quick_cert', 'CA', 'cacert.pem')
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
config
|
32
|
+
end
|
33
|
+
|
34
|
+
def install_quick_cert!
|
35
|
+
unless Shuttle.system.find_bin('QuickCert')
|
36
|
+
FileUtils.mkdir_p('/tmp/quick_cert')
|
37
|
+
File.chmod(0700, '/tmp/quick_cert')
|
38
|
+
|
39
|
+
Dir.chdir('/tmp/quick_cert') do
|
40
|
+
Shuttle.system.run "curl -O #{Shuttle::QUICK_CERT}"
|
41
|
+
Shuttle.system.run "tar xzf QuickCert-1.0.2.tar.gz"
|
42
|
+
|
43
|
+
Dir.chdir('/tmp/quick_cert/QuickCert-1.0.2') do
|
44
|
+
Shuttle.system.run "#{Shuttle.system.ruby_path} ./setup.rb config"
|
45
|
+
Shuttle.system.run "#{Shuttle.system.ruby_path} ./setup.rb setup"
|
46
|
+
Shuttle.system.run "#{Shuttle.system.ruby_path} ./setup.rb install"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
FileUtils.rm_rf('/tmp/quick_cert')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def dump_quick_cert_config!
|
55
|
+
return if File.file? Shuttle.system.path('quick_cert', 'qc_config')
|
56
|
+
|
57
|
+
config = %{
|
58
|
+
full_hostname = `hostname`.strip
|
59
|
+
domainname = full_hostname.split('.')[1..-1].join('.')
|
60
|
+
hostname = full_hostname.split('.')[0]
|
61
|
+
|
62
|
+
CA[:hostname] = hostname
|
63
|
+
CA[:domainname] = domainname
|
64
|
+
CA[:CA_dir] = File.join Dir.pwd, "CA"
|
65
|
+
CA[:password] = '#{rand(100_000)}'
|
66
|
+
|
67
|
+
CERTS << {
|
68
|
+
:type => 'server',
|
69
|
+
:hostname => 'shuttle',
|
70
|
+
# :password => '#{rand(100_000)}',
|
71
|
+
}
|
72
|
+
|
73
|
+
CERTS << {
|
74
|
+
:type => 'client',
|
75
|
+
:user => 'core',
|
76
|
+
:email => 'core@mrhenry.be',
|
77
|
+
}
|
78
|
+
}
|
79
|
+
FileUtils.mkdir_p(Shuttle.system.path('quick_cert'))
|
80
|
+
File.chmod(0700, Shuttle.system.path('quick_cert'))
|
81
|
+
File.open(Shuttle.system.path('quick_cert', 'qc_config'), 'w+') { |f| f.write config }
|
82
|
+
end
|
83
|
+
|
84
|
+
def run_quick_cert!
|
85
|
+
return if File.directory? Shuttle.system.path('quick_cert', 'CA')
|
86
|
+
|
87
|
+
Dir.chdir(Shuttle.system.path('quick_cert')) do
|
88
|
+
Shuttle.system.run Shuttle.system.find_bin('QuickCert')
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def make_client_cert_public!
|
93
|
+
token = nil
|
94
|
+
if Shuttle.system.use_ssl?
|
95
|
+
token = Shuttle::Client::AuthToken.new(
|
96
|
+
:target_uri => self.construct_uri(DRb.uri),
|
97
|
+
:verify_mode => OpenSSL::SSL::VERIFY_PEER,
|
98
|
+
:private_key_data => File.read(Shuttle.system.path('quick_cert', 'core', 'core_keypair.pem')),
|
99
|
+
:certificate_data => File.read(Shuttle.system.path('quick_cert', 'core', 'cert_core.pem')),
|
100
|
+
:ca_certificate_data => File.read(Shuttle.system.path('quick_cert', 'CA', 'cacert.pem'))
|
101
|
+
)
|
102
|
+
else
|
103
|
+
token = Shuttle::Client::AuthToken.new(
|
104
|
+
:target_uri => self.construct_uri(DRb.uri))
|
105
|
+
end
|
106
|
+
token.dump_file(Shuttle.system.path('core.token'))
|
107
|
+
FileUtils.chmod_R(0775, Shuttle.system.path('core.token'))
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'drb'
|
2
|
+
require 'drb/ssl'
|
3
|
+
require 'simple-daemon'
|
4
|
+
|
5
|
+
module Shuttle
|
6
|
+
|
7
|
+
# the Server is supposed to be a simple DRb interface to the System.
|
8
|
+
class Server < SimpleDaemon::Base
|
9
|
+
include DRbUndumped
|
10
|
+
|
11
|
+
autoload :Proxy, File.dirname(__FILE__)+'/server/proxy'
|
12
|
+
autoload :Daemon, File.dirname(__FILE__)+'/server/daemon'
|
13
|
+
autoload :Security, File.dirname(__FILE__)+'/server/security'
|
14
|
+
|
15
|
+
include Shuttle::Server::Daemon
|
16
|
+
include Shuttle::Server::Security
|
17
|
+
|
18
|
+
def self.shared
|
19
|
+
@shared ||= new
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.proxy
|
23
|
+
@proxy ||= Shuttle::Server::Proxy.new(self.shared)
|
24
|
+
end
|
25
|
+
|
26
|
+
def stop_server
|
27
|
+
Shuttle.log "stopping the server..."
|
28
|
+
Thread.new { sleep(1) and exit(Shuttle::STOP_STATUS) }
|
29
|
+
end
|
30
|
+
|
31
|
+
def restart_server
|
32
|
+
Shuttle.log "restarting the server..."
|
33
|
+
Thread.new { sleep(1) and exit(Shuttle::RESTART_STATUS) }
|
34
|
+
end
|
35
|
+
|
36
|
+
def reload_server
|
37
|
+
Shuttle.log "reloading the server..."
|
38
|
+
Thread.new { sleep(1) and exit(Shuttle::RELOAD_STATUS) }
|
39
|
+
end
|
40
|
+
|
41
|
+
def server_version
|
42
|
+
Shuttle.version
|
43
|
+
end
|
44
|
+
|
45
|
+
def update_server
|
46
|
+
if Shuttle.system.gem_update('shuttle', :user => 'root')
|
47
|
+
reload_server
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def install_satellite(domain)
|
52
|
+
Shuttle.system.install_satellite(domain)
|
53
|
+
end
|
54
|
+
|
55
|
+
def uninstall_satellite(domain)
|
56
|
+
satellite = Shuttle.system.find_satellite(domain)
|
57
|
+
if satellite
|
58
|
+
Shuttle.system.uninstall_satellite(satellite)
|
59
|
+
else
|
60
|
+
Shuttle.log "Satellite not found (#{domain})"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def install_engine(domain, name, options={})
|
65
|
+
satellite = Shuttle.system.find_satellite(domain)
|
66
|
+
if satellite
|
67
|
+
Shuttle.system.install_engine(satellite, name, options)
|
68
|
+
else
|
69
|
+
Shuttle.log "Satellite not found (#{domain})"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def update_engine(domain, name, options={})
|
74
|
+
satellite = Shuttle.system.find_satellite(domain)
|
75
|
+
if satellite
|
76
|
+
Shuttle.system.update_engine(satellite, name, options)
|
77
|
+
else
|
78
|
+
Shuttle.log "Satellite not found (#{domain})"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def uninstall_engine(domain, name)
|
83
|
+
satellite = Shuttle.system.find_satellite(domain)
|
84
|
+
if satellite
|
85
|
+
Shuttle.system.uninstall_engine(satellite, name)
|
86
|
+
else
|
87
|
+
Shuttle.log "Satellite not found (#{domain})"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def satellites
|
92
|
+
Shuttle.system.satellites
|
93
|
+
end
|
94
|
+
|
95
|
+
def queued_jobs
|
96
|
+
queued_jobs = []
|
97
|
+
Shuttle.system.queue.each do |job, canceled, immediated|
|
98
|
+
job_delay = job.delay
|
99
|
+
queued_jobs.push([job.id, job.name, canceled, immediated, job.running?, job.waiting?, job_delay])
|
100
|
+
end
|
101
|
+
queued_jobs
|
102
|
+
end
|
103
|
+
|
104
|
+
def cancel_job(id)
|
105
|
+
Shuttle.system.queue.cancel(id)
|
106
|
+
end
|
107
|
+
|
108
|
+
def immediate_job(id)
|
109
|
+
Shuttle.system.queue.immediate(id)
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
|
2
|
+
module Shuttle
|
3
|
+
class System
|
4
|
+
module Config
|
5
|
+
|
6
|
+
def use_development!
|
7
|
+
environment { 'development' }
|
8
|
+
end
|
9
|
+
|
10
|
+
def development?
|
11
|
+
environment == 'development'
|
12
|
+
end
|
13
|
+
|
14
|
+
def use_production!
|
15
|
+
environment { 'production' }
|
16
|
+
end
|
17
|
+
|
18
|
+
def production?
|
19
|
+
environment == 'production'
|
20
|
+
end
|
21
|
+
|
22
|
+
def environment(&block)
|
23
|
+
option(:environment, block) { |s,v| v or 'production' }
|
24
|
+
end
|
25
|
+
|
26
|
+
def use_ssl!
|
27
|
+
option(:use_ssl, lambda { true })
|
28
|
+
end
|
29
|
+
|
30
|
+
def use_ssl?
|
31
|
+
option(:use_ssl, nil)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
module Shuttle
|
3
|
+
class System
|
4
|
+
module Helper
|
5
|
+
|
6
|
+
def use(actor)
|
7
|
+
actor_klass = (Shuttle::Actors.const_get(actor) rescue nil)
|
8
|
+
raise "Actor not found! (#{actor})" unless actor_klass
|
9
|
+
|
10
|
+
actor_helper = (actor_klass.const_get('Helper') rescue nil)
|
11
|
+
extend actor_helper if actor_helper
|
12
|
+
|
13
|
+
actor_config = (actor_klass.const_get('Config') rescue nil)
|
14
|
+
extend actor_config if actor_config
|
15
|
+
|
16
|
+
@actors.push(actor_klass)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
|
2
|
+
module Shuttle
|
3
|
+
class System
|
4
|
+
module Options
|
5
|
+
|
6
|
+
def option(name, proc, &handler)
|
7
|
+
if proc
|
8
|
+
@option_descriptors.push({
|
9
|
+
:name => name.to_sym,
|
10
|
+
:proc => proc,
|
11
|
+
:handler => handler
|
12
|
+
})
|
13
|
+
else
|
14
|
+
if handler && !@options.key?(name.to_sym)
|
15
|
+
@options[name.to_sym] = handler.call(nil)
|
16
|
+
end
|
17
|
+
@options[name.to_sym]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def satellite_option(name, proc, &handler)
|
22
|
+
if proc
|
23
|
+
@satellite_option_descriptors.push({
|
24
|
+
:name => name.to_sym,
|
25
|
+
:proc => proc,
|
26
|
+
:handler => handler
|
27
|
+
})
|
28
|
+
else
|
29
|
+
if handler && !@satellite_options.key?(name.to_sym)
|
30
|
+
@satellite_options[name.to_sym] = handler.call(@current_satellite, nil)
|
31
|
+
end
|
32
|
+
@satellite_options[name.to_sym]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def set_satellite_option(name, value)
|
37
|
+
@satellite_options[name.to_sym] = value
|
38
|
+
end
|
39
|
+
|
40
|
+
def resolve_options_with(satellite)
|
41
|
+
@current_satellite = satellite
|
42
|
+
resolve_options!
|
43
|
+
|
44
|
+
result = yield
|
45
|
+
|
46
|
+
@current_satellite = nil
|
47
|
+
resolve_options!
|
48
|
+
|
49
|
+
result
|
50
|
+
end
|
51
|
+
|
52
|
+
def resolve_options!
|
53
|
+
resolve_options_for_system!
|
54
|
+
resolve_options_for_satellite!
|
55
|
+
end
|
56
|
+
|
57
|
+
def resolve_options_for_system!
|
58
|
+
@options = {}
|
59
|
+
@option_descriptors.each do |option|
|
60
|
+
value = option[:proc].call if option[:proc]
|
61
|
+
value = option[:handler].call(value) if option[:handler]
|
62
|
+
@options[option[:name]] = value
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def resolve_options_for_satellite!
|
67
|
+
@satellite_options = {}
|
68
|
+
if @current_satellite
|
69
|
+
@satellite_option_descriptors.each do |option|
|
70
|
+
value = option[:proc].call(@current_satellite) if option[:proc]
|
71
|
+
value = option[:handler].call(@current_satellite, value) if option[:handler]
|
72
|
+
@satellite_options[option[:name]] = value
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
|
2
|
+
autoload :Etc, 'etc'
|
3
|
+
|
4
|
+
module Shuttle
|
5
|
+
class System
|
6
|
+
module ProcessUser
|
7
|
+
|
8
|
+
# get the uid for a user name
|
9
|
+
def get_uid(username)
|
10
|
+
return username if Numeric === username
|
11
|
+
Etc.getpwnam(username).uid
|
12
|
+
end
|
13
|
+
|
14
|
+
# get the gid for a group name
|
15
|
+
def get_gid(groupname)
|
16
|
+
return groupname if Numeric === groupname
|
17
|
+
Etc.getgrnam(groupname).gid
|
18
|
+
end
|
19
|
+
|
20
|
+
# get the user name for a uid (or the current process user)
|
21
|
+
def get_user_name(uid=Process.uid)
|
22
|
+
return uid if String === uid
|
23
|
+
Etc.getpwuid(uid).name
|
24
|
+
end
|
25
|
+
|
26
|
+
# get the group name for a gid (or the current process group)
|
27
|
+
def get_group_name(gid=Process.gid)
|
28
|
+
return gid if String === gid
|
29
|
+
Etc.getgrgid(gid).name
|
30
|
+
end
|
31
|
+
|
32
|
+
# is this process running as this user?
|
33
|
+
def is_user(username)
|
34
|
+
uid = get_uid(username)
|
35
|
+
Process.euid == uid and Process.uid == uid
|
36
|
+
end
|
37
|
+
|
38
|
+
# is this process running as this group?
|
39
|
+
def is_group(groupname)
|
40
|
+
gid = get_gid(groupname)
|
41
|
+
Process.egid == gid and Process.gid == gid
|
42
|
+
end
|
43
|
+
|
44
|
+
# switch this user to the specified user and group
|
45
|
+
def switch_to_user(username, groupname=nil)
|
46
|
+
different_uid = (Process.euid != get_uid(username))
|
47
|
+
different_gid = (Process.egid != get_gid(groupname)) if groupname
|
48
|
+
|
49
|
+
if groupname and different_gid
|
50
|
+
Process.gid = Process.egid = get_gid(groupname)
|
51
|
+
end
|
52
|
+
|
53
|
+
if different_uid
|
54
|
+
Process.uid = Process.euid = get_uid(username)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# run the passed block as the specified user and group
|
59
|
+
def as_user(username, groupname=nil, &block)
|
60
|
+
euid = Process.euid
|
61
|
+
egid = Process.egid
|
62
|
+
|
63
|
+
value = nil
|
64
|
+
begin
|
65
|
+
switch_to_user(username, groupname)
|
66
|
+
value = block.call
|
67
|
+
ensure
|
68
|
+
switch_to_user(euid, egid)
|
69
|
+
end
|
70
|
+
value
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
|
2
|
+
module Shuttle
|
3
|
+
class System
|
4
|
+
module Satellites
|
5
|
+
|
6
|
+
def satellites_hash
|
7
|
+
@satellites || load_satellites
|
8
|
+
end
|
9
|
+
|
10
|
+
def satellites
|
11
|
+
satellites_hash.values
|
12
|
+
end
|
13
|
+
|
14
|
+
def find_satellite(domain)
|
15
|
+
satellites_hash[domain]
|
16
|
+
end
|
17
|
+
|
18
|
+
def save_satellite!(satellite)
|
19
|
+
satellites_hash[satellite.domain] = satellite
|
20
|
+
satellite.dump_file(self.path('satellites', "#{satellite.domain}.yml"))
|
21
|
+
end
|
22
|
+
|
23
|
+
def destroy_satellite!(satellite)
|
24
|
+
satellites_hash.delete(satellite.domain)
|
25
|
+
FileUtils.rm_f(self.path('satellites', "#{satellite.domain}.yml"))
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def load_satellites
|
31
|
+
@satellites = {}
|
32
|
+
|
33
|
+
FileUtils.mkdir_p(self.path('satellites'))
|
34
|
+
Dir.glob(self.path('satellites', '*.yml')).each do |yml|
|
35
|
+
satellite = Shuttle::Satellite.load_file(yml)
|
36
|
+
@satellites[satellite.domain] = satellite
|
37
|
+
end
|
38
|
+
|
39
|
+
@satellites
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
|
2
|
+
module Shuttle
|
3
|
+
class System
|
4
|
+
module Shell
|
5
|
+
|
6
|
+
def run(cmd)
|
7
|
+
as_user 'root', 'wheel' do
|
8
|
+
Shuttle.log "[#{get_user_name}]> "+cmd
|
9
|
+
cmd = "bash -l -c #{cmd.inspect}"
|
10
|
+
output = %x[#{cmd} 2>&1]
|
11
|
+
Shuttle.log output if development?
|
12
|
+
output
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def user_run(username, cmd)
|
17
|
+
as_user 'root', 'wheel' do
|
18
|
+
Shuttle.log "[#{username}]> "+cmd
|
19
|
+
cmd = "su #{username} -l -c #{cmd.inspect}"
|
20
|
+
output = %x[#{cmd} 2>&1]
|
21
|
+
Shuttle.log output if development?
|
22
|
+
output
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def popen(cmd, *args, &block)
|
27
|
+
as_user 'root', 'wheel' do
|
28
|
+
Shuttle.log cmd
|
29
|
+
cmd = "bash -l -c #{cmd.inspect}"
|
30
|
+
IO.popen(cmd, *args, &block)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def user_popen(username, cmd, *args, &block)
|
35
|
+
as_user 'root', 'wheel' do
|
36
|
+
Shuttle.log cmd
|
37
|
+
cmd = "su #{username} -l -c #{cmd.inspect}"
|
38
|
+
IO.popen(cmd, *args, &block)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def find_bin(*names)
|
43
|
+
names = names.flatten.compact.uniq
|
44
|
+
unless names.empty?
|
45
|
+
names = names.join(' ')
|
46
|
+
popen("which #{names}", 'r') do |f|
|
47
|
+
|
48
|
+
until f.eof?
|
49
|
+
path = f.readline
|
50
|
+
next unless path
|
51
|
+
path = path.strip
|
52
|
+
next if path =~ /(Last login)|(You have new)|(Using ruby)/
|
53
|
+
return path
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def user_find_bin(username, *names)
|
61
|
+
names = names.flatten.compact.uniq
|
62
|
+
unless names.empty?
|
63
|
+
names = names.join(' ')
|
64
|
+
user_popen(username, "which #{names}", 'r') do |f|
|
65
|
+
|
66
|
+
until f.eof?
|
67
|
+
path = f.readline
|
68
|
+
next unless path
|
69
|
+
path = path.strip
|
70
|
+
next if path =~ /(Last login)|(You have new)|(Using ruby)/
|
71
|
+
return path
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|