magistrate_monitor 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
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,2 @@
1
+ require 'lib/magistrate_monitor'
2
+ run MagistrateMonitor::Server
@@ -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,5 @@
1
+ DIAGNOSTIC_LOGGER = defined?(Rails) ? Rails.logger : require('logger') && Logger.new($stdout)
2
+
3
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
4
+
5
+ require 'server'
@@ -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
@@ -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>
@@ -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 %>
File without changes
@@ -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