wackamole 0.0.8 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|