capricorn 0.2.00

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.
Files changed (52) hide show
  1. data/app_generators/engine/engine_generator.rb +39 -0
  2. data/app_generators/engine/templates/Gmfile +20 -0
  3. data/app_generators/engine/templates/MIT-LICENSE.txt +20 -0
  4. data/app_generators/engine/templates/README.rdoc +7 -0
  5. data/app_generators/engine/templates/config/routes.rb +2 -0
  6. data/app_generators/engine/templates/gitignore +3 -0
  7. data/app_generators/engine/templates/init.rb +1 -0
  8. data/app_generators/engine/templates/lib/engine.rb +1 -0
  9. data/app_generators/engine/templates/rails/init.rb +1 -0
  10. data/app_generators/engine/templates/tasks/engine_tasks.rake +4 -0
  11. data/bin/capricorn +20 -0
  12. data/lib/capricorn.rb +100 -0
  13. data/lib/capricorn/actor.rb +23 -0
  14. data/lib/capricorn/actor/actions.rb +76 -0
  15. data/lib/capricorn/actors/apache_actor.rb +56 -0
  16. data/lib/capricorn/actors/base_actor.rb +276 -0
  17. data/lib/capricorn/actors/mysql_actor.rb +20 -0
  18. data/lib/capricorn/actors/passenger_actor.rb +19 -0
  19. data/lib/capricorn/actors/plesk_actor.rb +210 -0
  20. data/lib/capricorn/actors/sqlite3_actor.rb +44 -0
  21. data/lib/capricorn/app_runner.rb +119 -0
  22. data/lib/capricorn/apps/dev.rb +15 -0
  23. data/lib/capricorn/apps/engines.rb +33 -0
  24. data/lib/capricorn/apps/jobs.rb +35 -0
  25. data/lib/capricorn/apps/satellite.rb +32 -0
  26. data/lib/capricorn/apps/server.rb +67 -0
  27. data/lib/capricorn/client.rb +48 -0
  28. data/lib/capricorn/client/auth_token.rb +98 -0
  29. data/lib/capricorn/daemon.rb +71 -0
  30. data/lib/capricorn/exception_handler.rb +79 -0
  31. data/lib/capricorn/extentions/rubygems_plugin.rb +27 -0
  32. data/lib/capricorn/extentions/thor_extentions.rb +32 -0
  33. data/lib/capricorn/job_queue.rb +199 -0
  34. data/lib/capricorn/satellite.rb +50 -0
  35. data/lib/capricorn/satellite/actions.rb +35 -0
  36. data/lib/capricorn/satellite/dependency_loader.rb +78 -0
  37. data/lib/capricorn/satellite/persistence.rb +50 -0
  38. data/lib/capricorn/server.rb +122 -0
  39. data/lib/capricorn/server/daemon.rb +88 -0
  40. data/lib/capricorn/server/proxy.rb +25 -0
  41. data/lib/capricorn/server/security.rb +113 -0
  42. data/lib/capricorn/system.rb +184 -0
  43. data/lib/capricorn/system/config.rb +49 -0
  44. data/lib/capricorn/system/helper.rb +21 -0
  45. data/lib/capricorn/system/options.rb +79 -0
  46. data/lib/capricorn/system/process_user.rb +73 -0
  47. data/lib/capricorn/system/satellites.rb +44 -0
  48. data/lib/capricorn/system/shell.rb +80 -0
  49. data/lib/rubygems_plugin.rb +1 -0
  50. data/spec/actor/actions_spec.rb +13 -0
  51. data/spec/spec_helper.rb +1 -0
  52. metadata +108 -0
