magistrate_monitor 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +8 -8
- data/lib/public/css/application.css +5 -0
- data/lib/server.rb +34 -12
- data/lib/supervisor.rb +5 -7
- data/lib/views/index.erb +10 -7
- data/lib/views/layout.erb +3 -3
- data/lib/views/show.erb +2 -2
- data/spec/server_spec.rb +50 -0
- data/spec/spec_helper.rb +17 -1
- data/spec/supervisor_spec.rb +40 -0
- metadata +39 -9
data/README.md
CHANGED
@@ -1,15 +1,15 @@
|
|
1
|
-
|
1
|
+
# Magistrate Monitor
|
2
2
|
|
3
3
|
MagistrateMonitor is a frontend to the Magistrate gem that allows the gem to check in with the status of its workers and to receive commands from
|
4
4
|
the frontend user (such as enable/disable and start/stop workers)
|
5
5
|
|
6
|
-
|
6
|
+
## Installation
|
7
7
|
|
8
|
-
|
8
|
+
### Standalone Sinatra
|
9
9
|
MagistrateMonitor will run as a standalone Sinatra app. It will use ActiveRecord for the DB connection. Create a config/database.yml file
|
10
10
|
with your connection details. Then run rake db:migrate as normal. Then you can start the app with rackup or your other preferred method.
|
11
11
|
|
12
|
-
|
12
|
+
### Mounting in Rails 3.x
|
13
13
|
MagistrateMonitor will mount in a Rails 3.x app very easily.
|
14
14
|
|
15
15
|
1. Add the gem to your Gemfile: `gem 'magistrate_monitor`
|
@@ -18,7 +18,7 @@ MagistrateMonitor will mount in a Rails 3.x app very easily.
|
|
18
18
|
|
19
19
|
mount MagistrateMonitor::Server => '/magistrate'
|
20
20
|
|
21
|
-
|
21
|
+
### Mounting the application in rails 2.3.*
|
22
22
|
|
23
23
|
Create a new folder in app called metal. Add the file magistrate_monitor_web.rb with:
|
24
24
|
|
@@ -37,7 +37,7 @@ Create a new folder in app called metal. Add the file magistrate_monitor_web.rb
|
|
37
37
|
|
38
38
|
This will route all requests to /magistrate_monitor to the magistrate_monitor rack app
|
39
39
|
|
40
|
-
|
40
|
+
## Contributing to magistrate_monitor
|
41
41
|
|
42
42
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
43
43
|
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
@@ -47,10 +47,10 @@ This will route all requests to /magistrate_monitor to the magistrate_monitor ra
|
|
47
47
|
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
48
48
|
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
49
49
|
|
50
|
-
|
50
|
+
## Copyright
|
51
51
|
|
52
52
|
Copyright (c) 2011 Drew Blas. See LICENSE.txt for further details.
|
53
53
|
|
54
|
-
|
54
|
+
## Acknowledgements
|
55
55
|
|
56
56
|
Thanks to Matthew Deiter's healthy gem for the example of building this as a rack app (since I couldn't get 3.1 mountable engines to work)
|
data/lib/server.rb
CHANGED
@@ -2,6 +2,7 @@ require 'sinatra/base'
|
|
2
2
|
require 'sinatra-activerecord'
|
3
3
|
|
4
4
|
require 'supervisor'
|
5
|
+
require 'awesome_print'
|
5
6
|
|
6
7
|
module MagistrateMonitor
|
7
8
|
class Server < Sinatra::Base
|
@@ -10,8 +11,24 @@ module MagistrateMonitor
|
|
10
11
|
set :views, "#{dir}/views"
|
11
12
|
set :public, "#{dir}/public"
|
12
13
|
set :static, true
|
13
|
-
|
14
|
-
|
14
|
+
|
15
|
+
set :basic_auth_credentials, lambda {
|
16
|
+
config_file = File.join('config', 'magistrate.yml')
|
17
|
+
if File.exist?( config_file )
|
18
|
+
config = File.open(config_file) { |file| YAML.load(file) }
|
19
|
+
if config['http_username'] && config['http_password']
|
20
|
+
[config['http_username'], config['http_password']]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
}
|
24
|
+
|
25
|
+
if basic_auth_credentials && ENV['RACK_ENV'] != 'test'
|
26
|
+
use Rack::Auth::Basic do |username, password|
|
27
|
+
[username, password] == basic_auth_credentials
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
get '/' do
|
15
32
|
@supervisors = Supervisor.order('name ASC').all
|
16
33
|
normalize_status_data!
|
17
34
|
|
@@ -19,10 +36,16 @@ module MagistrateMonitor
|
|
19
36
|
end
|
20
37
|
|
21
38
|
get '/supervisors/:name' do
|
22
|
-
@supervisor = Supervisor.find_by_name params[:name]
|
39
|
+
@supervisor = Supervisor.find_by_name! params[:name]
|
23
40
|
erb :show
|
24
41
|
end
|
25
42
|
|
43
|
+
post '/supervisors/:name/delete' do
|
44
|
+
@supervisor = Supervisor.find_by_name! params[:name]
|
45
|
+
@supervisor.destroy
|
46
|
+
redirect url('/')
|
47
|
+
end
|
48
|
+
|
26
49
|
# Responds with the latest databag instructions for the supervisor
|
27
50
|
get '/api/status/:name' do
|
28
51
|
@supervisor = Supervisor.find_or_create_by_name params[:name]
|
@@ -42,23 +65,22 @@ module MagistrateMonitor
|
|
42
65
|
content_type :json
|
43
66
|
ActiveSupport::JSON.encode( {:status => 'Ok'} )
|
44
67
|
end
|
45
|
-
|
46
|
-
|
47
|
-
# But I'd like to get this working before I go about making the links to POST
|
48
|
-
get '/set/:supervisor_name/:worker_name/:action' do
|
68
|
+
|
69
|
+
post '/set/:supervisor_name/:worker_name/:action' do
|
49
70
|
@supervisor = Supervisor.find_or_create_by_name params[:supervisor_name]
|
50
71
|
|
51
72
|
@supervisor.set_target_state!(params[:action], params[:worker_name])
|
52
|
-
redirect
|
73
|
+
redirect url('/')
|
53
74
|
end
|
54
75
|
|
55
76
|
helpers do
|
56
|
-
def url_for(path)
|
57
|
-
|
58
|
-
|
77
|
+
# def url_for(path)
|
78
|
+
# root = request.env['SCRIPT_NAME'].chomp('/')
|
79
|
+
# "#{root}/#{path}"
|
80
|
+
# end
|
59
81
|
|
60
82
|
def url_for_worker(supervisor, name, action)
|
61
|
-
|
83
|
+
url("/set/#{supervisor.name}/#{name}/#{action}")
|
62
84
|
end
|
63
85
|
|
64
86
|
def normalize_status_data!
|
data/lib/supervisor.rb
CHANGED
@@ -9,19 +9,17 @@ module MagistrateMonitor
|
|
9
9
|
# All supervisors have a status that is a hash
|
10
10
|
# If it has something else for whatever reason, the real object is put in a hash under the 'status' key
|
11
11
|
def normalize_status_data!
|
12
|
-
self.status ||= {}
|
12
|
+
self.status ||= {}
|
13
|
+
self.status['workers'] ||= {}
|
13
14
|
|
14
|
-
|
15
|
-
self.status = { 'data-error' => self.status.inspect }
|
16
|
-
end
|
17
|
-
|
18
|
-
self.status.each do |k,v|
|
15
|
+
self.status['workers'].each do |k,v|
|
19
16
|
unless v.is_a?(Hash)
|
20
17
|
v = {'state' => v.inspect }
|
21
18
|
end
|
22
19
|
end
|
23
20
|
|
24
|
-
self.databag ||= {
|
21
|
+
self.databag ||= {}
|
22
|
+
self.databag['workers'] ||= {}
|
25
23
|
end
|
26
24
|
|
27
25
|
def set_target_state!(action, worker)
|
data/lib/views/index.erb
CHANGED
@@ -5,39 +5,42 @@
|
|
5
5
|
<tr>
|
6
6
|
<th>Supervisor</th>
|
7
7
|
<th>Worker</th>
|
8
|
+
<th>pid</th>
|
8
9
|
<th>State</th>
|
9
|
-
<th>
|
10
|
-
<th>
|
10
|
+
<th>Supervisor Target State</th>
|
11
|
+
<th>Monitor Target State</th>
|
11
12
|
<th colspan="3">Actions</th>
|
12
13
|
</tr>
|
13
14
|
</thead>
|
14
15
|
|
15
16
|
<% @supervisors.each do |supervisor| %>
|
16
17
|
<tr>
|
17
|
-
<th><a href="<%=
|
18
|
+
<th><a href="<%= url "/supervisors/#{supervisor.name}" %>"><%= supervisor.name %></a><br>
|
18
19
|
<%= supervisor.last_checkin_at %></th>
|
19
20
|
<th colspan="7"> - </th>
|
21
|
+
<td><a href="<%= url "/supervisors/#{supervisor.name}/delete" %>" data-confirm="Are you sure?" data-method="post" rel="nofollow">Delete</a><br>
|
20
22
|
</tr>
|
21
|
-
<% supervisor.status.each do |k,v| %>
|
23
|
+
<% supervisor.status['workers'].each do |k,v| %>
|
22
24
|
<tr>
|
23
25
|
<th> - </th>
|
24
26
|
<th><%= k %></th>
|
27
|
+
<td><%= v['pid'] %></td>
|
25
28
|
<td><%= v['state'] %></td>
|
26
29
|
<td><%= v['target_state']%></td>
|
27
30
|
<td><%= supervisor.databag['workers'][k]['target_state'] if supervisor.databag['workers'].is_a?(Hash) && supervisor.databag['workers'][k].is_a?(Hash) %></td>
|
28
31
|
<td>
|
29
32
|
<% if v['state'] != 'running' %>
|
30
|
-
<a href="<%= url_for_worker(supervisor, k, 'running') %>">Run</a>
|
33
|
+
<a href="<%= url_for_worker(supervisor, k, 'running') %>" data-method="post" rel="nofollow">Run</a>
|
31
34
|
<% end %>
|
32
35
|
</td>
|
33
36
|
<td>
|
34
37
|
<% if v['state'] != 'stopped' %>
|
35
|
-
<a href="<%= url_for_worker(supervisor, k, 'stopped') %>">Stop</a>
|
38
|
+
<a href="<%= url_for_worker(supervisor, k, 'stopped') %>" data-method="post" rel="nofollow">Stop</a>
|
36
39
|
<% end %>
|
37
40
|
</td>
|
38
41
|
<td>
|
39
42
|
<% if v['state'] != 'unmonitored' %>
|
40
|
-
<a href="<%= url_for_worker(supervisor, k, 'unmonitored') %>">Unmonitor</a>
|
43
|
+
<a href="<%= url_for_worker(supervisor, k, 'unmonitored') %>" data-method="post" rel="nofollow">Unmonitor</a>
|
41
44
|
<% end %>
|
42
45
|
</td>
|
43
46
|
</tr>
|
data/lib/views/layout.erb
CHANGED
@@ -7,8 +7,8 @@
|
|
7
7
|
|
8
8
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
9
9
|
|
10
|
-
<link rel="stylesheet" href="<%=
|
11
|
-
<link rel="stylesheet" href="<%=
|
10
|
+
<link rel="stylesheet" href="<%= url('css/style.css') %>">
|
11
|
+
<link rel="stylesheet" href="<%= url('css/application.css') %>">
|
12
12
|
|
13
13
|
</head>
|
14
14
|
<body>
|
@@ -25,7 +25,7 @@
|
|
25
25
|
</footer>
|
26
26
|
</div> <!--! end of #container -->
|
27
27
|
|
28
|
-
<script src="/js/application.js"></script>
|
28
|
+
<script src="<%= url '/js/application.js' %>"></script>
|
29
29
|
|
30
30
|
</body>
|
31
31
|
</html>
|
data/lib/views/show.erb
CHANGED
@@ -3,12 +3,12 @@
|
|
3
3
|
<% if @supervisor %>
|
4
4
|
<h3>Status from supervisor</h3>
|
5
5
|
<p><pre>
|
6
|
-
<%= @supervisor.status.
|
6
|
+
<%= @supervisor.status.ai(:html => true) %>
|
7
7
|
</pre></p>
|
8
8
|
|
9
9
|
<h3>Databag to be sent to supervisor</h3>
|
10
10
|
<p><pre>
|
11
|
-
<%= @supervisor.databag.
|
11
|
+
<%= @supervisor.databag.ai(:html => true) %>
|
12
12
|
</pre></p>
|
13
13
|
<% else %>
|
14
14
|
No supervisor by the name <%= params[:name] %>
|
data/spec/server_spec.rb
CHANGED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "MagistrateMonitor::Server" do
|
4
|
+
include Rack::Test::Methods
|
5
|
+
|
6
|
+
# Eventually could be replaced with fixtures, but we only need this one
|
7
|
+
before(:all) do
|
8
|
+
MagistrateMonitor::Supervisor.delete_all
|
9
|
+
@supervisor = MagistrateMonitor::Supervisor.create :name => 'foo'
|
10
|
+
@supervisor.normalize_status_data!
|
11
|
+
@supervisor.set_target_state!('running', 'worker1')
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should respond to /" do
|
15
|
+
get '/'
|
16
|
+
last_response.should be_ok
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should get a supervisor' do
|
20
|
+
get '/supervisors/foo'
|
21
|
+
last_response.should be_ok
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should delete a supervisor' do
|
25
|
+
supervisor = MagistrateMonitor::Supervisor.create :name => 'bar'
|
26
|
+
|
27
|
+
post '/supervisors/bar/delete'
|
28
|
+
last_response.status.should == 302
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'api' do
|
32
|
+
it 'should provide the databag' do
|
33
|
+
get '/api/status/foo'
|
34
|
+
|
35
|
+
last_response.should be_ok
|
36
|
+
last_response.body.should == ActiveSupport::JSON.encode(@supervisor.databag)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should record the incoming status' do
|
40
|
+
status = {'workers' => {'worker2' => {'state' => 'running'}}}
|
41
|
+
post '/api/status/bar', :status => ActiveSupport::JSON.encode( status )
|
42
|
+
|
43
|
+
last_response.should be_ok
|
44
|
+
|
45
|
+
s = MagistrateMonitor::Supervisor.find_by_name 'bar'
|
46
|
+
s.status.should == status
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,7 +1,21 @@
|
|
1
|
+
ENV['RACK_ENV'] = 'test'
|
2
|
+
|
1
3
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
4
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
-
require 'rspec'
|
4
5
|
require 'magistrate_monitor'
|
6
|
+
require 'rspec'
|
7
|
+
|
8
|
+
require 'rack/test'
|
9
|
+
|
10
|
+
def app
|
11
|
+
@app ||= MagistrateMonitor::Server
|
12
|
+
end
|
13
|
+
|
14
|
+
# set test environment
|
15
|
+
app.set :environment, :test
|
16
|
+
# set :run, false
|
17
|
+
# set :raise_errors, true
|
18
|
+
# set :logging, false
|
5
19
|
|
6
20
|
# Requires supporting files with custom matchers and macros, etc,
|
7
21
|
# in ./support/ and its subdirectories.
|
@@ -10,4 +24,6 @@ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
|
10
24
|
RSpec.configure do |config|
|
11
25
|
config.mock_with :rspec
|
12
26
|
config.color_enabled = true
|
27
|
+
# config.use_transactional_examples = true
|
28
|
+
|
13
29
|
end
|
data/spec/supervisor_spec.rb
CHANGED
@@ -0,0 +1,40 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "supervisor"
|
3
|
+
|
4
|
+
describe "Supervisor" do
|
5
|
+
before(:each) do
|
6
|
+
MagistrateMonitor::Supervisor.delete_all
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should save to the DB successfully' do
|
10
|
+
supervisor = MagistrateMonitor::Supervisor.new :name => 'foo'
|
11
|
+
supervisor.save.should be_true
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should set a target state with a blank databag' do
|
15
|
+
supervisor = MagistrateMonitor::Supervisor.new :name => 'foo'
|
16
|
+
supervisor.set_target_state!('running', 'worker1')
|
17
|
+
supervisor.reload
|
18
|
+
|
19
|
+
supervisor.databag['workers']['worker1']['target_state'].should == 'running'
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should set target state multiple times successfully' do
|
23
|
+
supervisor = MagistrateMonitor::Supervisor.new :name => 'foo'
|
24
|
+
supervisor.set_target_state!('running', 'worker1')
|
25
|
+
supervisor.set_target_state!('stopped', 'worker1')
|
26
|
+
supervisor.reload
|
27
|
+
|
28
|
+
supervisor.databag['workers']['worker1']['target_state'].should == 'stopped'
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should normalize the initial data' do
|
32
|
+
supervisor = MagistrateMonitor::Supervisor.new :name => 'foo'
|
33
|
+
|
34
|
+
supervisor.normalize_status_data!
|
35
|
+
|
36
|
+
supervisor.databag.should be_a(Hash)
|
37
|
+
supervisor.status.should be_a(Hash)
|
38
|
+
supervisor.databag['workers'].should be_a(Hash)
|
39
|
+
end
|
40
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: magistrate_monitor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 2
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.2.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Drew Blas
|
@@ -91,9 +91,23 @@ dependencies:
|
|
91
91
|
type: :development
|
92
92
|
version_requirements: *id005
|
93
93
|
- !ruby/object:Gem::Dependency
|
94
|
-
name:
|
94
|
+
name: rack-test
|
95
95
|
prerelease: false
|
96
96
|
requirement: &id006 !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
hash: 3
|
102
|
+
segments:
|
103
|
+
- 0
|
104
|
+
version: "0"
|
105
|
+
type: :development
|
106
|
+
version_requirements: *id006
|
107
|
+
- !ruby/object:Gem::Dependency
|
108
|
+
name: sinatra
|
109
|
+
prerelease: false
|
110
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
97
111
|
none: false
|
98
112
|
requirements:
|
99
113
|
- - ~>
|
@@ -105,11 +119,11 @@ dependencies:
|
|
105
119
|
- 6
|
106
120
|
version: 1.2.6
|
107
121
|
type: :runtime
|
108
|
-
version_requirements: *
|
122
|
+
version_requirements: *id007
|
109
123
|
- !ruby/object:Gem::Dependency
|
110
124
|
name: activerecord
|
111
125
|
prerelease: false
|
112
|
-
requirement: &
|
126
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
113
127
|
none: false
|
114
128
|
requirements:
|
115
129
|
- - ">="
|
@@ -120,11 +134,11 @@ dependencies:
|
|
120
134
|
- 0
|
121
135
|
version: "3.0"
|
122
136
|
type: :runtime
|
123
|
-
version_requirements: *
|
137
|
+
version_requirements: *id008
|
124
138
|
- !ruby/object:Gem::Dependency
|
125
139
|
name: activesupport
|
126
140
|
prerelease: false
|
127
|
-
requirement: &
|
141
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
128
142
|
none: false
|
129
143
|
requirements:
|
130
144
|
- - ">="
|
@@ -135,7 +149,23 @@ dependencies:
|
|
135
149
|
- 0
|
136
150
|
version: "3.0"
|
137
151
|
type: :runtime
|
138
|
-
version_requirements: *
|
152
|
+
version_requirements: *id009
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: awesome_print
|
155
|
+
prerelease: false
|
156
|
+
requirement: &id010 !ruby/object:Gem::Requirement
|
157
|
+
none: false
|
158
|
+
requirements:
|
159
|
+
- - ~>
|
160
|
+
- !ruby/object:Gem::Version
|
161
|
+
hash: 15
|
162
|
+
segments:
|
163
|
+
- 0
|
164
|
+
- 4
|
165
|
+
- 0
|
166
|
+
version: 0.4.0
|
167
|
+
type: :runtime
|
168
|
+
version_requirements: *id010
|
139
169
|
description: Receives checkins from the magistrate gem and sends back commands
|
140
170
|
email: drew.blas@gmail.com
|
141
171
|
executables: []
|