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.
Files changed (52) hide show
  1. data/History.txt +5 -1
  2. data/README.rdoc +12 -3
  3. data/bin/wackamole +2 -2
  4. data/data/fixtures.rb +132 -0
  5. data/features/env.rb +29 -0
  6. data/features/mission.feature +10 -0
  7. data/features/step_definitions/mission_steps.rb +5 -0
  8. data/lib/app.rb +23 -7
  9. data/lib/controllers/features.rb +3 -2
  10. data/lib/controllers/logs.rb +1 -0
  11. data/lib/controllers/mission.rb +14 -4
  12. data/lib/controllers/session.rb +32 -0
  13. data/lib/controllers/users.rb +3 -2
  14. data/lib/helpers/flash_helper.rb +4 -1
  15. data/lib/helpers/logs_helper.rb +2 -1
  16. data/lib/helpers/session_helper.rb +29 -0
  17. data/lib/wackamole.rb +1 -1
  18. data/lib/wackamole/models/control.rb +15 -1
  19. data/lib/wackamole/models/feature.rb +11 -2
  20. data/lib/wackamole/models/log.rb +1 -0
  21. data/lib/wackamole/models/mission.rb +9 -7
  22. data/lib/wackamole/models/mole_info.rb +8 -4
  23. data/lib/wackamole/models/search_filter.rb +48 -15
  24. data/lib/wackamole/models/user.rb +12 -1
  25. data/public/stylesheets/wackamole.css +60 -3
  26. data/spec/config/bogus_test.yml +1 -1
  27. data/spec/config/test.yml +1 -1
  28. data/spec/spec_helper.rb +3 -0
  29. data/spec/ui/log_spec.rb +68 -0
  30. data/spec/ui/mission_spec.rb +64 -0
  31. data/spec/ui/session_spec.rb +39 -0
  32. data/spec/ui_utils/mission_util.rb +41 -0
  33. data/spec/{models → wackamole/models}/control_spec.rb +21 -21
  34. data/spec/{models → wackamole/models}/feature_spec.rb +7 -7
  35. data/spec/{models → wackamole/models}/log_spec.rb +5 -5
  36. data/spec/{models → wackamole/models}/mission_spec.rb +11 -7
  37. data/spec/wackamole/models/moled_info_spec.rb +36 -0
  38. data/spec/{models → wackamole/models}/search_filter_spec.rb +12 -16
  39. data/spec/{models → wackamole/models}/user_spec.rb +5 -5
  40. data/spec/{wackamole_spec.rb → wackamole/wackamole_spec.rb} +2 -2
  41. data/tasks/fixtures.rake +3 -1
  42. data/tasks/setup.rb +2 -1
  43. data/tasks/spec.rake +17 -3
  44. data/views/dashboard/_report.erb +3 -3
  45. data/views/layout.erb +44 -11
  46. data/views/logs/show.erb +3 -0
  47. data/views/mission/_report.erb +2 -2
  48. data/views/session/login.erb +28 -0
  49. data/views/shared/_search.erb +1 -1
  50. data/views/users/index.js.erb +1 -1
  51. metadata +22 -10
  52. data/spec/models/moled_info_spec.rb +0 -30
@@ -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
@@ -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
- host: localhost
55
- port: 27017
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
@@ -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..."
@@ -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
@@ -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
@@ -0,0 +1,5 @@
1
+ Given /^I have applications named (.+)$/ do |apps|
2
+ apps.split( ', ' ).each do |app|
3
+
4
+ end
5
+ end
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
- set :logging, true
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
- :server => "%s:%d/%s/%s" % ['localhost', '27017', 'wackamole_ses', 'sessions'],
47
- :log_level => :error
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
@@ -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
- logger.error boom
26
- flash[:error] = boom
25
+ puts boom
26
+ flash_it!( :error, boom )
27
+ @filter.search_terms = nil
27
28
  @features = [].paginate
28
29
  end
29
30
 
@@ -22,6 +22,7 @@ module Logs
22
22
  @logs = Wackamole::Log.paginate( @filter.to_conds )
23
23
  rescue => boom
24
24
  # puts boom
25
+ @filter.search_terms = nil
25
26
  flash_it!( :error, boom )
26
27
  @logs = [].paginate
27
28
  end
@@ -2,15 +2,25 @@ require 'chronic'
2
2
 
3
3
  module Mission
4
4
  # ---------------------------------------------------------------------------
5
- get '/' do
6
- # reset app info
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.utc )
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.utc )
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
@@ -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
- logger.error boom
27
- flash[:error] = boom
26
+ puts boom
27
+ @filter.search_terms = nil
28
+ flash_it!( :error, boom )
28
29
  @users = [].paginate
29
30
  end
30
31
 
@@ -2,15 +2,18 @@ module FlashHelper
2
2
  helpers do
3
3
 
4
4
  # clear out flash object
5
- def clear_it!
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
@@ -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