@@ -0,0 +1,122 @@
1
+
2
+ module Capricorn
3
+
4
+ # the Server is supposed to be a simple DRb interface to the System.
5
+ class Server < Capricorn::Daemon::Base
6
+ include DRbUndumped
7
+
8
+ autoload :Proxy, File.dirname(__FILE__)+'/server/proxy'
9
+ autoload :Daemon, File.dirname(__FILE__)+'/server/daemon'
10
+ autoload :Security, File.dirname(__FILE__)+'/server/security'
11
+
12
+ include Capricorn::Server::Daemon
13
+ include Capricorn::Server::Security
14
+
15
+ def self.shared
16
+ @shared ||= new
17
+ end
18
+
19
+ def self.proxy
20
+ @proxy ||= Capricorn::Server::Proxy.new(self.shared)
21
+ end
22
+
23
+ def stop_server
24
+ Capricorn.log "stopping the server..."
25
+ $exitstatus = Capricorn::STOP_STATUS
26
+ DRb.stop_service
27
+ end
28
+
29
+ def restart_server
30
+ Capricorn.log "restarting the server..."
31
+ $exitstatus = Capricorn::RESTART_STATUS
32
+ DRb.stop_service
33
+ end
34
+
35
+ def reload_server
36
+ Capricorn.log "reloading the server..."
37
+ $exitstatus = Capricorn::RELOAD_STATUS
38
+ DRb.stop_service
39
+ end
40
+
41
+ def server_version
42
+ Capricorn.version
43
+ end
44
+
45
+ def update_server
46
+ if Capricorn.system.gem_update('capricorn', :user => 'root')
47
+ reload_server
48
+ end
49
+ end
50
+
51
+ def install_satellite(domain)
52
+ Capricorn.system.install_satellite(domain)
53
+ end
54
+
55
+ def uninstall_satellite(domain)
56
+ satellite = Capricorn.system.find_satellite(domain)
57
+ if satellite
58
+ Capricorn.system.uninstall_satellite(satellite)
59
+ else
60
+ Capricorn.log "Satellite not found (#{domain})"
61
+ end
62
+ end
63
+
64
+ def make_development_satellite(domain)
65
+ satellite = Capricorn.system.find_satellite(domain)
66
+ if satellite
67
+ Capricorn.system.make_development_satellite(satellite)
68
+ else
69
+ Capricorn.log "Satellite not found (#{domain})"
70
+ end
71
+ end
72
+
73
+ def install_engine(domain, name, options={})
74
+ satellite = Capricorn.system.find_satellite(domain)
75
+ if satellite
76
+ Capricorn.system.install_engine(satellite, name, options)
77
+ else
78
+ Capricorn.log "Satellite not found (#{domain})"
79
+ end
80
+ end
81
+
82
+ def update_engine(domain, name, options={})
83
+ satellite = Capricorn.system.find_satellite(domain)
84
+ if satellite
85
+ Capricorn.system.update_engine(satellite, name, options)
86
+ else
87
+ Capricorn.log "Satellite not found (#{domain})"
88
+ end
89
+ end
90
+
91
+ def uninstall_engine(domain, name)
92
+ satellite = Capricorn.system.find_satellite(domain)
93
+ if satellite
94
+ Capricorn.system.uninstall_engine(satellite, name)
95
+ else
96
+ Capricorn.log "Satellite not found (#{domain})"
97
+ end
98
+ end
99
+
100
+ def satellites
101
+ Capricorn.system.satellites
102
+ end
103
+
104
+ def queued_jobs
105
+ queued_jobs = []
106
+ Capricorn.system.queue.each do |job, canceled, immediated|
107
+ job_delay = job.delay
108
+ queued_jobs.push([job.id, job.name, canceled, immediated, job.running?, job.waiting?, job_delay])
109
+ end
110
+ queued_jobs
111
+ end
112
+
113
+ def cancel_job(id)
114
+ Capricorn.system.queue.cancel(id)
115
+ end
116
+
117
+ def immediate_job(id)
118
+ Capricorn.system.queue.immediate(id)
119
+ end
120
+
121
+ end
122
+ end
@@ -0,0 +1,88 @@
1
+
2
+ module Capricorn
3
+ class Server
4
+
5
+ module Daemon # :nodoc:
6
+
7
+ def self.included(base)
8
+ base.extend Capricorn::Server::Daemon::ClassMethods
9
+ end
10
+
11
+ # all a daemon needs to run
12
+ module ClassMethods
13
+
14
+ # construct a Capricorn uri from a DRb uri
15
+ def construct_uri(uri)
16
+ uri = URI.parse(uri)
17
+ uri.scheme = ( Capricorn.system.use_ssl? ? 'ssl+capricorn' : 'capricorn')
18
+ uri.to_s
19
+ end
20
+
21
+ # stop the server
22
+ def stop
23
+ Capricorn.client.stop_server
24
+ end
25
+
26
+ # start the server
27
+ def start
28
+ start_with_failsafe
29
+ end
30
+
31
+ # start the failsafe runner.
32
+ def start_with_failsafe
33
+ $master = true
34
+ stop_server = false
35
+ wait_before_start = 0
36
+ retries = 0
37
+ until stop_server
38
+ if wait_before_start > 0
39
+ sleep(wait_before_start)
40
+ wait_before_start = 0
41
+ end
42
+
43
+ pid = Process.fork { self.run_server }
44
+ return unless pid
45
+ Process.waitpid(pid, 0)
46
+ case $?.exitstatus
47
+ when Capricorn::STOP_STATUS
48
+ stop_server = true
49
+ retries = 0
50
+ when Capricorn::RESTART_STATUS
51
+ wait_before_start = 2
52
+ retries = 0
53
+ when Capricorn::RELOAD_STATUS
54
+ stop_server = true
55
+ retries = 0
56
+ Capricorn::Daemon::PidFile.destroy
57
+ Capricorn.system.run %{#{Capricorn::BIN_PATH} #{ORIGINAL_ARGV.join(' ')}}
58
+ else
59
+ retries += 1
60
+ stop_server = true if retries >= 3
61
+ end
62
+ end
63
+ end
64
+
65
+ # start the actual DRb server
66
+ def run_server
67
+ $master = false
68
+ Dir.chdir(Capricorn.system.root)
69
+
70
+ Capricorn.log "Server started"
71
+ uri = "druby://#{Capricorn.system.server_hostname}:#{Capricorn.system.server_port}"
72
+ DRb.start_service uri, self.proxy, self.options_for_server
73
+ Capricorn.log "listening at #{self.construct_uri(uri)}"
74
+ make_client_cert_public!
75
+
76
+ at_exit do
77
+ Capricorn.system.queue.stop!
78
+ Capricorn.log "Server stopped"
79
+ end
80
+
81
+ DRb.thread.join
82
+ exit($exitstatus || Capricorn::STOP_STATUS)
83
+ end
84
+
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,25 @@
1
+
2
+ module Capricorn
3
+ class Server
4
+ # the proxy object hides all the server internals from the clients.
5
+ class Proxy
6
+
7
+ def initialize(server)
8
+ @server = server
9
+ end
10
+
11
+ def self.allow(*methods)
12
+ methods.each do |method|
13
+ module_eval %{ def #{method}(*args,&block) ; @server.#{method}(*args,&block) ; end }
14
+ end
15
+ end
16
+
17
+ allow :stop_server, :restart_server, :reload_server, :server_version, :update_server, :install_satellite, :uninstall_satellite, :install_engine, :update_engine, :uninstall_engine, :satellites, :queued_jobs, :cancel_job, :immediate_job, :make_development_satellite
18
+
19
+ class << self
20
+ undef_method :allow
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,113 @@
1
+
2
+ module Capricorn
3
+ class Server
4
+ module Security # :nodoc:
5
+
6
+ def self.included(base)
7
+ base.extend Capricorn::Server::Security::ClassMethods
8
+ end
9
+
10
+ module ClassMethods
11
+
12
+ def options_for_server
13
+
14
+ config = {}
15
+ if Capricorn.system.use_ssl?
16
+ install_quick_cert!
17
+ dump_quick_cert_config!
18
+ run_quick_cert!
19
+
20
+ keypair = Capricorn.system.path('quick_cert', 'capricorn', 'capricorn_keypair.pem')
21
+ cert = Capricorn.system.path('quick_cert', 'capricorn', 'cert_capricorn.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 => Capricorn.system.path('quick_cert', 'CA', 'cacert.pem')
28
+ }
29
+ end
30
+
31
+ config
32
+ end
33
+
34
+ def install_quick_cert!
35
+ unless Capricorn.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
+ Capricorn.system.run "curl -O #{Capricorn::QUICK_CERT}"
41
+ Capricorn.system.run "tar xzf QuickCert-1.0.2.tar.gz"
42
+
43
+ Dir.chdir('/tmp/quick_cert/QuickCert-1.0.2') do
44
+ Capricorn.system.run "#{Capricorn.system.ruby_path} ./setup.rb config"
45
+ Capricorn.system.run "#{Capricorn.system.ruby_path} ./setup.rb setup"
46
+ Capricorn.system.run "#{Capricorn.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? Capricorn.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 => 'capricorn',
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(Capricorn.system.path('quick_cert'))
80
+ File.chmod(0700, Capricorn.system.path('quick_cert'))
81
+ File.open(Capricorn.system.path('quick_cert', 'qc_config'), 'w+') { |f| f.write config }
82
+ end
83
+
84
+ def run_quick_cert!
85
+ return if File.directory? Capricorn.system.path('quick_cert', 'CA')
86
+
87
+ Dir.chdir(Capricorn.system.path('quick_cert')) do
88
+ Capricorn.system.run Capricorn.system.find_bin('QuickCert')
89
+ end
90
+ end
91
+
92
+ def make_client_cert_public!
93
+ token = nil
94
+ if Capricorn.system.use_ssl?
95
+ token = Capricorn::Client::AuthToken.new(
96
+ :target_uri => self.construct_uri(DRb.uri),
97
+ :verify_mode => OpenSSL::SSL::VERIFY_PEER,
98
+ :private_key_data => File.read(Capricorn.system.path('quick_cert', 'core', 'core_keypair.pem')),
99
+ :certificate_data => File.read(Capricorn.system.path('quick_cert', 'core', 'cert_core.pem')),
100
+ :ca_certificate_data => File.read(Capricorn.system.path('quick_cert', 'CA', 'cacert.pem'))
101
+ )
102
+ else
103
+ token = Capricorn::Client::AuthToken.new(
104
+ :target_uri => self.construct_uri(DRb.uri))
105
+ end
106
+ token.dump_file(Capricorn.system.path('core.token'))
107
+ FileUtils.chmod_R(0775, Capricorn.system.path('core.token'))
108
+ end
109
+
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,184 @@
1
+
2
+ module Capricorn
3
+ class System
4
+ include DRbUndumped
5
+
6
+ autoload :Shell, File.dirname(__FILE__)+'/system/shell'
7
+ autoload :Config, File.dirname(__FILE__)+'/system/config'
8
+ autoload :Helper, File.dirname(__FILE__)+'/system/helper'
9
+ autoload :Options, File.dirname(__FILE__)+'/system/options'
10
+ autoload :Satellites, File.dirname(__FILE__)+'/system/satellites'
11
+ autoload :ProcessUser, File.dirname(__FILE__)+'/system/process_user'
12
+
13
+ include Capricorn::System::Shell
14
+ include Capricorn::System::Config
15
+ include Capricorn::System::Helper
16
+ include Capricorn::System::Options
17
+ include Capricorn::System::Satellites
18
+ include Capricorn::System::ProcessUser
19
+
20
+ # get the shared system. this will also set the shared system if you pass a new system as its argument.
21
+ def self.shared(system=nil)
22
+ @system = system if system
23
+ @system
24
+ end
25
+
26
+ # load the shared system
27
+ def self.load!(root=nil)
28
+ @system = new(root)
29
+ end
30
+
31
+ def initialize(root=nil)
32
+ unless root
33
+ if get_user_name == 'root'
34
+ root = Capricorn::DEFAULT_ROOT_SYSTEM_DIR
35
+ else
36
+ root = Capricorn::DEFAULT_USER_SYSTEM_DIR
37
+ end
38
+ end
39
+
40
+ @root = File.expand_path(root)
41
+ @actors = []
42
+ @options = {}
43
+ @option_descriptors = []
44
+ @satellite_options = {}
45
+ @satellite_option_descriptors = []
46
+
47
+ system_file = self.path('system.rb')
48
+ unless File.file? system_file
49
+ Capricorn.log "No system file found (#{system_file})"
50
+ exit(1)
51
+ end
52
+
53
+ Capricorn::ExceptionHandler.setup(self.path('ServerNormal.log'), self.path('ServerError.log'))
54
+
55
+ use :BaseActor
56
+ self.instance_eval File.read(system_file)
57
+ self.resolve_options!
58
+ end
59
+
60
+ attr_accessor :current_satellite, :root
61
+
62
+ def queue
63
+ @queue ||= Capricorn::JobQueue.new
64
+ end
65
+
66
+ def path(*args)
67
+ File.join(@root, *args)
68
+ end
69
+
70
+ def install_satellite(domain)
71
+ self.queue.enqueue("install new satellite #{domain}", :domain => domain) do |options|
72
+ satellite = Capricorn::Satellite.new(options[:domain])
73
+
74
+ run_action_on :install_satellite, satellite
75
+ run_action_on :link_satellite, satellite
76
+ save_satellite! satellite
77
+ end
78
+ end
79
+
80
+ def uninstall_satellite(satellite)
81
+ if satellite
82
+ self.queue.enqueue("uninstall #{satellite.domain}", :satellite => satellite) do |options|
83
+ run_action_on :uninstall_satellite, options[:satellite]
84
+ destroy_satellite! options[:satellite]
85
+ end
86
+ else
87
+ false
88
+ end
89
+ end
90
+
91
+ def make_development_satellite(satellite)
92
+ if satellite
93
+ Capricorn.runtime_gem('rubigen', Capricorn::RUBIGEN_VERSION)
94
+ resolve_options_with satellite do
95
+ as_user(web_user, web_group) do
96
+ Dir.chdir(File.dirname(satellite_root)) do
97
+
98
+ name = File.basename(satellite_root)
99
+
100
+ FileUtils.rm_r("#{name}/doc", :verbose => true) rescue nil
101
+ FileUtils.rm_r("#{name}/README", :verbose => true) rescue nil
102
+ FileUtils.rm_r("#{name}/public/javascripts", :verbose => true) rescue nil
103
+
104
+ require 'rubigen/scripts/generate'
105
+ RubiGen::Base.use_application_sources!
106
+ RubiGen::Scripts::Generate.new.run(["-f", name], :generator => 'engine')
107
+
108
+ end
109
+ end
110
+ end
111
+ else
112
+ false
113
+ end
114
+ end
115
+
116
+ def install_engine(satellite, name, options={})
117
+ if satellite
118
+ self.queue.enqueue("install #{satellite.domain}: #{name} #{options.inspect}",
119
+ :satellite => satellite, :name => name, :options => options) do |options|
120
+
121
+ satellite, name, options = options[:satellite], options[:name], options[:options]
122
+ resolve_options_with(satellite) { ensure_presence_of_gem(name, options) }
123
+ if satellite.add_engine(name, options)
124
+ run_action_on :install_engine, satellite
125
+ run_action_on :link_satellite, satellite
126
+ save_satellite! satellite
127
+ end
128
+
129
+ end
130
+ else
131
+ false
132
+ end
133
+ end
134
+
135
+ def update_engine(satellite, name, options={})
136
+ if satellite
137
+ self.queue.enqueue("update #{satellite.domain}: #{name} #{options.inspect}",
138
+ :satellite => satellite, :name => name, :options => options) do |options|
139
+
140
+ satellite, name, options = options[:satellite], options[:name], options[:options]
141
+ resolve_options_with(satellite) { ensure_presence_of_gem(name, options) }
142
+ if satellite.update_engine(name, options)
143
+ run_action_on :update_engine, satellite
144
+ run_action_on :link_satellite, satellite
145
+ save_satellite! satellite
146
+ end
147
+
148
+ end
149
+ else
150
+ false
151
+ end
152
+ end
153
+
154
+ def uninstall_engine(satellite, name)
155
+ if satellite
156
+ self.queue.enqueue("uninstall #{satellite.domain}: #{name}",
157
+ :satellite => satellite, :name => name) do |options|
158
+
159
+ satellite, name = options[:satellite], options[:name]
160
+ if satellite.remove_engine(name)
161
+ run_action_on :uninstall_engine, satellite
162
+ run_action_on :link_satellite, satellite
163
+ save_satellite! satellite
164
+ end
165
+
166
+ end
167
+ else
168
+ false
169
+ end
170
+ end
171
+
172
+ private
173
+
174
+ def run_action_on(action, satellite)
175
+ resolve_options_with satellite do
176
+ actors = @actors.collect { |actor_klass| actor_klass.new(self, satellite) }
177
+ actors.each { |actor| actor.run_callbacks_in_fase! action, :before }
178
+ actors.each { |actor| actor.run_callbacks_in_fase! action, :on }
179
+ actors.each { |actor| actor.run_callbacks_in_fase! action, :after }
180
+ end
181
+ end
182
+
183
+ end
184
+ end