wackamole 0.0.8 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +5 -1
- data/README.rdoc +12 -3
- data/bin/wackamole +2 -2
- data/data/fixtures.rb +132 -0
- data/features/env.rb +29 -0
- data/features/mission.feature +10 -0
- data/features/step_definitions/mission_steps.rb +5 -0
- data/lib/app.rb +23 -7
- data/lib/controllers/features.rb +3 -2
- data/lib/controllers/logs.rb +1 -0
- data/lib/controllers/mission.rb +14 -4
- data/lib/controllers/session.rb +32 -0
- data/lib/controllers/users.rb +3 -2
- data/lib/helpers/flash_helper.rb +4 -1
- data/lib/helpers/logs_helper.rb +2 -1
- data/lib/helpers/session_helper.rb +29 -0
- data/lib/wackamole.rb +1 -1
- data/lib/wackamole/models/control.rb +15 -1
- data/lib/wackamole/models/feature.rb +11 -2
- data/lib/wackamole/models/log.rb +1 -0
- data/lib/wackamole/models/mission.rb +9 -7
- data/lib/wackamole/models/mole_info.rb +8 -4
- data/lib/wackamole/models/search_filter.rb +48 -15
- data/lib/wackamole/models/user.rb +12 -1
- data/public/stylesheets/wackamole.css +60 -3
- data/spec/config/bogus_test.yml +1 -1
- data/spec/config/test.yml +1 -1
- data/spec/spec_helper.rb +3 -0
- data/spec/ui/log_spec.rb +68 -0
- data/spec/ui/mission_spec.rb +64 -0
- data/spec/ui/session_spec.rb +39 -0
- data/spec/ui_utils/mission_util.rb +41 -0
- data/spec/{models → wackamole/models}/control_spec.rb +21 -21
- data/spec/{models → wackamole/models}/feature_spec.rb +7 -7
- data/spec/{models → wackamole/models}/log_spec.rb +5 -5
- data/spec/{models → wackamole/models}/mission_spec.rb +11 -7
- data/spec/wackamole/models/moled_info_spec.rb +36 -0
- data/spec/{models → wackamole/models}/search_filter_spec.rb +12 -16
- data/spec/{models → wackamole/models}/user_spec.rb +5 -5
- data/spec/{wackamole_spec.rb → wackamole/wackamole_spec.rb} +2 -2
- data/tasks/fixtures.rake +3 -1
- data/tasks/setup.rb +2 -1
- data/tasks/spec.rake +17 -3
- data/views/dashboard/_report.erb +3 -3
- data/views/layout.erb +44 -11
- data/views/logs/show.erb +3 -0
- data/views/mission/_report.erb +2 -2
- data/views/session/login.erb +28 -0
- data/views/shared/_search.erb +1 -1
- data/views/users/index.js.erb +1 -1
- metadata +22 -10
- data/spec/models/moled_info_spec.rb +0 -30
data/History.txt
CHANGED
@@ -27,4 +27,8 @@
|
|
27
27
|
* Bug fixes and clean up
|
28
28
|
|
29
29
|
=== 0.0.8 /2010-02-21
|
30
|
-
* Fix bug on mission and local time
|
30
|
+
* Fix bug on mission and local time
|
31
|
+
|
32
|
+
=== 0.0.9 /2010-02-28
|
33
|
+
* Added console authentication - see README for info
|
34
|
+
* Added support for auth on mongo instance - see README for info
|
data/README.rdoc
CHANGED
@@ -49,12 +49,21 @@
|
|
49
49
|
a file wackamole.yml. You will need to specify the envs, host and ports specific
|
50
50
|
to your configuration, but here is a sample.
|
51
51
|
|
52
|
-
wackamole.yml
|
52
|
+
wackamole.yml
|
53
|
+
|
54
|
+
# New ! Optionally you can specify login name and password for the Wackamole web app.
|
55
|
+
console_auth: &auth
|
56
|
+
auth:
|
57
|
+
user: admin
|
58
|
+
password: admin
|
59
|
+
|
53
60
|
development:
|
54
|
-
|
55
|
-
|
61
|
+
<<: *auth
|
62
|
+
host: localhost
|
63
|
+
port: 27017
|
56
64
|
|
57
65
|
beta:
|
66
|
+
<<: *auth
|
58
67
|
host: beta_host_name
|
59
68
|
port: 27017
|
60
69
|
user: bobo
|
data/bin/wackamole
CHANGED
@@ -7,7 +7,7 @@ URI_MATCH = /(mongo|memcache):\/\/(.+?)\:(\d+)\/(\w+)\/{0,1}(\w*)/
|
|
7
7
|
Main {
|
8
8
|
option( 'pool=[pool]', 'p' ) {
|
9
9
|
validate { |pool| pool =~ URI_MATCH }
|
10
|
-
description "specify session server uri. Must be of the form {[mongo|memcache]}://{host}:{port}/{[database_name|namespace]}[/{collection_name}]"
|
10
|
+
description "specify session server uri. Must be of the form {[mongo|memcache]}://{host}:{port}/{[database_name|namespace]}[/{collection_name}]. Defaults to local memcached on default port"
|
11
11
|
}
|
12
12
|
option( 'environment', 'e' ) {
|
13
13
|
argument :required
|
@@ -26,7 +26,7 @@ Main {
|
|
26
26
|
|
27
27
|
Thread.new do
|
28
28
|
puts "-"*100
|
29
|
-
puts "Initializing Wackamole -- Version #{Wackamole::VERSION}"
|
29
|
+
puts "Initializing Wackamole -- Version #{Wackamole::VERSION} -- Landscape #{params['environment']}"
|
30
30
|
puts "-"*100
|
31
31
|
puts "\n"*2
|
32
32
|
puts ">>> Waiting for Franky to warm up..."
|
data/data/fixtures.rb
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "mongo"
|
3
|
+
require 'rackamole'
|
4
|
+
require 'wackamole'
|
5
|
+
|
6
|
+
class Fixtures
|
7
|
+
attr_reader :con
|
8
|
+
|
9
|
+
def mole_collections() %w(users features logs); end
|
10
|
+
|
11
|
+
def initialize( host='localhost', port=27099 )
|
12
|
+
puts "Loading fixture data"
|
13
|
+
@con = Mongo::Connection.new( host, port )
|
14
|
+
end
|
15
|
+
|
16
|
+
def clear
|
17
|
+
con.database_names.select do |db_name|
|
18
|
+
if db_name =~ /^mole_/
|
19
|
+
puts "Dropping db #{db_name}"
|
20
|
+
@con.drop_database( db_name )
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def populate
|
26
|
+
clear
|
27
|
+
apps = [
|
28
|
+
%w(app1 test),
|
29
|
+
%w(app2 test)
|
30
|
+
]
|
31
|
+
apps.each { |config| create_mole_db( config.first, config.last ) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def create_mole_db( app_name, env )
|
35
|
+
db_name = mole_db_name( app_name, env )
|
36
|
+
provision( db_name )
|
37
|
+
end
|
38
|
+
|
39
|
+
def provision( db_name )
|
40
|
+
db = con.db( db_name )
|
41
|
+
clear_collections(db) if db
|
42
|
+
|
43
|
+
populate_features( db )
|
44
|
+
populate_users( db )
|
45
|
+
populate_logs( db )
|
46
|
+
end
|
47
|
+
|
48
|
+
def populate_features( db )
|
49
|
+
app_name, stage = Wackamole::Control.extract_app_info( db.name )
|
50
|
+
%w(/ /normal /params/10 /error /slow /post ).each do |ctx|
|
51
|
+
row = {
|
52
|
+
:app => app_name,
|
53
|
+
:env => stage,
|
54
|
+
:did => Time.now.utc.to_date_id.to_s,
|
55
|
+
:ctx => ctx
|
56
|
+
}
|
57
|
+
db['features'].insert( row )
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def populate_users( db )
|
62
|
+
%w(fernand bobo bubba eddie freddie).each do |user|
|
63
|
+
row = { :una => user, :did => Time.now.to_date_id }
|
64
|
+
db['users'].insert( row )
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def populate_logs( db )
|
69
|
+
logs_cltn = db['logs']
|
70
|
+
user_config = {
|
71
|
+
'fernand' => {
|
72
|
+
:days => 2,
|
73
|
+
:activities => [2, 1, 0]
|
74
|
+
},
|
75
|
+
'bobo' => {
|
76
|
+
:days => 3,
|
77
|
+
:activities => [1, 1, 1]
|
78
|
+
}
|
79
|
+
}
|
80
|
+
user_config.each_pair do |user_name, activity|
|
81
|
+
user = db['users'].find_one( { :una => user_name } )
|
82
|
+
(0...activity[:days]).each do |day|
|
83
|
+
date = Time.now - day*(24*60*60)
|
84
|
+
count = 0
|
85
|
+
[Rackamole.feature, Rackamole.perf, Rackamole.fault].each do |type|
|
86
|
+
create_logs( db, logs_cltn, activity[:activities][count], type, date.utc, user )
|
87
|
+
count += 1
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def create_logs( db, logs_cltn, count, type, time, user )
|
94
|
+
date_id = time.to_date_id
|
95
|
+
features = db['features'].find( {} ).to_a
|
96
|
+
(0...count).each do |i|
|
97
|
+
time_id = "%02d0100" % (i%23)
|
98
|
+
create_log( logs_cltn, type, date_id, time_id, user, features[i%features.size] )
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def create_log( logs_cltn, type, date_id, time_id, user, feature )
|
103
|
+
row = {
|
104
|
+
:url => "http://localhost:3000#{feature['ctx']}",
|
105
|
+
:typ => type,
|
106
|
+
:fid => feature['_id'],
|
107
|
+
:hos => 'localhost',
|
108
|
+
:met => 'GET',
|
109
|
+
:sts => 200,
|
110
|
+
:did => date_id.to_s,
|
111
|
+
:tid => time_id.to_s,
|
112
|
+
:rti => (type == Rackamole.perf ? 10 : 1),
|
113
|
+
:bro => { :version => '1.0', :name => 'Firefox' },
|
114
|
+
:sof => "thin 1.2.5 codename This Is Not A Web Server",
|
115
|
+
:hdr => { 'Content-Type' => 'text/html', 'Content-Length' => 100 },
|
116
|
+
:par => { :blee => 10, :duh => "bumblebeetuna" },
|
117
|
+
:uid => user['_id'],
|
118
|
+
:mac => { :version => 10.6, :platform => 'Macintosh', :os => 'Intel Mac OS X' },
|
119
|
+
:ses => { :user_name => user['una'] }
|
120
|
+
}
|
121
|
+
logs_cltn.insert( row )
|
122
|
+
end
|
123
|
+
|
124
|
+
def mole_db_name( app_name, env )
|
125
|
+
"mole_#{app_name}_#{env}_mdb"
|
126
|
+
end
|
127
|
+
|
128
|
+
def clear_collections( db )
|
129
|
+
mole_collections.each { |cltn| db.drop_collection( cltn ) }
|
130
|
+
end
|
131
|
+
end
|
132
|
+
# Fixtures.new.populate
|
data/features/env.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
app_file = File.join( File.dirname(__FILE__), *%w[.. lib app.rb] )
|
2
|
+
require app_file
|
3
|
+
|
4
|
+
# Force the application name because polyglot breaks the auto-detection logic.
|
5
|
+
Sinatra::Application.app_file = app_file
|
6
|
+
|
7
|
+
require 'spec/expectations'
|
8
|
+
require 'spec/interop/test'
|
9
|
+
require 'rack/test'
|
10
|
+
require 'sinatra/test'
|
11
|
+
require 'capybara'
|
12
|
+
|
13
|
+
# Webrat.configure do |config|
|
14
|
+
# config.mode = :rack
|
15
|
+
# end
|
16
|
+
|
17
|
+
class MyWorld
|
18
|
+
include Rack::Test::Methods
|
19
|
+
# include Webrat::Methods
|
20
|
+
# include Webrat::Matchers
|
21
|
+
|
22
|
+
# Webrat::Methods.delegate_to_session :response_code, :response_body
|
23
|
+
|
24
|
+
def app
|
25
|
+
Sinatra::Application
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
World{MyWorld.new}
|
@@ -0,0 +1,10 @@
|
|
1
|
+
Feature: Manage moled applications
|
2
|
+
In order to view my application cruise control
|
3
|
+
As a user
|
4
|
+
I want to see all my moled applications
|
5
|
+
|
6
|
+
Scenario: Moles application list
|
7
|
+
Given I have applications named App1, App2
|
8
|
+
When I go to the mission
|
9
|
+
Then I should see App1
|
10
|
+
And I should see App2
|
data/lib/app.rb
CHANGED
@@ -5,6 +5,7 @@ require 'mongo'
|
|
5
5
|
gem 'agnostic-will_paginate'
|
6
6
|
require 'will_paginate'
|
7
7
|
require 'mongo_rack'
|
8
|
+
require 'rack-flash'
|
8
9
|
require 'rackamole'
|
9
10
|
require File.expand_path( File.join( File.dirname(__FILE__), 'wackamole.rb' ) )
|
10
11
|
|
@@ -18,9 +19,9 @@ end
|
|
18
19
|
# -----------------------------------------------------------------------------
|
19
20
|
# Configurations
|
20
21
|
|
21
|
-
configure :production do
|
22
|
-
|
23
|
-
end
|
22
|
+
# configure :production do
|
23
|
+
# set :logging, true
|
24
|
+
# end
|
24
25
|
|
25
26
|
configure do
|
26
27
|
set :sessions, false
|
@@ -29,6 +30,8 @@ configure do
|
|
29
30
|
Wackamole.load_all_libs_relative_to(__FILE__, 'helpers' )
|
30
31
|
Wackamole.load_all_libs_relative_to(__FILE__, 'controllers' )
|
31
32
|
|
33
|
+
# use Rack::Flash, :accessorize => [:notice, :error]
|
34
|
+
|
32
35
|
#Pick up command line args if any?
|
33
36
|
if defined? @@options and @@options
|
34
37
|
if @@options[:protocol] == 'mongo'
|
@@ -41,18 +44,31 @@ configure do
|
|
41
44
|
:namespace => @@options[:namespace]
|
42
45
|
end
|
43
46
|
else
|
47
|
+
# Default is local memcache on default port.
|
48
|
+
use Rack::Session::Memcache,
|
49
|
+
:memcache_server => "%s:%d" % ['localhost', 11211],
|
50
|
+
:namespace => 'wackamole'
|
51
|
+
|
44
52
|
# Default is a mongo session store
|
45
|
-
use Rack::Session::Mongo,
|
46
|
-
|
47
|
-
|
53
|
+
# use Rack::Session::Mongo,
|
54
|
+
# :server => "%s:%d/%s/%s" % ['localhost', '27017', 'wackamole_ses', 'sessions'],
|
55
|
+
# :log_level => :error
|
48
56
|
end
|
49
57
|
Wackamole::Control.init_config( default_config, Sinatra::Application.environment.to_s )
|
50
58
|
end
|
51
59
|
|
52
60
|
# -----------------------------------------------------------------------------
|
53
61
|
# Before filters
|
54
|
-
before do
|
62
|
+
before do
|
55
63
|
unless request.path =~ /\.[css gif png js]/
|
64
|
+
if console_auth?
|
65
|
+
unless request.path == '/' or request.path == '/session/create' or request.path == '/session/delete'
|
66
|
+
unless authenticated?
|
67
|
+
redirect '/'
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
56
72
|
@filter = session[:filter]
|
57
73
|
unless @filter
|
58
74
|
@filter = Wackamole::SearchFilter.new
|
data/lib/controllers/features.rb
CHANGED
@@ -22,8 +22,9 @@ module Features
|
|
22
22
|
@filter.search_terms = params[:search_filter][:search_terms]
|
23
23
|
@features = Wackamole::Feature.paginate_tops( @filter.to_conds )
|
24
24
|
rescue => boom
|
25
|
-
|
26
|
-
|
25
|
+
puts boom
|
26
|
+
flash_it!( :error, boom )
|
27
|
+
@filter.search_terms = nil
|
27
28
|
@features = [].paginate
|
28
29
|
end
|
29
30
|
|
data/lib/controllers/logs.rb
CHANGED
data/lib/controllers/mission.rb
CHANGED
@@ -2,15 +2,25 @@ require 'chronic'
|
|
2
2
|
|
3
3
|
module Mission
|
4
4
|
# ---------------------------------------------------------------------------
|
5
|
-
get '/' do
|
6
|
-
|
5
|
+
get '/mission' do
|
6
|
+
clear_flash!
|
7
|
+
|
8
|
+
# reset app info
|
7
9
|
session[:app_info] = @app_info = nil
|
8
10
|
|
11
|
+
# Support store like mongodb where not allowed to peruse connection
|
12
|
+
# in which case just show the dashboard
|
13
|
+
if Wackamole::Control.single_app?
|
14
|
+
app_name, stage = Wackamole::Control.app_info
|
15
|
+
redirect "/dashboard/#{app_name}/#{stage}"
|
16
|
+
return
|
17
|
+
end
|
18
|
+
|
9
19
|
last_tick = session[:last_tick]
|
10
20
|
last_tick ||= Chronic.parse( "#{@refresh_rate} seconds ago" )
|
11
21
|
session[:last_tick] = Time.now
|
12
22
|
|
13
|
-
@pulse = Wackamole::Mission.pulse( last_tick
|
23
|
+
@pulse = Wackamole::Mission.pulse( last_tick )
|
14
24
|
|
15
25
|
erb :'mission/index'
|
16
26
|
end
|
@@ -21,7 +31,7 @@ module Mission
|
|
21
31
|
last_tick ||= Chronic.parse( "#{@refresh_rate} seconds ago" )
|
22
32
|
session[:last_tick] = Time.now
|
23
33
|
|
24
|
-
@pulse = Wackamole::Mission.pulse( last_tick
|
34
|
+
@pulse = Wackamole::Mission.pulse( last_tick )
|
25
35
|
|
26
36
|
erb :'/mission/refresh_js', :layout => false
|
27
37
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Session
|
2
|
+
|
3
|
+
# ---------------------------------------------------------------------------
|
4
|
+
# Check auth
|
5
|
+
get "/" do
|
6
|
+
if console_auth?
|
7
|
+
# clear_flash!
|
8
|
+
erb :'session/login'
|
9
|
+
else
|
10
|
+
redirect '/mission'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# ---------------------------------------------------------------------------
|
15
|
+
# Log out
|
16
|
+
get "/session/delete" do
|
17
|
+
session.clear
|
18
|
+
redirect '/'
|
19
|
+
end
|
20
|
+
|
21
|
+
# ---------------------------------------------------------------------------
|
22
|
+
# Check credentials
|
23
|
+
post "/session/create" do
|
24
|
+
if authenticate( params[:login] )
|
25
|
+
session[:user] = params[:login][:username]
|
26
|
+
redirect '/mission'
|
27
|
+
else
|
28
|
+
flash_it!( :error, "Authentication failed! Please check credentials." )
|
29
|
+
redirect '/'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/controllers/users.rb
CHANGED
@@ -23,8 +23,9 @@ module Users
|
|
23
23
|
@filter.search_terms = params[:search_filter][:search_terms]
|
24
24
|
@users = Wackamole::User.paginate_tops( @filter.to_conds )
|
25
25
|
rescue => boom
|
26
|
-
|
27
|
-
|
26
|
+
puts boom
|
27
|
+
@filter.search_terms = nil
|
28
|
+
flash_it!( :error, boom )
|
28
29
|
@users = [].paginate
|
29
30
|
end
|
30
31
|
|
data/lib/helpers/flash_helper.rb
CHANGED
@@ -2,15 +2,18 @@ module FlashHelper
|
|
2
2
|
helpers do
|
3
3
|
|
4
4
|
# clear out flash object
|
5
|
-
def
|
5
|
+
def clear_flash!
|
6
6
|
@flash = session[:flash] || OrderedHash.new
|
7
7
|
@flash.clear
|
8
|
+
session[:flash] = @flash
|
8
9
|
end
|
9
10
|
|
10
11
|
# add flash message
|
11
12
|
def flash_it!( type, msg )
|
12
13
|
@flash = session[:flash] || OrderedHash.new
|
13
14
|
@flash[type] = msg
|
15
|
+
session[:flash] = @flash
|
16
|
+
puts @flash.inspect
|
14
17
|
end
|
15
18
|
end
|
16
19
|
end
|
data/lib/helpers/logs_helper.rb
CHANGED
@@ -79,7 +79,8 @@ module LogsHelper
|
|
79
79
|
|
80
80
|
# ---------------------------------------------------------------------------
|
81
81
|
# Trim out extra host info if any
|
82
|
-
def format_host( host )
|
82
|
+
def format_host( host )
|
83
|
+
return "n/a" unless host or host.empty?
|
83
84
|
return host.split( "." ).first if host.index( /\./ )
|
84
85
|
host
|
85
86
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module SessionHelper
|
2
|
+
helpers do
|
3
|
+
|
4
|
+
# Check credentials against config file
|
5
|
+
def authenticate( creds )
|
6
|
+
env = Sinatra::Application.environment.to_s
|
7
|
+
config = YAML.load_file( default_config )
|
8
|
+
conf = config[env]
|
9
|
+
((creds['username'] == conf['auth']['user']) and (creds['password'] == conf['auth']['password']))
|
10
|
+
end
|
11
|
+
|
12
|
+
def console_auth?
|
13
|
+
env = Sinatra::Application.environment.to_s
|
14
|
+
config = YAML.load_file( default_config )
|
15
|
+
conf = config[env]
|
16
|
+
conf['auth']
|
17
|
+
end
|
18
|
+
|
19
|
+
# Check if session has auth
|
20
|
+
def authenticated?
|
21
|
+
session[:user]
|
22
|
+
end
|
23
|
+
|
24
|
+
# check for login path
|
25
|
+
def root_path?
|
26
|
+
request.path == "/"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|