jesus 0.0.2

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.
@@ -0,0 +1,5 @@
1
+ *.kpf
2
+ *.tmproj
3
+ .DS_Store
4
+ vendor/gems/*
5
+ bin/*
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source "http://gemcutter.org"
2
+ #
3
+ # Required on every environment
4
+ #
5
+ gem "sinatra"
6
+ gem "sinatra_more"
7
+ gem "god"
8
+
9
+ #
10
+ # Required only for tests
11
+ #
12
+ gem "rspec", :only => :testing
13
+ gem "rack-test", :only => :testing
14
+ gem "mocha", :only => :testing
@@ -0,0 +1,44 @@
1
+ h1. Jesus
2
+
3
+ Jesus is a web interface to "god":http://github.com/mojombo/god
4
+ It allows you to see the process and monitor/unmonitor them.
5
+
6
+ !http://cloud.github.com/downloads/dmathieu/jesus/jesus-0.0.1.thumb.png(Screenshot 0.0.1)!:http://cloud.github.com/downloads/dmathieu/jesus/jesus-0.0.1.png
7
+
8
+ h2. Installation
9
+
10
+ To install the application you first need to have "bundler":http://github.com/wycats/bundler installed on your machine.
11
+ Once that is done, clone the project in the directory of your choice.
12
+
13
+ @git clone git://github.com/dmathieu/jesus.git@
14
+
15
+ Then you should install the dependencies.
16
+
17
+ @gem bundle@
18
+
19
+ You now have Jesus available on your machine. Start your god process.
20
+ And start Jesus.
21
+
22
+ @god -c /path/to/your/god.config@
23
+
24
+ @rackup@
25
+
26
+ Note: Jesus and God should be started with the same user. Otherwise, Jesus won't be able to get access to the God informations.
27
+
28
+ Go to "localhot:9292":http://localhost:9292 to watch the process monitored by god.
29
+
30
+ h2. Contributing
31
+
32
+ If you think Jesus is great but can be improved, feel free to contribute.
33
+ To do so, you can :
34
+
35
+ * "Fork":http://help.github.com/forking/ the project
36
+ * Do your changes and commit them to your repository
37
+ * Test your changes. We won't accept any untested contributions (except if they're not testable).
38
+ * Create an "issue":http://help.github.com/forking/ with a link to your commits.
39
+
40
+ And that's it! We'll soon take a look at your issue and review your changes.
41
+
42
+ h2. Author
43
+
44
+ Damien MATHIEU :: 42 (AT|CHEZ) dmathieu.com
@@ -0,0 +1,33 @@
1
+ require 'vendor/gems/environment'
2
+ require 'spec/rake/spectask'
3
+
4
+ #
5
+ # Jeweler, to execute the tests
6
+ #
7
+ begin
8
+ require 'jeweler'
9
+ Jeweler::Tasks.new do |gemspec|
10
+ gemspec.name = "jesus"
11
+ gemspec.summary = "A web interface for god to speak with mankind"
12
+ gemspec.description = "A web interface for god to speak with mankind"
13
+ gemspec.email = "42@dmathieu.com"
14
+ gemspec.homepage = "http://github.com/dmathieu/jesus"
15
+ gemspec.authors = ["Damien MATHIEU"]
16
+ gemspec.version = '0.0.2'
17
+ end
18
+ rescue LoadError
19
+ puts "Jeweler not available. Install it with:"
20
+ puts "gem install jeweler"
21
+ end
22
+
23
+
24
+ #
25
+ # The rspec tasks
26
+ #
27
+ task :default => :spec
28
+
29
+ desc "Run all specs"
30
+ Spec::Rake::SpecTask.new('spec') do |t|
31
+ t.spec_files = FileList['spec/**/*.rb']
32
+ t.spec_opts = ['-cfs']
33
+ end
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ require 'logger'
3
+
4
+ # We require the bundled gems
5
+ require 'vendor/gems/environment'
6
+
7
+ # We require the application
8
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/lib')
9
+ require 'jesus/server'
10
+
11
+ # We start the server
12
+ use Rack::ShowExceptions
13
+ run Jesus::Server.new
@@ -0,0 +1,58 @@
1
+ require 'god'
2
+
3
+ module Jesus
4
+ #
5
+ # Interface between jesus and god
6
+ #
7
+ class Interface
8
+ attr_reader :server
9
+
10
+ def initialize
11
+ @server = DRbObject.new(nil, God::Socket.socket(17165))
12
+ end
13
+
14
+
15
+ #
16
+ # We retrieve the processes by group
17
+ #
18
+ def status
19
+ begin
20
+ statuses = server.status
21
+ rescue
22
+ return nil
23
+ end
24
+ groups = Hash.new
25
+
26
+ statuses.each do |name, status|
27
+ g = status[:group] || ''
28
+ groups[g] ||= Hash.new
29
+ groups[g][name] = status
30
+ end
31
+ groups
32
+ end
33
+
34
+ #
35
+ # We execute a specific command to god
36
+ # Could be "start", "stop", "restart", "quit", "terminate"
37
+ #
38
+ def command(command, name)
39
+ begin
40
+ server.control(name, command)
41
+ rescue
42
+ return nil
43
+ end
44
+ end
45
+
46
+ #
47
+ # Gets the god's logs for one process since some time
48
+ # By default, gets all the logs
49
+ #
50
+ def log(name=nil, start=Time.at(0))
51
+ begin
52
+ server.running_log(name, start).split("\n")
53
+ rescue
54
+ nil
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,50 @@
1
+ require 'sinatra/base'
2
+ require 'sinatra_more/render_plugin'
3
+ require 'jesus/interface'
4
+ require 'jesus/server/helpers'
5
+
6
+ module Jesus
7
+ class Server < Sinatra::Base
8
+ dir = File.dirname(File.expand_path(__FILE__))
9
+ register SinatraMore::RenderPlugin
10
+ include Jesus::Helpers
11
+
12
+ set :views, "#{dir}/server/views"
13
+ set :public, "#{dir}/server/public"
14
+ set :static, true
15
+ enable :sessions
16
+
17
+ #
18
+ # The home
19
+ # Displays the list of the process
20
+ #
21
+ get '/' do
22
+ @status = Jesus::Interface.new.status
23
+ erb_template @status.nil? ? :error : :home
24
+ end
25
+
26
+ #
27
+ # Displays a process log
28
+ #
29
+ get '/logs/:process' do
30
+ @log = Jesus::Interface.new.log(params[:process])
31
+ erb_template @log.nil? ? :error : :log
32
+ end
33
+
34
+ #
35
+ # Displays every page logs
36
+ #
37
+ get '/logs' do
38
+ flash(:notice, 'You currently can not display all the logs. You should select a process first.')
39
+ redirect '/'
40
+ end
41
+
42
+ #
43
+ # Executes a command (start, restart, stop, quit or terminate) on the server
44
+ #
45
+ post '/command/:command/:process' do
46
+ @command = Jesus::Interface.new.command(params[:command], params[:process])
47
+ redirect '/'
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,18 @@
1
+ module Jesus
2
+ module Helpers
3
+ def class_if_current(link)
4
+ link = '^/$' if link == '/'
5
+ 'class="current"' if request.path_info =~ Regexp.new(link)
6
+ end
7
+ def tab(name, link)
8
+ "<li #{class_if_current(link)}><a href='#{link}'>#{name}</a></li>"
9
+ end
10
+
11
+ def flash_tag(type)
12
+ "<div id='flash'>#{session.delete(type)}</div>" unless session[type].nil?
13
+ end
14
+ def flash(type, message)
15
+ session[type] = message
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,131 @@
1
+ /*
2
+ * The global styles
3
+ */
4
+ html {
5
+ background:#efefef;
6
+ font-family:Arial, Verdana, sans-serif;
7
+ font-size:13px;
8
+ }
9
+ body {
10
+ padding:0;
11
+ margin:0;
12
+ }
13
+
14
+ /*
15
+ * The page header
16
+ */
17
+ #header {
18
+ background:#000;
19
+ padding: 8px 5% 0 5%;
20
+ border-bottom:1px solid #444;
21
+ border-bottom:5px solid #ce1212;
22
+ }
23
+ #header ul {
24
+ margin: 0px;
25
+ padding: 0px;
26
+ }
27
+ #header ul li {
28
+ display:inline;
29
+ }
30
+ #header ul li a {
31
+ color:#fff;
32
+ text-decoration:none;
33
+ margin: 0px 10px 0px 0px;
34
+ display:inline-block;
35
+ padding:8px;
36
+
37
+ -webkit-border-top-right-radius:6px;
38
+ -webkit-border-top-left-radius:6px;
39
+ -moz-border-radius-topright:6px;
40
+ -moz-border-radius-topleft:6px;
41
+ border-top-right-radius:6px;
42
+ border-top-left-radius:6px;
43
+ }
44
+ #header ul li a:hover {
45
+ background:#333;
46
+ }
47
+ #header ul li.current a {
48
+ background:#ce1212;
49
+ font-weight:bold;
50
+ color:#fff;
51
+ }
52
+
53
+ /*
54
+ * The page itself
55
+ */
56
+ #page {
57
+ padding: 15px;
58
+ }
59
+
60
+ /*
61
+ * The flash message
62
+ */
63
+ #flash {
64
+ width: 700px;
65
+ text-align: center;
66
+ margin: 10px auto;
67
+ padding: 5px;
68
+ background-color: #FFCFD1;
69
+ border: 1px solid #FF000A;
70
+ }
71
+
72
+ /*
73
+ * The common page info div
74
+ */
75
+ div.page_info h1 {
76
+ color: #FF0000;
77
+ margin: 0px;
78
+ text-align: center;
79
+ }
80
+ div.page_info p {
81
+ text-align: left;
82
+ padding: 0px 15px;
83
+ color: #6F6F6F;
84
+ }
85
+ div.page_info {
86
+ width: 700px;
87
+ text-align: center;
88
+ margin: 0 auto;
89
+ background-color: #D0CFFF;
90
+ border: 1px solid #0300FF;
91
+ }
92
+
93
+ /*
94
+ * The home page (processes list)
95
+ */
96
+ div.group h2 { margin: 5px 30px; }
97
+ div.group ul {
98
+ list-style-type: none;
99
+ padding: 0px;
100
+ }
101
+ div.group li {
102
+ border: 1px solid #CCC;
103
+ margin: 5px 0px;
104
+ padding: 10px;
105
+ }
106
+
107
+ div.group li.up { background-color: #BFFFC8; }
108
+ div.group li.unmonitored { background-color: #FFBFBF; }
109
+
110
+ ul.links {
111
+ list-style-type: none;
112
+ margin: 0px;
113
+ float: right;
114
+ }
115
+ ul.links li {
116
+ display: inline;
117
+ border: 0px;
118
+ }
119
+
120
+
121
+ /*
122
+ * The logs page
123
+ */
124
+ div#logs {
125
+ text-align: center;
126
+ margin: 30px 0px;
127
+ }
128
+ div#logs textarea {
129
+ width: 100%;
130
+ height: 500px;
131
+ }
@@ -0,0 +1,6 @@
1
+ <div class="page_info">
2
+ <h1>An error occured</h1>
3
+ <p>
4
+ God doesn't seem to be started. Or I don't have the privileges to access it.
5
+ </p>
6
+ </div>
@@ -0,0 +1,24 @@
1
+ <div class="page_info">
2
+ <h1>Processes</h1>
3
+ <p>
4
+ In the list below, you see the processes monitored by God.<br />
5
+ If the process is green, it mean it's launched. If it's in red then it's not currently being monitored.
6
+ </p>
7
+ </div>
8
+
9
+ <% @status.each_pair do |group,processes| %>
10
+ <div class="group">
11
+ <h2><%= group %></h2>
12
+ <ul>
13
+ <% processes.each do |process| %>
14
+ <li class="<%= process[1][:state] %>">
15
+ <%= process[0] %>
16
+
17
+ <ul class="links">
18
+ <li><a href="/logs/<%= process[0] %>">View Logs</a></li>
19
+ </ul>
20
+ </li>
21
+ <% end %>
22
+ </ul>
23
+ </div>
24
+ <% end %>
@@ -0,0 +1,20 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Jesus</title>
5
+ <link href="/css/style.css" media="screen" rel="stylesheet" type="text/css" />
6
+ </head>
7
+ <body>
8
+ <div id="header">
9
+ <ul>
10
+ <%= tab 'Home', '/' %>
11
+ <%= tab 'Logs', '/logs' %>
12
+ </ul>
13
+ </div>
14
+ <div id="page">
15
+ <%= flash_tag(:notice) %>
16
+
17
+ <%= yield %>
18
+ </div>
19
+ </body>
20
+ </html>
@@ -0,0 +1,7 @@
1
+ <div class="page_info">
2
+ <h1>Logs for <%= params[:process] %></h1>
3
+ </div>
4
+
5
+ <div id="logs">
6
+ <textarea><%= @log.join("\r\n") %></textarea>
7
+ </div>
@@ -0,0 +1,35 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require 'jesus/interface'
3
+
4
+ describe "God interface" do
5
+ before(:all) do
6
+ @server = Jesus::Interface.new
7
+ end
8
+
9
+ describe 'no mock' do
10
+ it 'should get the server' do
11
+ @server.server.should be_kind_of DRb::DRbObject
12
+ end
13
+
14
+ it 'should fail because the server is not connected' do
15
+ @server.status.should be_nil
16
+ end
17
+ end
18
+
19
+ describe 'with mocking' do
20
+ before(:all) do
21
+ @server.server.stubs(:status).returns({
22
+ :FirstProcess => { :group => 'GroupName', :status => :up },
23
+ :SecondProcess => { :group => 'Group', :status => :unmonitored },
24
+ })
25
+ end
26
+
27
+ it 'should retrieve the status ordered by group' do
28
+ status = @server.status
29
+
30
+ status.length.should eql(2)
31
+ status['Group'].should eql({ :SecondProcess => { :status => :unmonitored, :group => "Group" }})
32
+ status['GroupName'].should eql({ :FirstProcess => { :status => :up, :group=>"GroupName"}})
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,27 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe "The home page" do
4
+ include Rack::Test::Methods
5
+ include Jesus::Spec
6
+
7
+ it "should respond to /" do
8
+ get '/'
9
+ last_response.should be_ok
10
+ end
11
+
12
+ it 'should display a process logs' do
13
+ class Jesus::Interface
14
+ def log(name); ['First Log Line', 'Second Log Line']; end
15
+ end
16
+
17
+ get '/logs/test'
18
+ last_response.should be_ok
19
+ last_response.should match(/<h1>Logs for test<\/h1>/)
20
+ last_response.should match(/<textarea>First Log Line\r\nSecond Log Line<\/textarea>/)
21
+ end
22
+
23
+ it 'should execute the command' do
24
+ post '/command/start/jesus'
25
+ last_response.should be_redirect
26
+ end
27
+ end
@@ -0,0 +1,4 @@
1
+ --colour
2
+ --format progress
3
+ --loadby mtime
4
+ --reverse
@@ -0,0 +1,23 @@
1
+ require 'vendor/gems/environment'
2
+ require 'sinatra'
3
+ require 'rack/test'
4
+ require 'spec'
5
+ require 'mocha'
6
+ require 'spec/autorun'
7
+ require 'spec/interop/test'
8
+
9
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
10
+ require 'jesus/server'
11
+
12
+ # set test environment
13
+ set :environment, :test
14
+ set :run, false
15
+ set :raise_errors, true
16
+ set :logging, false
17
+
18
+ # Set the application
19
+ module Jesus::Spec
20
+ def app
21
+ @app ||= Sinatra.new Jesus::Server
22
+ end
23
+ end
@@ -0,0 +1,56 @@
1
+ APP_ROOT = File.expand_path(File.dirname(__FILE__))
2
+ preload_app true
3
+ timeout 30
4
+
5
+ # Listen on a Unix data socket
6
+ listen APP_ROOT + '/tmp/jesus.sock', :backlog => 2048
7
+ pid APP_ROOT + '/tmp/jesus.pid'
8
+
9
+ ##
10
+ # REE
11
+
12
+ # http://www.rubyenterpriseedition.com/faq.html#adapt_apps_for_cow
13
+ if GC.respond_to?(:copy_on_write_friendly=)
14
+ GC.copy_on_write_friendly = true
15
+ end
16
+
17
+ before_fork do |server, worker|
18
+ ##
19
+ # When sent a USR2, Unicorn will suffix its pidfile with .oldbin and
20
+ # immediately start loading up a new version of itself (loaded with a new
21
+ # version of our app). When this new Unicorn is completely loaded
22
+ # it will begin spawning workers. The first worker spawned will check to
23
+ # see if an .oldbin pidfile exists. If so, this means we've just booted up
24
+ # a new Unicorn and need to tell the old one that it can now die. To do so
25
+ # we send it a QUIT.
26
+ #
27
+ # Using this method we get 0 downtime deploys.
28
+
29
+ old_pid = APP_ROOT + '/tmp/unicorn.pid.oldbin'
30
+ if File.exists?(old_pid) && server.pid != old_pid
31
+ begin
32
+ Process.kill("QUIT", File.read(old_pid).to_i)
33
+ rescue Errno::ENOENT, Errno::ESRCH
34
+ # someone else did our job for us
35
+ end
36
+ end
37
+ end
38
+
39
+
40
+ after_fork do |server, worker|
41
+ ##
42
+ # Unicorn master is started as root, which is fine, but let's
43
+ # drop the workers to www-data:www-data
44
+
45
+ uid, gid = Process.euid, Process.egid
46
+ user, group = 'www-data', 'www-data'
47
+ target_uid = Etc.getpwnam(user).uid
48
+ target_gid = Etc.getgrnam(group).gid
49
+
50
+ worker.tmp.chown(target_uid, target_gid)
51
+ if uid != target_uid || gid != target_gid
52
+ Process.initgroups(user, target_gid)
53
+ Process::GID.change_privilege(target_gid)
54
+ Process::UID.change_privilege(target_uid)
55
+ end
56
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jesus
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Damien MATHIEU
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-11-19 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: A web interface for god to speak with mankind
17
+ email: 42@dmathieu.com
18
+ executables:
19
+ - autospec
20
+ - rake2thor
21
+ - sinatra_gen
22
+ - spec
23
+ - rackup
24
+ - god
25
+ - rake
26
+ - thor
27
+ extensions: []
28
+
29
+ extra_rdoc_files:
30
+ - README.textile
31
+ files:
32
+ - .gitignore
33
+ - Gemfile
34
+ - README.textile
35
+ - Rakefile
36
+ - config.ru
37
+ - lib/jesus/interface.rb
38
+ - lib/jesus/server.rb
39
+ - lib/jesus/server/helpers.rb
40
+ - lib/jesus/server/public/css/style.css
41
+ - lib/jesus/server/views/error.erb
42
+ - lib/jesus/server/views/home.erb
43
+ - lib/jesus/server/views/layout.erb
44
+ - lib/jesus/server/views/log.erb
45
+ - spec/lib/god_spec.rb
46
+ - spec/server/home_spec.rb
47
+ - spec/spec.opts
48
+ - spec/spec_helper.rb
49
+ - unicorn.rb
50
+ has_rdoc: true
51
+ homepage: http://github.com/dmathieu/jesus
52
+ licenses: []
53
+
54
+ post_install_message:
55
+ rdoc_options:
56
+ - --charset=UTF-8
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: "0"
70
+ version:
71
+ requirements: []
72
+
73
+ rubyforge_project:
74
+ rubygems_version: 1.3.5
75
+ signing_key:
76
+ specification_version: 3
77
+ summary: A web interface for god to speak with mankind
78
+ test_files:
79
+ - spec/spec_helper.rb
80
+ - spec/server/home_spec.rb
81
+ - spec/lib/god_spec.rb