capricorn 0.2.00
Sign up to get free protection for your applications and to get access to all the features.
- data/app_generators/engine/engine_generator.rb +39 -0
- data/app_generators/engine/templates/Gmfile +20 -0
- data/app_generators/engine/templates/MIT-LICENSE.txt +20 -0
- data/app_generators/engine/templates/README.rdoc +7 -0
- data/app_generators/engine/templates/config/routes.rb +2 -0
- data/app_generators/engine/templates/gitignore +3 -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/app_generators/engine/templates/tasks/engine_tasks.rake +4 -0
- data/bin/capricorn +20 -0
- data/lib/capricorn.rb +100 -0
- data/lib/capricorn/actor.rb +23 -0
- data/lib/capricorn/actor/actions.rb +76 -0
- data/lib/capricorn/actors/apache_actor.rb +56 -0
- data/lib/capricorn/actors/base_actor.rb +276 -0
- data/lib/capricorn/actors/mysql_actor.rb +20 -0
- data/lib/capricorn/actors/passenger_actor.rb +19 -0
- data/lib/capricorn/actors/plesk_actor.rb +210 -0
- data/lib/capricorn/actors/sqlite3_actor.rb +44 -0
- data/lib/capricorn/app_runner.rb +119 -0
- data/lib/capricorn/apps/dev.rb +15 -0
- data/lib/capricorn/apps/engines.rb +33 -0
- data/lib/capricorn/apps/jobs.rb +35 -0
- data/lib/capricorn/apps/satellite.rb +32 -0
- data/lib/capricorn/apps/server.rb +67 -0
- data/lib/capricorn/client.rb +48 -0
- data/lib/capricorn/client/auth_token.rb +98 -0
- data/lib/capricorn/daemon.rb +71 -0
- data/lib/capricorn/exception_handler.rb +79 -0
- data/lib/capricorn/extentions/rubygems_plugin.rb +27 -0
- data/lib/capricorn/extentions/thor_extentions.rb +32 -0
- data/lib/capricorn/job_queue.rb +199 -0
- data/lib/capricorn/satellite.rb +50 -0
- data/lib/capricorn/satellite/actions.rb +35 -0
- data/lib/capricorn/satellite/dependency_loader.rb +78 -0
- data/lib/capricorn/satellite/persistence.rb +50 -0
- data/lib/capricorn/server.rb +122 -0
- data/lib/capricorn/server/daemon.rb +88 -0
- data/lib/capricorn/server/proxy.rb +25 -0
- data/lib/capricorn/server/security.rb +113 -0
- data/lib/capricorn/system.rb +184 -0
- data/lib/capricorn/system/config.rb +49 -0
- data/lib/capricorn/system/helper.rb +21 -0
- data/lib/capricorn/system/options.rb +79 -0
- data/lib/capricorn/system/process_user.rb +73 -0
- data/lib/capricorn/system/satellites.rb +44 -0
- data/lib/capricorn/system/shell.rb +80 -0
- data/lib/rubygems_plugin.rb +1 -0
- data/spec/actor/actions_spec.rb +13 -0
- data/spec/spec_helper.rb +1 -0
- metadata +108 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
Capricorn.runtime_gem('thor', Capricorn::THOR_VERSION)
|
2
|
+
|
3
|
+
module Capricorn
|
4
|
+
module Apps
|
5
|
+
class Jobs < Thor
|
6
|
+
|
7
|
+
desc "list", 'list the jobs in the queue'
|
8
|
+
method_options :token => :optional
|
9
|
+
def list
|
10
|
+
queued_jobs = Capricorn.client(options[:token]).queued_jobs
|
11
|
+
queued_jobs.each do |id, name, canceled, immediated, running, waiting, delay|
|
12
|
+
status = []
|
13
|
+
status.push canceled ? 'c' : ' '
|
14
|
+
status.push immediated ? 'i' : ' '
|
15
|
+
status.push running ? 'r' : ' '
|
16
|
+
status.push waiting ? 'w' : ' '
|
17
|
+
puts("% 8d % 8d % 8s %s" % [id, delay.to_i, status.join, name])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
desc "cancel ID", 'cancel the job with ID'
|
22
|
+
method_options :token => :optional
|
23
|
+
def cancel(id)
|
24
|
+
Capricorn.client(options[:token]).cancel_job(id.to_i)
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "immediate ID", 'immediately run the job with ID'
|
28
|
+
method_options :token => :optional
|
29
|
+
def immediate(id)
|
30
|
+
Capricorn.client(options[:token]).immediate_job(id.to_i)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
Capricorn.runtime_gem('thor', Capricorn::THOR_VERSION)
|
2
|
+
|
3
|
+
module Capricorn
|
4
|
+
module Apps # :nodoc:
|
5
|
+
|
6
|
+
class Satellite < Thor
|
7
|
+
desc 'list', 'show all managed satellites'
|
8
|
+
method_options :token => :optional
|
9
|
+
def list
|
10
|
+
Capricorn.client(options[:token]).satellites.each do |sat|
|
11
|
+
puts sat.domain
|
12
|
+
sat.engines.each do |name, options|
|
13
|
+
puts "- #{name} #{options.inspect}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
desc 'install DOMAIN', 'install a satellite'
|
19
|
+
method_options :token => :optional
|
20
|
+
def install(domain)
|
21
|
+
Capricorn.client(options[:token]).install_satellite(domain)
|
22
|
+
end
|
23
|
+
|
24
|
+
desc 'uninstall DOMAIN', 'uninstall a satellite'
|
25
|
+
method_options :token => :optional
|
26
|
+
def uninstall(domain)
|
27
|
+
Capricorn.client(options[:token]).uninstall_satellite(domain)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
Capricorn.runtime_gem('thor', Capricorn::THOR_VERSION)
|
2
|
+
|
3
|
+
module Capricorn
|
4
|
+
module Apps
|
5
|
+
|
6
|
+
class Server < Thor
|
7
|
+
|
8
|
+
desc "start", 'start the server'
|
9
|
+
method_options :foreground => :boolean, :config => :optional
|
10
|
+
def start
|
11
|
+
Capricorn.server? true
|
12
|
+
Capricorn::System.load!(options[:root_path])
|
13
|
+
|
14
|
+
begin
|
15
|
+
FileUtils.mkdir_p(Capricorn.system.root)
|
16
|
+
rescue Errno::EACCES
|
17
|
+
Capricorn.logger.out.fatal "must be executed as root"
|
18
|
+
exit(1)
|
19
|
+
end
|
20
|
+
|
21
|
+
unless Capricorn.system.is_user('root')
|
22
|
+
Capricorn.logger.out.fatal "must be executed as root"
|
23
|
+
exit(1)
|
24
|
+
end
|
25
|
+
|
26
|
+
if options[:foreground]
|
27
|
+
Capricorn::Server.start
|
28
|
+
else
|
29
|
+
Capricorn::Server.daemonize
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "stop", 'stop the server'
|
34
|
+
method_options :token => :optional
|
35
|
+
def stop
|
36
|
+
Capricorn.client(options[:token]).stop_server
|
37
|
+
end
|
38
|
+
|
39
|
+
desc "restart", 'restart the server'
|
40
|
+
method_options :token => :optional
|
41
|
+
def restart
|
42
|
+
Capricorn.client(options[:token]).restart_server
|
43
|
+
end
|
44
|
+
|
45
|
+
desc "reload", 'reload the server'
|
46
|
+
method_options :token => :optional
|
47
|
+
def reload
|
48
|
+
Capricorn.client(options[:token]).reload_server
|
49
|
+
end
|
50
|
+
|
51
|
+
desc "update", 'update the capricorn'
|
52
|
+
method_options :token => :optional
|
53
|
+
def update
|
54
|
+
Capricorn.client(options[:token]).update_server
|
55
|
+
end
|
56
|
+
|
57
|
+
desc "version", 'version of the server'
|
58
|
+
method_options :token => :optional
|
59
|
+
def version
|
60
|
+
puts "Client: #{Capricorn.version}"
|
61
|
+
puts "Server: #{Capricorn.client(options[:token]).server_version}"
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'drb'
|
2
|
+
require 'drb/ssl'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
module Capricorn
|
6
|
+
class Client
|
7
|
+
|
8
|
+
autoload :AuthToken, File.dirname(__FILE__)+'/client/auth_token'
|
9
|
+
|
10
|
+
# return a DRb uri for the given Capricorn uri.
|
11
|
+
def self.parse_uri(uri)
|
12
|
+
uri = URI.parse(uri)
|
13
|
+
use_ssl = (uri.scheme == 'ssl+capricorn')
|
14
|
+
uri.scheme = 'druby'
|
15
|
+
return use_ssl, uri.to_s
|
16
|
+
end
|
17
|
+
|
18
|
+
# return an potentialy initialize the client to the given token.
|
19
|
+
def self.current(token=nil)
|
20
|
+
@client = connect(token) unless @client
|
21
|
+
@client
|
22
|
+
end
|
23
|
+
|
24
|
+
# connect to the server referenced by the given token.
|
25
|
+
def self.connect(token=nil)
|
26
|
+
token ||= 'core.token'
|
27
|
+
|
28
|
+
[Capricorn::DEFAULT_ROOT_SYSTEM_DIR,
|
29
|
+
Capricorn::DEFAULT_USER_SYSTEM_DIR,
|
30
|
+
File.join(Capricorn::DEFAULT_USER_SYSTEM_DIR, 'tokens'),
|
31
|
+
'.'].each do |path|
|
32
|
+
path = File.expand_path(File.join(path, token))
|
33
|
+
if File.file? path
|
34
|
+
token = path
|
35
|
+
break
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
unless File.file? token
|
40
|
+
raise "Unable to read the token at: #{token}"
|
41
|
+
end
|
42
|
+
|
43
|
+
token = Capricorn::Client::AuthToken.load_file(token) if String === token
|
44
|
+
token.connect if token
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Capricorn
|
4
|
+
class Client
|
5
|
+
class AuthToken
|
6
|
+
|
7
|
+
# load a token from the passed IO.
|
8
|
+
def self.load(io)
|
9
|
+
self.new YAML.load(io)
|
10
|
+
end
|
11
|
+
|
12
|
+
# load a token from a file referenced by the given +path+.
|
13
|
+
def self.load_file(path)
|
14
|
+
self.new YAML.load_file(path)
|
15
|
+
end
|
16
|
+
|
17
|
+
# the uri at which the capricorn server can be accessed.
|
18
|
+
attr_reader :target_uri
|
19
|
+
# the SSL verification mode used by the capricorn server
|
20
|
+
attr_reader :verify_mode
|
21
|
+
# the optional CA certificate used by the capricorn server
|
22
|
+
attr_reader :ca_certificate_data
|
23
|
+
# the private key used by the client
|
24
|
+
attr_reader :private_key_data
|
25
|
+
# the certificate used by the client
|
26
|
+
attr_reader :certificate_data
|
27
|
+
|
28
|
+
# create a new token from the given options
|
29
|
+
#
|
30
|
+
# +:target_uri+, +:verify_mode+, +:ca_certificate_data+, +:private_key_data+, +:certificate_data+
|
31
|
+
def initialize(options={})
|
32
|
+
@target_uri = options[:target_uri]
|
33
|
+
@verify_mode = options[:verify_mode]
|
34
|
+
@ca_certificate_data = options[:ca_certificate_data]
|
35
|
+
@private_key_data = options[:private_key_data]
|
36
|
+
@certificate_data = options[:certificate_data]
|
37
|
+
end
|
38
|
+
|
39
|
+
# get the parsed and initialized OpenSSL::X509::Certificate
|
40
|
+
def ca_certificate
|
41
|
+
@ca_certificate ||= OpenSSL::X509::Certificate.new(@ca_certificate_data)
|
42
|
+
end
|
43
|
+
|
44
|
+
# get the parsed and initialized OpenSSL::X509::Certificate
|
45
|
+
def certificate
|
46
|
+
@certificate ||= OpenSSL::X509::Certificate.new(@certificate_data)
|
47
|
+
end
|
48
|
+
|
49
|
+
# get the parsed and initialized OpenSSL::PKey::RSA
|
50
|
+
def private_key
|
51
|
+
@private_key ||= OpenSSL::PKey::RSA.new(@private_key_data)
|
52
|
+
end
|
53
|
+
|
54
|
+
# connect to the server and return the server handle.
|
55
|
+
def connect
|
56
|
+
use_ssl, uri = Capricorn::Client.parse_uri(self.target_uri)
|
57
|
+
if use_ssl
|
58
|
+
DRb.start_service nil, nil, self.options_for_drb
|
59
|
+
else
|
60
|
+
DRb.start_service
|
61
|
+
end
|
62
|
+
DRbObject.new nil, uri
|
63
|
+
end
|
64
|
+
|
65
|
+
# return options for use with DRb
|
66
|
+
def options_for_drb
|
67
|
+
@options_for_drb ||= {
|
68
|
+
:SSLVerifyMode => self.verify_mode,
|
69
|
+
:SSLCACertificate => self.ca_certificate,
|
70
|
+
:SSLPrivateKey => self.private_key,
|
71
|
+
:SSLCertificate => self.certificate
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
# dump this token to the given IO or return the content as a String
|
76
|
+
def dump(io=nil)
|
77
|
+
data = {
|
78
|
+
:target_uri => self.target_uri,
|
79
|
+
:verify_mode => self.verify_mode,
|
80
|
+
:ca_certificate_data => self.ca_certificate_data,
|
81
|
+
:private_key_data => self.private_key_data,
|
82
|
+
:certificate_data => self.certificate_data
|
83
|
+
}
|
84
|
+
if io
|
85
|
+
io.write YAML.dump(data)
|
86
|
+
else
|
87
|
+
YAML.dump(data)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# dump this token to a file at the given +path+.
|
92
|
+
def dump_file(path)
|
93
|
+
File.open(path, 'w+') { |f| dump(f) }
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
|
2
|
+
module Capricorn
|
3
|
+
module Daemon
|
4
|
+
class Base
|
5
|
+
|
6
|
+
def self.daemonize(&block)
|
7
|
+
Capricorn::Daemon::Controller.start(self,&block)
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
module PidFile
|
13
|
+
def self.store(pid)
|
14
|
+
File.open(self.pid_file, 'w') {|f| f << pid}
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.recall
|
18
|
+
IO.read(self.pid_file).to_i rescue nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.destroy
|
22
|
+
FileUtils.rm(self.pid_file) if self.exist?
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.pid_file
|
26
|
+
Capricorn.system.path("Server.pid")
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.exist?
|
30
|
+
File.file?(self.pid_file)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module Controller
|
35
|
+
|
36
|
+
def self.start(daemon, &block)
|
37
|
+
fork do
|
38
|
+
Process.setsid
|
39
|
+
exit if fork
|
40
|
+
if PidFile.exist?
|
41
|
+
puts "Pid file #{PidFile.pid_file} already exists. Not starting."
|
42
|
+
exit 1
|
43
|
+
end
|
44
|
+
Capricorn::Daemon::PidFile.store(Process.pid)
|
45
|
+
Dir.chdir Capricorn.system.root
|
46
|
+
File.umask 0000
|
47
|
+
|
48
|
+
Capricorn::ExceptionHandler.redirect_std
|
49
|
+
|
50
|
+
trap("TERM") { daemon.stop; exit }
|
51
|
+
at_exit { Capricorn::Daemon::PidFile.destroy if $master }
|
52
|
+
at_exit(&block) if block
|
53
|
+
daemon.start
|
54
|
+
end
|
55
|
+
puts "Daemon started."
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.stop
|
59
|
+
if !Capricorn::Daemon::PidFile.exist?
|
60
|
+
puts "Pid file not found. Is the daemon started?"
|
61
|
+
exit
|
62
|
+
end
|
63
|
+
pid = Capricorn::Daemon::PidFile.recall
|
64
|
+
pid && Process.kill("TERM", pid)
|
65
|
+
rescue Errno::ESRCH
|
66
|
+
puts "Pid file found, but process was not running. The daemon may have died."
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
|
2
|
+
module Capricorn
|
3
|
+
module ExceptionHandler
|
4
|
+
|
5
|
+
def self.setup(out=STDOUT, err=STDERR)
|
6
|
+
if String === out
|
7
|
+
@out = Logger.new(out, 'daily')
|
8
|
+
@stdout = @out.instance_variable_get('@logdev').instance_variable_get('@dev')
|
9
|
+
else
|
10
|
+
@out = Logger.new(out)
|
11
|
+
@stdout = out
|
12
|
+
end
|
13
|
+
|
14
|
+
if String === err
|
15
|
+
@err = Logger.new(err, 'daily')
|
16
|
+
@stderr = @err.instance_variable_get('@logdev').instance_variable_get('@dev')
|
17
|
+
else
|
18
|
+
@err = Logger.new(err)
|
19
|
+
@stderr = err
|
20
|
+
end
|
21
|
+
|
22
|
+
@out.level = Logger::DEBUG
|
23
|
+
@err.level = Logger::DEBUG
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.err
|
27
|
+
@err
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.out
|
31
|
+
@out
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.stderr
|
35
|
+
@stderr
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.stdout
|
39
|
+
@stdout
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.redirect_std
|
43
|
+
if STDOUT != self.stdout
|
44
|
+
STDOUT.reopen self.stdout
|
45
|
+
end
|
46
|
+
|
47
|
+
if STDERR != self.stderr
|
48
|
+
STDERR.reopen self.stderr
|
49
|
+
end
|
50
|
+
|
51
|
+
STDIN.reopen "/dev/null"
|
52
|
+
end
|
53
|
+
|
54
|
+
def logger
|
55
|
+
Capricorn::ExceptionHandler
|
56
|
+
end
|
57
|
+
|
58
|
+
def log(*args, &block)
|
59
|
+
args = [args.inspect] if args.size == 1 and Array === args.first
|
60
|
+
logger.out.info(*args, &block)
|
61
|
+
end
|
62
|
+
|
63
|
+
def report
|
64
|
+
yield
|
65
|
+
rescue Exception => e
|
66
|
+
if StandardError === e
|
67
|
+
logger.err.error(e)
|
68
|
+
else
|
69
|
+
logger.err.fatal(e)
|
70
|
+
end
|
71
|
+
raise e
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def FileUtils.fu_output_message(msg)
|
78
|
+
Capricorn::ExceptionHandler.out.info(msg)
|
79
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rubygems/specification'
|
2
|
+
|
3
|
+
module Gem # :nodoc:
|
4
|
+
class Specification
|
5
|
+
attribute :engine_dependencies, {}
|
6
|
+
|
7
|
+
def add_engine_dependency(name, options={})
|
8
|
+
name = name.to_s
|
9
|
+
add_runtime_dependency(name, *[options[:version]].compact)
|
10
|
+
@engine_dependencies ||= {}
|
11
|
+
@engine_dependencies[name] = options
|
12
|
+
end
|
13
|
+
|
14
|
+
alias_method :ruby_code_without_engines, :ruby_code # :nodoc:
|
15
|
+
def ruby_code(obj) # :nodoc:
|
16
|
+
return obj.inspect if Hash === obj
|
17
|
+
return ruby_code_without_engines(obj)
|
18
|
+
end
|
19
|
+
|
20
|
+
alias_method :to_ruby_without_engines, :to_ruby # :nodoc:
|
21
|
+
def to_ruby # :nodoc:
|
22
|
+
code = to_ruby_without_engines
|
23
|
+
code.gsub! /s\.engine_dependencies\s+[=]([^\n]+)/, 's.instance_variable_set(:@engine_dependencies,\1)'
|
24
|
+
code
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|