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 CHANGED
@@ -1,15 +1,15 @@
1
- = Magistrate Monitor
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
- == Installation
6
+ ## Installation
7
7
 
8
- === Standalone Sinatra
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
- === Mounting in Rails 3.x
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
- === Mounting the application in rails 2.3.*
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
- == Contributing to magistrate_monitor
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
- == Copyright
50
+ ## Copyright
51
51
 
52
52
  Copyright (c) 2011 Drew Blas. See LICENSE.txt for further details.
53
53
 
54
- == Acknowledgements
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)
@@ -20,4 +20,9 @@ td{
20
20
  padding: 0.4em;
21
21
  margin: 0.4em;
22
22
  border: 1px solid blue;
23
+ }
24
+
25
+ pre{
26
+ margin: 0;
27
+ display: inline;
23
28
  }
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
- get '/', :provides => 'html' do
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
- # These should not be gets
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 url_for('/')
73
+ redirect url('/')
53
74
  end
54
75
 
55
76
  helpers do
56
- def url_for(path)
57
- "#{request.env['SCRIPT_NAME']}/#{path}"
58
- end
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
- url_for("set/#{supervisor.name}/#{name}/#{action}")
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
- unless self.status.is_a?(Hash)
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 ||= {'workers' => {}}
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>Client Target State</th>
10
- <th>Server Target State</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="<%= url_for "supervisors/#{supervisor.name}" %>"><%= supervisor.name %></a><br>
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="<%= url_for('/css/style.css') %>">
11
- <link rel="stylesheet" href="<%= url_for('/css/application.css') %>">
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.inspect %>
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.inspect %>
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
@@ -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: 27
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 1
8
+ - 2
9
9
  - 0
10
- version: 0.1.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: sinatra
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: *id006
122
+ version_requirements: *id007
109
123
  - !ruby/object:Gem::Dependency
110
124
  name: activerecord
111
125
  prerelease: false
112
- requirement: &id007 !ruby/object:Gem::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: *id007
137
+ version_requirements: *id008
124
138
  - !ruby/object:Gem::Dependency
125
139
  name: activesupport
126
140
  prerelease: false
127
- requirement: &id008 !ruby/object:Gem::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: *id008
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: []