simonmenke-shuttle 0.1.07

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/app_generators/engine/engine_generator.rb +39 -0
  2. data/app_generators/engine/templates/config/routes.rb +2 -0
  3. data/app_generators/engine/templates/init.rb +1 -0
  4. data/app_generators/engine/templates/lib/engine.rb +1 -0
  5. data/app_generators/engine/templates/rails/init.rb +1 -0
  6. data/bin/shuttle +20 -0
  7. data/lib/rubygems_plugin.rb +1 -0
  8. data/lib/shuttle/actor/actions.rb +76 -0
  9. data/lib/shuttle/actor.rb +23 -0
  10. data/lib/shuttle/actors/apache_actor.rb +56 -0
  11. data/lib/shuttle/actors/base_actor.rb +276 -0
  12. data/lib/shuttle/actors/mysql_actor.rb +20 -0
  13. data/lib/shuttle/actors/passenger_actor.rb +19 -0
  14. data/lib/shuttle/actors/plesk_actor.rb +210 -0
  15. data/lib/shuttle/actors/sqlite3_actor.rb +44 -0
  16. data/lib/shuttle/app_runner.rb +118 -0
  17. data/lib/shuttle/apps/dev.rb +27 -0
  18. data/lib/shuttle/apps/engines.rb +33 -0
  19. data/lib/shuttle/apps/jobs.rb +35 -0
  20. data/lib/shuttle/apps/satellite.rb +32 -0
  21. data/lib/shuttle/apps/server.rb +70 -0
  22. data/lib/shuttle/client/auth_token.rb +98 -0
  23. data/lib/shuttle/client.rb +48 -0
  24. data/lib/shuttle/exception_handler.rb +53 -0
  25. data/lib/shuttle/extentions/rubygems_plugin.rb +27 -0
  26. data/lib/shuttle/extentions/thor_extentions.rb +32 -0
  27. data/lib/shuttle/job_queue.rb +199 -0
  28. data/lib/shuttle/satellite/actions.rb +35 -0
  29. data/lib/shuttle/satellite/dependency_loader.rb +79 -0
  30. data/lib/shuttle/satellite/persistence.rb +50 -0
  31. data/lib/shuttle/satellite.rb +49 -0
  32. data/lib/shuttle/server/daemon.rb +85 -0
  33. data/lib/shuttle/server/proxy.rb +25 -0
  34. data/lib/shuttle/server/security.rb +113 -0
  35. data/lib/shuttle/server.rb +113 -0
  36. data/lib/shuttle/system/config.rb +36 -0
  37. data/lib/shuttle/system/helper.rb +21 -0
  38. data/lib/shuttle/system/options.rb +79 -0
  39. data/lib/shuttle/system/process_user.rb +75 -0
  40. data/lib/shuttle/system/satellites.rb +44 -0
  41. data/lib/shuttle/system/shell.rb +80 -0
  42. data/lib/shuttle/system.rb +159 -0
  43. data/lib/shuttle/systems/centos_plesk_system.rb +28 -0
  44. data/lib/shuttle/systems/macports_system.rb +14 -0
  45. data/lib/shuttle.rb +82 -0
  46. data/spec/actor/actions_spec.rb +13 -0
  47. data/spec/spec_helper.rb +1 -0
  48. 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