magistrate_monitor 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +3 -0
- data/LICENSE.txt +20 -0
- data/README.md +56 -0
- data/Rakefile +82 -0
- data/bin/magistrate_monitor-web +15 -0
- data/config.ru +2 -0
- data/db/migrate/20110808122502_create_magistrate_monitor_table.rb +23 -0
- data/lib/magistrate_monitor.rb +5 -0
- data/lib/public/css/application.css +23 -0
- data/lib/public/css/style.css +276 -0
- data/lib/server.rb +71 -0
- data/lib/sinatra-activerecord.rb +53 -0
- data/lib/supervisor.rb +34 -0
- data/lib/views/index.erb +46 -0
- data/lib/views/layout.erb +31 -0
- data/lib/views/show.erb +15 -0
- data/spec/server_spec.rb +0 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/supervisor_spec.rb +0 -0
- metadata +205 -0
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Drew Blas
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
= Magistrate Monitor
|
2
|
+
|
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
|
+
the frontend user (such as enable/disable and start/stop workers)
|
5
|
+
|
6
|
+
== Installation
|
7
|
+
|
8
|
+
=== Standalone Sinatra
|
9
|
+
MagistrateMonitor will run as a standalone Sinatra app. It will use ActiveRecord for the DB connection. Create a config/database.yml file
|
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
|
+
|
12
|
+
=== Mounting in Rails 3.x
|
13
|
+
MagistrateMonitor will mount in a Rails 3.x app very easily.
|
14
|
+
|
15
|
+
1. Add the gem to your Gemfile: `gem 'magistrate_monitor`
|
16
|
+
2. Copy the migrations to your main migration folder and run them.
|
17
|
+
3. Then add this to your routes.rb:
|
18
|
+
|
19
|
+
mount MagistrateMonitor::Server => '/magistrate'
|
20
|
+
|
21
|
+
=== Mounting the application in rails 2.3.*
|
22
|
+
|
23
|
+
Create a new folder in app called metal. Add the file magistrate_monitor_web.rb with:
|
24
|
+
|
25
|
+
require 'magistrate_monitor'
|
26
|
+
class MagistrateMonitorWeb
|
27
|
+
@app = Rack::Builder.new {
|
28
|
+
map "/magistrate_monitor" do
|
29
|
+
run MagistrateMonitor::Server.new
|
30
|
+
end
|
31
|
+
}.to_app
|
32
|
+
|
33
|
+
def self.call(env)
|
34
|
+
@app.call(env)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
This will route all requests to /magistrate_monitor to the magistrate_monitor rack app
|
39
|
+
|
40
|
+
== Contributing to magistrate_monitor
|
41
|
+
|
42
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
43
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
44
|
+
* Fork the project
|
45
|
+
* Start a feature/bugfix branch
|
46
|
+
* Commit and push until you are happy with your contribution
|
47
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
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
|
+
|
50
|
+
== Copyright
|
51
|
+
|
52
|
+
Copyright (c) 2011 Drew Blas. See LICENSE.txt for further details.
|
53
|
+
|
54
|
+
== Acknowledgements
|
55
|
+
|
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/Rakefile
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'rake'
|
12
|
+
|
13
|
+
require 'rspec/core'
|
14
|
+
require 'rspec/core/rake_task'
|
15
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
16
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
17
|
+
end
|
18
|
+
|
19
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
20
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
21
|
+
spec.rcov = true
|
22
|
+
end
|
23
|
+
|
24
|
+
task :default => :spec
|
25
|
+
|
26
|
+
require 'rake/rdoctask'
|
27
|
+
Rake::RDocTask.new do |rdoc|
|
28
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
29
|
+
|
30
|
+
rdoc.rdoc_dir = 'rdoc'
|
31
|
+
rdoc.title = "magistrate_monitor #{version}"
|
32
|
+
rdoc.rdoc_files.include('README*')
|
33
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
34
|
+
end
|
35
|
+
|
36
|
+
# Thanks to: https://github.com/bmizerany/sinatra-activerecord/blob/master/lib/sinatra/activerecord/rake.rb
|
37
|
+
namespace :db do
|
38
|
+
desc "migrate your database"
|
39
|
+
task :migrate do
|
40
|
+
require 'active_record'
|
41
|
+
require 'active_support/all'
|
42
|
+
require 'fileutils'
|
43
|
+
require 'erb'
|
44
|
+
|
45
|
+
env = ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development'
|
46
|
+
|
47
|
+
file = File.join('config', 'database.yml')
|
48
|
+
database_options = YAML::load(ERB.new(IO.read(file)).result).with_indifferent_access[env]
|
49
|
+
|
50
|
+
ActiveRecord::Base.establish_connection(database_options)
|
51
|
+
|
52
|
+
ActiveRecord::Migrator.migrate(
|
53
|
+
'db/migrate',
|
54
|
+
ENV["VERSION"] ? ENV["VERSION"].to_i : nil
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
58
|
+
desc "create an ActiveRecord migration in ./db/migrate"
|
59
|
+
task :create_migration do
|
60
|
+
name = ENV['NAME']
|
61
|
+
abort("no NAME specified. use `rake db:create_migration NAME=create_users`") if !name
|
62
|
+
|
63
|
+
migrations_dir = File.join("db", "migrate")
|
64
|
+
version = ENV["VERSION"] || Time.now.utc.strftime("%Y%m%d%H%M%S")
|
65
|
+
filename = "#{version}_#{name}.rb"
|
66
|
+
migration_name = name.gsub(/_(.)/) { $1.upcase }.gsub(/^(.)/) { $1.upcase }
|
67
|
+
|
68
|
+
FileUtils.mkdir_p(migrations_dir)
|
69
|
+
|
70
|
+
open(File.join(migrations_dir, filename), 'w') do |f|
|
71
|
+
f << (<<-EOS).gsub(" ", "")
|
72
|
+
class #{migration_name} < ActiveRecord::Migration
|
73
|
+
def self.up
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.down
|
77
|
+
end
|
78
|
+
end
|
79
|
+
EOS
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
4
|
+
begin
|
5
|
+
require 'vegas'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'vegas'
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'magistrate_monitor'
|
12
|
+
|
13
|
+
Vegas::Runner.new(MagistrateMonitor::Server, 'magistrate_monitor-web', {}) do |runner, opts, app|
|
14
|
+
|
15
|
+
end
|
data/config.ru
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
class CreateMagistrateMonitorTable < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :magistrate_supervisors do |t|
|
4
|
+
t.string :name
|
5
|
+
t.string :remote_ip
|
6
|
+
|
7
|
+
t.text :status
|
8
|
+
t.text :databag
|
9
|
+
|
10
|
+
t.datetime :last_checkin_at
|
11
|
+
|
12
|
+
t.boolean :active, :default => true
|
13
|
+
|
14
|
+
t.timestamps
|
15
|
+
end
|
16
|
+
|
17
|
+
add_index :magistrate_supervisors, :name, :unique => true
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.down
|
21
|
+
drop_table :magistrate_supervisors
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#main{
|
2
|
+
margin: 2em;
|
3
|
+
}
|
4
|
+
|
5
|
+
table{
|
6
|
+
margin: 0.5em;
|
7
|
+
}
|
8
|
+
|
9
|
+
th{
|
10
|
+
padding: 0.5em;
|
11
|
+
margin: 0.5em;
|
12
|
+
}
|
13
|
+
|
14
|
+
tr{
|
15
|
+
padding: 0.2em;
|
16
|
+
border: 1px solid black;
|
17
|
+
}
|
18
|
+
|
19
|
+
td{
|
20
|
+
padding: 0.4em;
|
21
|
+
margin: 0.4em;
|
22
|
+
border: 1px solid blue;
|
23
|
+
}
|
@@ -0,0 +1,276 @@
|
|
1
|
+
/*
|
2
|
+
* HTML5 Boilerplate
|
3
|
+
*
|
4
|
+
* What follows is the result of much research on cross-browser styling.
|
5
|
+
* Credit left inline and big thanks to Nicolas Gallagher, Jonathan Neal,
|
6
|
+
* Kroc Camen, and the H5BP dev community and team.
|
7
|
+
*/
|
8
|
+
|
9
|
+
|
10
|
+
/* =============================================================================
|
11
|
+
HTML5 element display
|
12
|
+
========================================================================== */
|
13
|
+
|
14
|
+
article, aside, details, figcaption, figure, footer, header, hgroup, nav, section { display: block; }
|
15
|
+
audio[controls], canvas, video { display: inline-block; *display: inline; *zoom: 1; }
|
16
|
+
|
17
|
+
|
18
|
+
/* =============================================================================
|
19
|
+
Base
|
20
|
+
========================================================================== */
|
21
|
+
|
22
|
+
/*
|
23
|
+
* 1. Correct text resizing oddly in IE6/7 when body font-size is set using em units
|
24
|
+
* http://clagnut.com/blog/348/#c790
|
25
|
+
* 2. Force vertical scrollbar in non-IE
|
26
|
+
* 3. Remove Android and iOS tap highlight color to prevent entire container being highlighted
|
27
|
+
* www.yuiblog.com/blog/2010/10/01/quick-tip-customizing-the-mobile-safari-tap-highlight-color/
|
28
|
+
* 4. Prevent iOS text size adjust on device orientation change, without disabling user zoom
|
29
|
+
* www.456bereastreet.com/archive/201012/controlling_text_size_in_safari_for_ios_without_disabling_user_zoom/
|
30
|
+
*/
|
31
|
+
|
32
|
+
html { font-size: 100%; overflow-y: scroll; -webkit-overflow-scrolling: touch; -webkit-tap-highlight-color: rgba(0,0,0,0); -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; }
|
33
|
+
|
34
|
+
body { margin: 0; font-size: 13px; line-height: 1.231; }
|
35
|
+
|
36
|
+
body, button, input, select, textarea { font-family: sans-serif; color: #222; }
|
37
|
+
|
38
|
+
/*
|
39
|
+
* These selection declarations have to be separate
|
40
|
+
* No text-shadow: twitter.com/miketaylr/status/12228805301
|
41
|
+
* Also: hot pink!
|
42
|
+
*/
|
43
|
+
|
44
|
+
::-moz-selection { background: #fe57a1; color: #fff; text-shadow: none; }
|
45
|
+
::selection { background: #fe57a1; color: #fff; text-shadow: none; }
|
46
|
+
|
47
|
+
|
48
|
+
/* =============================================================================
|
49
|
+
Links
|
50
|
+
========================================================================== */
|
51
|
+
|
52
|
+
a { color: #00e; }
|
53
|
+
a:visited { color: #551a8b; }
|
54
|
+
a:focus { outline: thin dotted; }
|
55
|
+
|
56
|
+
/* Improve readability when focused and hovered in all browsers: people.opera.com/patrickl/experiments/keyboard/test */
|
57
|
+
a:hover, a:active { outline: 0; }
|
58
|
+
|
59
|
+
|
60
|
+
/* =============================================================================
|
61
|
+
Typography
|
62
|
+
========================================================================== */
|
63
|
+
|
64
|
+
abbr[title] { border-bottom: 1px dotted; }
|
65
|
+
|
66
|
+
b, strong { font-weight: bold; }
|
67
|
+
|
68
|
+
blockquote { margin: 1em 40px; }
|
69
|
+
|
70
|
+
dfn { font-style: italic; }
|
71
|
+
|
72
|
+
hr { display: block; height: 1px; border: 0; border-top: 1px solid #ccc; margin: 1em 0; padding: 0; }
|
73
|
+
|
74
|
+
ins { background: #ff9; color: #000; text-decoration: none; }
|
75
|
+
|
76
|
+
mark { background: #ff0; color: #000; font-style: italic; font-weight: bold; }
|
77
|
+
|
78
|
+
/* Redeclare monospace font family: en.wikipedia.org/wiki/User:Davidgothberg/Test59 */
|
79
|
+
pre, code, kbd, samp { font-family: monospace, monospace; _font-family: 'courier new', monospace; font-size: 1em; }
|
80
|
+
|
81
|
+
/* Improve readability of pre-formatted text in all browsers */
|
82
|
+
pre { white-space: pre; white-space: pre-wrap; word-wrap: break-word; }
|
83
|
+
|
84
|
+
q { quotes: none; }
|
85
|
+
q:before, q:after { content: ""; content: none; }
|
86
|
+
|
87
|
+
small { font-size: 85%; }
|
88
|
+
|
89
|
+
/* Position subscript and superscript content without affecting line-height: gist.github.com/413930 */
|
90
|
+
sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; }
|
91
|
+
sup { top: -0.5em; }
|
92
|
+
sub { bottom: -0.25em; }
|
93
|
+
|
94
|
+
|
95
|
+
/* =============================================================================
|
96
|
+
Lists
|
97
|
+
========================================================================== */
|
98
|
+
|
99
|
+
ul, ol { margin: 1em 0; padding: 0 0 0 40px; }
|
100
|
+
dd { margin: 0 0 0 40px; }
|
101
|
+
nav ul, nav ol { list-style: none; margin: 0; padding: 0; }
|
102
|
+
|
103
|
+
|
104
|
+
/* =============================================================================
|
105
|
+
Embedded content
|
106
|
+
========================================================================== */
|
107
|
+
|
108
|
+
/*
|
109
|
+
* Improve image quality when scaled in IE7
|
110
|
+
* code.flickr.com/blog/2008/11/12/on-ui-quality-the-little-things-client-side-image-resizing/
|
111
|
+
*/
|
112
|
+
|
113
|
+
img { border: 0; -ms-interpolation-mode: bicubic; }
|
114
|
+
|
115
|
+
/*
|
116
|
+
* Correct overflow displayed oddly in IE9
|
117
|
+
*/
|
118
|
+
|
119
|
+
svg:not(:root) {
|
120
|
+
overflow: hidden;
|
121
|
+
}
|
122
|
+
|
123
|
+
|
124
|
+
/* =============================================================================
|
125
|
+
Figures
|
126
|
+
========================================================================== */
|
127
|
+
|
128
|
+
figure { margin: 0; }
|
129
|
+
|
130
|
+
|
131
|
+
/* =============================================================================
|
132
|
+
Forms
|
133
|
+
========================================================================== */
|
134
|
+
|
135
|
+
form { margin: 0; }
|
136
|
+
fieldset { border: 0; margin: 0; padding: 0; }
|
137
|
+
|
138
|
+
/*
|
139
|
+
* 1. Correct color not inheriting in IE6/7/8/9
|
140
|
+
* 2. Correct alignment displayed oddly in IE6/7
|
141
|
+
*/
|
142
|
+
|
143
|
+
legend { border: 0; *margin-left: -7px; padding: 0; }
|
144
|
+
|
145
|
+
/* Indicate that 'label' will shift focus to the associated form element */
|
146
|
+
label { cursor: pointer; }
|
147
|
+
|
148
|
+
/*
|
149
|
+
* 1. Correct font-size not inheriting in all browsers
|
150
|
+
* 2. Remove margins in FF3/4 S5 Chrome
|
151
|
+
* 3. Define consistent vertical alignment display in all browsers
|
152
|
+
*/
|
153
|
+
|
154
|
+
button, input, select, textarea { font-size: 100%; margin: 0; vertical-align: baseline; *vertical-align: middle; }
|
155
|
+
|
156
|
+
/*
|
157
|
+
* 1. Define line-height as normal to match FF3/4 (set using !important in the UA stylesheet)
|
158
|
+
* 2. Correct inner spacing displayed oddly in IE6/7
|
159
|
+
*/
|
160
|
+
|
161
|
+
button, input { line-height: normal; *overflow: visible; }
|
162
|
+
|
163
|
+
/*
|
164
|
+
* 1. Display hand cursor for clickable form elements
|
165
|
+
* 2. Allow styling of clickable form elements in iOS
|
166
|
+
*/
|
167
|
+
|
168
|
+
button, input[type="button"], input[type="reset"], input[type="submit"] { cursor: pointer; -webkit-appearance: button; }
|
169
|
+
|
170
|
+
/*
|
171
|
+
* Consistent box sizing and appearance
|
172
|
+
*/
|
173
|
+
|
174
|
+
input[type="checkbox"], input[type="radio"] { box-sizing: border-box; }
|
175
|
+
input[type="search"] { -moz-box-sizing: content-box; -webkit-box-sizing: content-box; box-sizing: content-box; }
|
176
|
+
|
177
|
+
/*
|
178
|
+
* Remove inner padding and border in FF3/4
|
179
|
+
* www.sitepen.com/blog/2008/05/14/the-devils-in-the-details-fixing-dojos-toolbar-buttons/
|
180
|
+
*/
|
181
|
+
|
182
|
+
button::-moz-focus-inner, input::-moz-focus-inner { border: 0; padding: 0; }
|
183
|
+
|
184
|
+
/* Remove default vertical scrollbar in IE6/7/8/9 */
|
185
|
+
textarea { overflow: auto; vertical-align: top; }
|
186
|
+
|
187
|
+
/* Colors for form validity */
|
188
|
+
input:valid, textarea:valid { }
|
189
|
+
input:invalid, textarea:invalid { background-color: #f0dddd; }
|
190
|
+
|
191
|
+
|
192
|
+
/* =============================================================================
|
193
|
+
Tables
|
194
|
+
========================================================================== */
|
195
|
+
|
196
|
+
table { border-collapse: collapse; border-spacing: 0; }
|
197
|
+
|
198
|
+
|
199
|
+
/* =============================================================================
|
200
|
+
Primary styles
|
201
|
+
Author:
|
202
|
+
========================================================================== */
|
203
|
+
|
204
|
+
|
205
|
+
|
206
|
+
|
207
|
+
|
208
|
+
|
209
|
+
|
210
|
+
|
211
|
+
/* =============================================================================
|
212
|
+
Non-semantic helper classes
|
213
|
+
Please define your styles before this section.
|
214
|
+
========================================================================== */
|
215
|
+
|
216
|
+
/* For image replacement */
|
217
|
+
.ir { display: block; text-indent: -999em; overflow: hidden; background-repeat: no-repeat; text-align: left; direction: ltr; }
|
218
|
+
.ir br { display: none; }
|
219
|
+
|
220
|
+
/* Hide for both screenreaders and browsers:
|
221
|
+
css-discuss.incutio.com/wiki/Screenreader_Visibility */
|
222
|
+
.hidden { display: none; visibility: hidden; }
|
223
|
+
|
224
|
+
/* Hide only visually, but have it available for screenreaders: by Jon Neal.
|
225
|
+
www.webaim.org/techniques/css/invisiblecontent/ & j.mp/visuallyhidden */
|
226
|
+
.visuallyhidden { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; }
|
227
|
+
|
228
|
+
/* Extends the .visuallyhidden class to allow the element to be focusable when navigated to via the keyboard: drupal.org/node/897638 */
|
229
|
+
.visuallyhidden.focusable:active, .visuallyhidden.focusable:focus { clip: auto; height: auto; margin: 0; overflow: visible; position: static; width: auto; }
|
230
|
+
|
231
|
+
/* Hide visually and from screenreaders, but maintain layout */
|
232
|
+
.invisible { visibility: hidden; }
|
233
|
+
|
234
|
+
/* Contain floats: nicolasgallagher.com/micro-clearfix-hack/ */
|
235
|
+
.clearfix:before, .clearfix:after { content: ""; display: table; }
|
236
|
+
.clearfix:after { clear: both; }
|
237
|
+
.clearfix { zoom: 1; }
|
238
|
+
|
239
|
+
|
240
|
+
|
241
|
+
/* =============================================================================
|
242
|
+
PLACEHOLDER Media Queries for Responsive Design.
|
243
|
+
These override the primary ('mobile first') styles
|
244
|
+
Modify as content requires.
|
245
|
+
========================================================================== */
|
246
|
+
|
247
|
+
@media only screen and (min-width: 480px) {
|
248
|
+
/* Style adjustments for viewports 480px and over go here */
|
249
|
+
|
250
|
+
}
|
251
|
+
|
252
|
+
@media only screen and (min-width: 768px) {
|
253
|
+
/* Style adjustments for viewports 768px and over go here */
|
254
|
+
|
255
|
+
}
|
256
|
+
|
257
|
+
|
258
|
+
/* =============================================================================
|
259
|
+
Print styles.
|
260
|
+
Inlined to avoid required HTTP connection: www.phpied.com/delay-loading-your-print-css/
|
261
|
+
========================================================================== */
|
262
|
+
|
263
|
+
@media print {
|
264
|
+
* { background: transparent !important; color: black !important; text-shadow: none !important; filter:none !important; -ms-filter: none !important; } /* Black prints faster: sanbeiji.com/archives/953 */
|
265
|
+
a, a:visited { color: #444 !important; text-decoration: underline; }
|
266
|
+
a[href]:after { content: " (" attr(href) ")"; }
|
267
|
+
abbr[title]:after { content: " (" attr(title) ")"; }
|
268
|
+
.ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; } /* Don't show links for images, or javascript/internal links */
|
269
|
+
pre, blockquote { border: 1px solid #999; page-break-inside: avoid; }
|
270
|
+
thead { display: table-header-group; } /* css-discuss.incutio.com/wiki/Printing_Tables */
|
271
|
+
tr, img { page-break-inside: avoid; }
|
272
|
+
img { max-width: 100% !important; }
|
273
|
+
@page { margin: 0.5cm; }
|
274
|
+
p, h2, h3 { orphans: 3; widows: 3; }
|
275
|
+
h2, h3{ page-break-after: avoid; }
|
276
|
+
}
|
data/lib/server.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'sinatra-activerecord'
|
3
|
+
|
4
|
+
require 'supervisor'
|
5
|
+
|
6
|
+
module MagistrateMonitor
|
7
|
+
class Server < Sinatra::Base
|
8
|
+
dir = File.dirname(File.expand_path(__FILE__))
|
9
|
+
|
10
|
+
set :views, "#{dir}/views"
|
11
|
+
set :public, "#{dir}/public"
|
12
|
+
set :static, true
|
13
|
+
|
14
|
+
get '/', :provides => 'html' do
|
15
|
+
@supervisors = Supervisor.order('name ASC').all
|
16
|
+
normalize_status_data!
|
17
|
+
|
18
|
+
erb :index
|
19
|
+
end
|
20
|
+
|
21
|
+
get '/supervisors/:name' do
|
22
|
+
@supervisor = Supervisor.find_by_name params[:name]
|
23
|
+
erb :show
|
24
|
+
end
|
25
|
+
|
26
|
+
# Responds with the latest databag instructions for the supervisor
|
27
|
+
get '/api/status/:name' do
|
28
|
+
@supervisor = Supervisor.find_or_create_by_name params[:name]
|
29
|
+
|
30
|
+
content_type :json
|
31
|
+
ActiveSupport::JSON.encode( @supervisor.databag || {} )
|
32
|
+
end
|
33
|
+
|
34
|
+
# Saves the status update to the db
|
35
|
+
post '/api/status/:name' do
|
36
|
+
@supervisor = Supervisor.find_or_create_by_name params[:name]
|
37
|
+
|
38
|
+
status = ActiveSupport::JSON.decode( params[:status] )
|
39
|
+
|
40
|
+
@supervisor.update_attributes :last_checkin_at => Time.now, :status => status
|
41
|
+
|
42
|
+
content_type :json
|
43
|
+
ActiveSupport::JSON.encode( {:status => 'Ok'} )
|
44
|
+
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
|
49
|
+
@supervisor = Supervisor.find_or_create_by_name params[:supervisor_name]
|
50
|
+
|
51
|
+
@supervisor.set_target_state!(params[:action], params[:worker_name])
|
52
|
+
redirect url_for('/')
|
53
|
+
end
|
54
|
+
|
55
|
+
helpers do
|
56
|
+
def url_for(path)
|
57
|
+
"#{request.env['SCRIPT_NAME']}/#{path}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def url_for_worker(supervisor, name, action)
|
61
|
+
url_for("set/#{supervisor.name}/#{name}/#{action}")
|
62
|
+
end
|
63
|
+
|
64
|
+
def normalize_status_data!
|
65
|
+
@supervisors.each do |supervisor|
|
66
|
+
supervisor.normalize_status_data!
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'active_support/all'
|
3
|
+
require 'logger'
|
4
|
+
require 'yaml'
|
5
|
+
require 'erb'
|
6
|
+
|
7
|
+
module Sinatra
|
8
|
+
module ActiveRecordHelper
|
9
|
+
def database
|
10
|
+
options.database
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module ActiveRecordExtension
|
15
|
+
def database=(cfg)
|
16
|
+
@database = nil
|
17
|
+
set :database_options, cfg
|
18
|
+
database
|
19
|
+
end
|
20
|
+
|
21
|
+
def database
|
22
|
+
@database ||= (
|
23
|
+
#ActiveRecord::Base.logger ||= activerecord_logger # Having this enabled overrides Rails TODO: Find a way to make it not override Rails
|
24
|
+
ActiveRecord::Base.establish_connection(database_options)
|
25
|
+
ActiveRecord::Base
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
def self.registered(app)
|
31
|
+
app.set :database_options, Hash.new
|
32
|
+
app.set :database_extras, Hash.new
|
33
|
+
app.set :activerecord_logger, Logger.new(STDOUT)
|
34
|
+
# app.database # force connection
|
35
|
+
app.helpers ActiveRecordHelper
|
36
|
+
|
37
|
+
app.configure do
|
38
|
+
if defined?(Rails)
|
39
|
+
env = Rails.env
|
40
|
+
else
|
41
|
+
|
42
|
+
env = ENV['RACK_ENV'] || 'development'
|
43
|
+
end
|
44
|
+
|
45
|
+
file = File.join('config', 'database.yml')
|
46
|
+
|
47
|
+
app.database = YAML::load(ERB.new(IO.read(file)).result).with_indifferent_access[env]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
register ActiveRecordExtension
|
53
|
+
end
|
data/lib/supervisor.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
module MagistrateMonitor
|
2
|
+
class Supervisor < ActiveRecord::Base
|
3
|
+
set_table_name 'magistrate_supervisors'
|
4
|
+
|
5
|
+
serialize :status, Hash
|
6
|
+
serialize :databag, Hash
|
7
|
+
|
8
|
+
# This makes sure that:
|
9
|
+
# All supervisors have a status that is a hash
|
10
|
+
# If it has something else for whatever reason, the real object is put in a hash under the 'status' key
|
11
|
+
def normalize_status_data!
|
12
|
+
self.status ||= {}
|
13
|
+
|
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|
|
19
|
+
unless v.is_a?(Hash)
|
20
|
+
v = {'state' => v.inspect }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
self.databag ||= {'workers' => {}}
|
25
|
+
end
|
26
|
+
|
27
|
+
def set_target_state!(action, worker)
|
28
|
+
d = self.databag || {}
|
29
|
+
d['workers'] ||= {}
|
30
|
+
d['workers'][worker] = {'target_state' => action }
|
31
|
+
self.update_attribute :databag, d
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/views/index.erb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
<h1>MagistrateMonitor :: Supervisor list</h1>
|
2
|
+
|
3
|
+
<table>
|
4
|
+
<thead>
|
5
|
+
<tr>
|
6
|
+
<th>Supervisor</th>
|
7
|
+
<th>Worker</th>
|
8
|
+
<th>State</th>
|
9
|
+
<th>Client Target State</th>
|
10
|
+
<th>Server Target State</th>
|
11
|
+
<th colspan="3">Actions</th>
|
12
|
+
</tr>
|
13
|
+
</thead>
|
14
|
+
|
15
|
+
<% @supervisors.each do |supervisor| %>
|
16
|
+
<tr>
|
17
|
+
<th><a href="<%= url_for "supervisors/#{supervisor.name}" %>"><%= supervisor.name %></a><br>
|
18
|
+
<%= supervisor.last_checkin_at %></th>
|
19
|
+
<th colspan="7"> - </th>
|
20
|
+
</tr>
|
21
|
+
<% supervisor.status.each do |k,v| %>
|
22
|
+
<tr>
|
23
|
+
<th> - </th>
|
24
|
+
<th><%= k %></th>
|
25
|
+
<td><%= v['state'] %></td>
|
26
|
+
<td><%= v['target_state']%></td>
|
27
|
+
<td><%= supervisor.databag['workers'][k]['target_state'] if supervisor.databag['workers'].is_a?(Hash) && supervisor.databag['workers'][k].is_a?(Hash) %></td>
|
28
|
+
<td>
|
29
|
+
<% if v['state'] != 'running' %>
|
30
|
+
<a href="<%= url_for_worker(supervisor, k, 'running') %>">Run</a>
|
31
|
+
<% end %>
|
32
|
+
</td>
|
33
|
+
<td>
|
34
|
+
<% if v['state'] != 'stopped' %>
|
35
|
+
<a href="<%= url_for_worker(supervisor, k, 'stopped') %>">Stop</a>
|
36
|
+
<% end %>
|
37
|
+
</td>
|
38
|
+
<td>
|
39
|
+
<% if v['state'] != 'unmonitored' %>
|
40
|
+
<a href="<%= url_for_worker(supervisor, k, 'unmonitored') %>">Unmonitor</a>
|
41
|
+
<% end %>
|
42
|
+
</td>
|
43
|
+
</tr>
|
44
|
+
<% end %>
|
45
|
+
<% end %>
|
46
|
+
</table>
|
@@ -0,0 +1,31 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<head>
|
3
|
+
<meta charset="utf-8">
|
4
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
5
|
+
|
6
|
+
<title>MagistrateMonitor</title>
|
7
|
+
|
8
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
9
|
+
|
10
|
+
<link rel="stylesheet" href="<%= url_for('/css/style.css') %>">
|
11
|
+
<link rel="stylesheet" href="<%= url_for('/css/application.css') %>">
|
12
|
+
|
13
|
+
</head>
|
14
|
+
<body>
|
15
|
+
|
16
|
+
<div id="container">
|
17
|
+
<header>
|
18
|
+
|
19
|
+
</header>
|
20
|
+
<div id="main" role="main">
|
21
|
+
<%= yield %>
|
22
|
+
</div>
|
23
|
+
<footer>
|
24
|
+
|
25
|
+
</footer>
|
26
|
+
</div> <!--! end of #container -->
|
27
|
+
|
28
|
+
<script src="/js/application.js"></script>
|
29
|
+
|
30
|
+
</body>
|
31
|
+
</html>
|
data/lib/views/show.erb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
<h1>Supervisor Details : <%= params[:name] %></h1>
|
2
|
+
|
3
|
+
<% if @supervisor %>
|
4
|
+
<h3>Status from supervisor</h3>
|
5
|
+
<p><pre>
|
6
|
+
<%= @supervisor.status.inspect %>
|
7
|
+
</pre></p>
|
8
|
+
|
9
|
+
<h3>Databag to be sent to supervisor</h3>
|
10
|
+
<p><pre>
|
11
|
+
<%= @supervisor.databag.inspect %>
|
12
|
+
</pre></p>
|
13
|
+
<% else %>
|
14
|
+
No supervisor by the name <%= params[:name] %>
|
15
|
+
<% end %>
|
data/spec/server_spec.rb
ADDED
File without changes
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
require 'rspec'
|
4
|
+
require 'magistrate_monitor'
|
5
|
+
|
6
|
+
# Requires supporting files with custom matchers and macros, etc,
|
7
|
+
# in ./support/ and its subdirectories.
|
8
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
config.mock_with :rspec
|
12
|
+
config.color_enabled = true
|
13
|
+
end
|
File without changes
|
metadata
ADDED
@@ -0,0 +1,205 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: magistrate_monitor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Drew Blas
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-08-10 00:00:00 -05:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rake
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: rspec
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 23
|
44
|
+
segments:
|
45
|
+
- 2
|
46
|
+
- 6
|
47
|
+
- 0
|
48
|
+
version: 2.6.0
|
49
|
+
type: :development
|
50
|
+
version_requirements: *id002
|
51
|
+
- !ruby/object:Gem::Dependency
|
52
|
+
name: rcov
|
53
|
+
prerelease: false
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 3
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
version: "0"
|
63
|
+
type: :development
|
64
|
+
version_requirements: *id003
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: sqlite3
|
67
|
+
prerelease: false
|
68
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
hash: 3
|
74
|
+
segments:
|
75
|
+
- 0
|
76
|
+
version: "0"
|
77
|
+
type: :development
|
78
|
+
version_requirements: *id004
|
79
|
+
- !ruby/object:Gem::Dependency
|
80
|
+
name: mongrel
|
81
|
+
prerelease: false
|
82
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
hash: 3
|
88
|
+
segments:
|
89
|
+
- 0
|
90
|
+
version: "0"
|
91
|
+
type: :development
|
92
|
+
version_requirements: *id005
|
93
|
+
- !ruby/object:Gem::Dependency
|
94
|
+
name: sinatra
|
95
|
+
prerelease: false
|
96
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
hash: 19
|
102
|
+
segments:
|
103
|
+
- 1
|
104
|
+
- 2
|
105
|
+
- 6
|
106
|
+
version: 1.2.6
|
107
|
+
type: :runtime
|
108
|
+
version_requirements: *id006
|
109
|
+
- !ruby/object:Gem::Dependency
|
110
|
+
name: activerecord
|
111
|
+
prerelease: false
|
112
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
hash: 7
|
118
|
+
segments:
|
119
|
+
- 3
|
120
|
+
- 0
|
121
|
+
version: "3.0"
|
122
|
+
type: :runtime
|
123
|
+
version_requirements: *id007
|
124
|
+
- !ruby/object:Gem::Dependency
|
125
|
+
name: activesupport
|
126
|
+
prerelease: false
|
127
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
128
|
+
none: false
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
hash: 7
|
133
|
+
segments:
|
134
|
+
- 3
|
135
|
+
- 0
|
136
|
+
version: "3.0"
|
137
|
+
type: :runtime
|
138
|
+
version_requirements: *id008
|
139
|
+
description: Receives checkins from the magistrate gem and sends back commands
|
140
|
+
email: drew.blas@gmail.com
|
141
|
+
executables: []
|
142
|
+
|
143
|
+
extensions: []
|
144
|
+
|
145
|
+
extra_rdoc_files:
|
146
|
+
- LICENSE.txt
|
147
|
+
- README.md
|
148
|
+
files:
|
149
|
+
- Gemfile
|
150
|
+
- LICENSE.txt
|
151
|
+
- README.md
|
152
|
+
- Rakefile
|
153
|
+
- config.ru
|
154
|
+
- bin/magistrate_monitor-web
|
155
|
+
- db/migrate/20110808122502_create_magistrate_monitor_table.rb
|
156
|
+
- lib/magistrate_monitor.rb
|
157
|
+
- lib/server.rb
|
158
|
+
- lib/sinatra-activerecord.rb
|
159
|
+
- lib/supervisor.rb
|
160
|
+
- lib/public/css/application.css
|
161
|
+
- lib/public/css/style.css
|
162
|
+
- lib/views/index.erb
|
163
|
+
- lib/views/layout.erb
|
164
|
+
- lib/views/show.erb
|
165
|
+
- spec/spec_helper.rb
|
166
|
+
- spec/server_spec.rb
|
167
|
+
- spec/supervisor_spec.rb
|
168
|
+
has_rdoc: true
|
169
|
+
homepage: http://github.com/drewblas/magistrate_monitor
|
170
|
+
licenses:
|
171
|
+
- MIT
|
172
|
+
post_install_message:
|
173
|
+
rdoc_options: []
|
174
|
+
|
175
|
+
require_paths:
|
176
|
+
- lib
|
177
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
178
|
+
none: false
|
179
|
+
requirements:
|
180
|
+
- - ">="
|
181
|
+
- !ruby/object:Gem::Version
|
182
|
+
hash: 3
|
183
|
+
segments:
|
184
|
+
- 0
|
185
|
+
version: "0"
|
186
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
187
|
+
none: false
|
188
|
+
requirements:
|
189
|
+
- - ">="
|
190
|
+
- !ruby/object:Gem::Version
|
191
|
+
hash: 3
|
192
|
+
segments:
|
193
|
+
- 0
|
194
|
+
version: "0"
|
195
|
+
requirements: []
|
196
|
+
|
197
|
+
rubyforge_project:
|
198
|
+
rubygems_version: 1.6.2
|
199
|
+
signing_key:
|
200
|
+
specification_version: 3
|
201
|
+
summary: The user frontend to monitoring and managing the magistrate gem
|
202
|
+
test_files:
|
203
|
+
- spec/spec_helper.rb
|
204
|
+
- spec/server_spec.rb
|
205
|
+
- spec/supervisor_spec.rb
|