nutcracker-web 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +10 -0
  3. data/Gemfile.lock +63 -0
  4. data/README.md +56 -0
  5. data/Rakefile +26 -0
  6. data/assets/javascripts/application.js +10 -0
  7. data/assets/javascripts/collections/clusters.js.coffee +4 -0
  8. data/assets/javascripts/collections/nodes.js.coffee +19 -0
  9. data/assets/javascripts/models/cluster.js.coffee +16 -0
  10. data/assets/javascripts/models/node.js.coffee +14 -0
  11. data/assets/javascripts/models/overview.js.coffee +27 -0
  12. data/assets/javascripts/nutcracker.js.coffee +20 -0
  13. data/assets/javascripts/routers/nutcracker_router.js.coffee +29 -0
  14. data/assets/javascripts/utils/region_manager.js.coffee +12 -0
  15. data/assets/javascripts/utils/underscore_ext.js.coffee +6 -0
  16. data/assets/javascripts/vendor/backbone.js +1571 -0
  17. data/assets/javascripts/vendor/bootstrap.js +2276 -0
  18. data/assets/javascripts/vendor/google_chart.js.coffee +124 -0
  19. data/assets/javascripts/vendor/humanize.js +459 -0
  20. data/assets/javascripts/vendor/jquery.js +8842 -0
  21. data/assets/javascripts/vendor/underscore.js +1227 -0
  22. data/assets/javascripts/views/cluster.js.coffee +58 -0
  23. data/assets/javascripts/views/config.js.coffee +6 -0
  24. data/assets/javascripts/views/footer.js.coffee +8 -0
  25. data/assets/javascripts/views/navbar.js.coffee +28 -0
  26. data/assets/javascripts/views/node.js.coffee +54 -0
  27. data/assets/javascripts/views/overview.js.coffee +6 -0
  28. data/assets/stylesheets/application.css +24 -0
  29. data/assets/stylesheets/bootstrap-responsive.css +1109 -0
  30. data/assets/stylesheets/bootstrap.css +6158 -0
  31. data/assets/templates/cluster.jst.eco +87 -0
  32. data/assets/templates/config.jst.eco +15 -0
  33. data/assets/templates/footer.jst.eco +1 -0
  34. data/assets/templates/navbar.jst.eco +55 -0
  35. data/assets/templates/node.jst.eco +73 -0
  36. data/assets/templates/overview.jst.eco +32 -0
  37. data/lib/nutcracker/web/app.rb +51 -0
  38. data/lib/nutcracker/web/version.rb +5 -0
  39. data/lib/nutcracker/web.rb +29 -0
  40. metadata +122 -0
@@ -0,0 +1,87 @@
1
+ <h3 align=center> <%= @model.get("name") %> </h3>
2
+
3
+ <ul class="pager fixed">
4
+ <%if @prevCluster: %>
5
+ <li class="previous nosel"><a class="nextPrevButton" href="<%= @prevCluster?.get("routeURL")%>">&larr; Prev</a></li>
6
+ <% else: %>
7
+ <li class="previous disabled nosel"><a>&larr; Prev</a></li>
8
+ <%end%>
9
+
10
+ <%if @nextCluster: %>
11
+ <li class="next nosel"><a class="nextPrevButton" href="<%= @nextCluster?.get("routeURL")%>">Next &rarr;</a></li>
12
+ <% else: %>
13
+ <li class="next disabled nosel"><a>Next &rarr;</a></li>
14
+ <%end%>
15
+ </li>
16
+ </ul>
17
+
18
+
19
+ </br>
20
+ <table class="table table-striped table-bordered">
21
+ <tr>
22
+ <th>Client Connections</th>
23
+ <th>Client EOF</th>
24
+ <th>Client Errors</th>
25
+ <th>Forward Errors</th>
26
+ <th>Fragments</th>
27
+ <th>Server Ejects</th>
28
+ </tr>
29
+ <tr>
30
+ <td><%= @model.get('client_connections')%></td>
31
+ <td><%= @model.get('client_eof')%></td>
32
+ <td><%= @model.get('client_err')%></td>
33
+ <td><%= @model.get('forward_error')%></td>
34
+ <td><%= @model.get('fragments')%></td>
35
+ <td><%= @model.get('server_ejects')%></td>
36
+ </tr>
37
+
38
+ </table>
39
+
40
+ </br>
41
+ <div class="chartsBox">
42
+ <div class="row">
43
+ <div class="span5">
44
+ <div id="chart1" style="padding-left: 23%"></div>
45
+ </div>
46
+ <div class="span5">
47
+ <div id="chart2" style="padding-left: 40%"></div>
48
+ </div>
49
+ </div>
50
+ </div>
51
+
52
+
53
+ </br>
54
+ <table class="table table-striped table-bordered">
55
+ <thead>
56
+ <tr>
57
+ <th>Host</th>
58
+ <th>Used Memory</th>
59
+ <th>Free Memory</th>
60
+ <th>Used Memory RSS</th>
61
+ <th>Max Memory</th>
62
+ <th>Fragmentation</th>
63
+ </tr>
64
+ </thead>
65
+ <tbody>
66
+ <% for node in @model.get("nodes").models: %>
67
+ <tr>
68
+ <td><a href="<%=node.get("routeURL")%>"><%=node.get("hostname")%></a></td>
69
+ <td><%=humanize.filesize node.get("usedMemory")%></td>
70
+ <td><%=humanize.filesize node.get("freeMemory")%></td>
71
+ <td><%=humanize.filesize node.get("usedMemoryRss")%></td>
72
+ <td><%=humanize.filesize node.get("maxMemory")%></td>
73
+ <td><%=node.get("fragmentation")%></td>
74
+ </tr>
75
+ <% end %>
76
+ <tr>
77
+ <td>&nbsp;</td>
78
+ <td><%=humanize.filesize _(@model.get("nodes").pluck("usedMemory")).sum()%></td>
79
+ <td><%=humanize.filesize _(@model.get("nodes").pluck("freeMemory")).sum()%></td>
80
+ <td><%=humanize.filesize _(@model.get("nodes").pluck("usedMemoryRss")).sum()%></td>
81
+ <td><%=humanize.filesize _(@model.get("nodes").pluck("maxMemory")).sum()%></td>
82
+ <td>~<%=humanize.numberFormat(_(@model.get("nodes").pluck("fragmentation")).average(),2)%></td>
83
+ </tr>
84
+ </tbody>
85
+ </table>
86
+
87
+
@@ -0,0 +1,15 @@
1
+
2
+ <h3> Clusters </h3>
3
+ <br/>
4
+ <% for conf in _(@model.get("config")).map( (v,k)->[k,v]): %>
5
+ <table class="table table-striped table-bordered">
6
+ <tr><th>Name</th><td><%-"<a href=#{Nutcracker.Models.Cluster.routeURL conf[0]}>#{conf[0]}</a>"%></td></tr>
7
+ <tr><th>Servers</th><td><%-conf[1].servers.map((s)->"<a href=#{Nutcracker.Models.Node.routeURL(s)}>#{s}</a>").join("<br/>")%></td></tr>
8
+ <% for array in _(conf[1]).map((v,k)->[k,v]): %>
9
+ <%if not /servers/.test array[0]:%>
10
+ <tr><th><%=array[0]%></th><td><%=array[1]%></td></tr>
11
+ <% end %>
12
+ <% end %>
13
+ </table>
14
+ </br>
15
+ <% end %>
@@ -0,0 +1 @@
1
+ Last Update <%=humanize.relativeTime(@model.get('timestamp'))%>
@@ -0,0 +1,55 @@
1
+ <div class="navbar">
2
+ <div class="navbar-inner">
3
+ <div class="container" style="font-size: 17px">
4
+ <a class="btn btn-navbar" data-toggle="collapse" data-target=".navbar-responsive-collapse">
5
+ <span class="icon-bar"></span>
6
+ <span class="icon-bar"></span>
7
+ <span class="icon-bar"></span>
8
+ </a>
9
+ <a class="brand" href="#" style="color: #ffffff;font-size: 25px">Nutcracker</a>
10
+ <div class="nav-collapse collapse navbar-responsive-collapse">
11
+ <ul class="nav">
12
+ <li class="divider-vertical"></li>
13
+ <li id="overview" ><a href="#/">Overview</a></li>
14
+ <li class="divider-vertical"></li>
15
+ <li id="config" ><a href="#/config">Config </a></li>
16
+ <li class="divider-vertical"></li>
17
+ <li id="clusters" class="dropdown">
18
+ <a class="dropdown-toggle" id="drop4" style="padding-top: 12px;" role="button" data-toggle="dropdown" href="#">Clusters <b class="caret"></b></a>
19
+ <ul id="menu1" class="dropdown-menu" role="menu" aria-labelledby="drop4">
20
+ <li class='divider'></li>
21
+ <% for cluster in @model.get("clusters").models: %>
22
+ <li role="presentation" style="font-size: 15px">
23
+ <a role="menuitem" tabindex="-1" href="<%=cluster.get('routeURL')%>"><%=cluster.get('name')%></a>
24
+ </li>
25
+ <li class='divider'></li>
26
+ <% end %>
27
+ </ul>
28
+ </li>
29
+
30
+ <li class="divider-vertical"></li>
31
+ <li id="nodes" class="dropdown">
32
+ <a class="dropdown-toggle" id="drop5" style="padding-top: 12px;" role="button" data-toggle="dropdown" href="#">Nodes <b class="caret"></b></a>
33
+ <ul id="menu1" class="dropdown-menu" role="menu" aria-labelledby="drop5">
34
+ <li class='divider'></li>
35
+ <% for node in @model.nodes().models: %>
36
+ <li role="presentation" style="font-size: 15px">
37
+ <a role="menuitem" tabindex="-1" href="<%=node.get("routeURL")%>"><%=node.get("hostname")%></a>
38
+ </li>
39
+ <li class='divider'></li>
40
+ <% end %>
41
+ </ul>
42
+ </li>
43
+
44
+ <li class="divider-vertical"></li>
45
+ </ul>
46
+
47
+ <ul class="nav pull-right">
48
+ <li class="divider-vertical"></li>
49
+ <li class="no-hl"><a>Version <%=@model.get("version")%></a></li>
50
+ <li class="divider-vertical"></li>
51
+ </ul>
52
+ </div><!-- /.nav-collapse -->
53
+ </div>
54
+ </div><!-- /navbar-inner -->
55
+ </div><!-- /navbar -->
@@ -0,0 +1,73 @@
1
+ <h3 align=center><%= @model.get("hostname") %></h3>
2
+
3
+ <ul class="pager">
4
+ <%if @prevNode: %>
5
+ <li class="previous nosel"><a class="nextPrevButton" href="<%= @prevNode?.get("routeURL")%>">&larr; Prev</a></li>
6
+ <% else: %>
7
+ <li class="previous disabled nosel"><a>&larr; Prev</a></li>
8
+ <%end%>
9
+
10
+ <% for cluster in @model.get("clusters"): %>
11
+ <li class="nosel"><a class="nextPrevButton" href="<%= cluster.get('routeURL')%>"><%=cluster.get('name')%></a></li>
12
+ <% end %>
13
+
14
+ <%if @nextNode: %>
15
+ <li class="next nosel"><a class="nextPrevButton" href="<%= @nextNode?.get("routeURL")%>">Next &rarr;</a></li>
16
+ <% else: %>
17
+ <li class="next disabled nosel"><a>Next &rarr;</a></li>
18
+ <%end%>
19
+ </li>
20
+ </ul>
21
+ </br>
22
+ <div class="chartsBox">
23
+ <div class="row">
24
+ <div class="span5">
25
+ <div id="chart1" style="padding-left: 26%"></div>
26
+ </div>
27
+ <div class="span5">
28
+ <div id="chart2" style="padding-left: 40%"></div>
29
+ </div>
30
+ </div>
31
+ </div>
32
+
33
+ <br/>
34
+ <div class="row-fluid">
35
+ <div class="span6">
36
+ <h4> Cluster <-> Node Stats </h4>
37
+ <table class="table table-striped table-bordered">
38
+ <tr><th>In-Queue</th><td> <%= @model.get "in_queue" %></td></tr>
39
+ <tr><th>In-Queue Memory Size</th><td> <%= humanize.filesize(@model.get "in_queue_bytes") %></td></tr>
40
+ <tr><th>Out-Queue</th><td> <%= @model.get "out_queue" %></td></tr>
41
+ <tr><th>Out-Queue Memory Size</th><td> <%= humanize.filesize(@model.get "out_queue_bytes") %></td></tr>
42
+ <tr><th>Requests</th><td> <%= @model.get "requests" %></td></tr>
43
+ <tr><th>Requests Memory Size</th><td> <%= humanize.filesize(@model.get "request_bytes") %></td></tr>
44
+ <tr><th>Responses</th><td> <%= @model.get "responses" %></td></tr>
45
+ <tr><th>Responses Memory Size</th><td> <%= humanize.filesize(@model.get "response_bytes") %></td></tr>
46
+ <tr><th>Server Connections</th><td> <%= @model.get "server_connections" %></td></tr>
47
+ <tr><th>Server EOF</th><td> <%= @model.get "server_eof" %></td></tr>
48
+ <tr><th>Server Error</th><td> <%= @model.get "server_err" %></td></tr>
49
+ <tr><th>Server Timedout</th><td> <%= @model.get "server_timedout" %></td></tr>
50
+ </table>
51
+ </div>
52
+
53
+ <div class="span6">
54
+ <h4>Node Stats</h3>
55
+ <table class="table table-striped table-bordered">
56
+ <tr><th>Hits</th><td> <%= humanize.numberFormat @model.get("info").hits, 0 %></td></tr>
57
+ <tr><th>Misses</th><td> <%= humanize.numberFormat @model.get("info").misses, 0 %></td></tr>
58
+ <tr><th>Hit Ratio</th><td> <%= humanize.numberFormat @model.get("info").hit_ratio, 2 %></td></tr>
59
+ <tr><th>Max Memory</th><td> <%= humanize.filesize @model.get("info").max_memory %></td></tr>
60
+ <tr><th>Used Memory</th><td> <%= humanize.filesize @model.get("info").used_memory %></td></tr>
61
+ <tr><th>Used Memory RSS</th><td> <%= humanize.filesize @model.get("info").used_memory_rss %></td></tr>
62
+ <tr><th>Connections</th><td> <%= @model.get("info").connections %></td></tr>
63
+ <tr><th>Keys</th><td> <%= humanize.numberFormat @model.get("info").keys , 0%></td></tr>
64
+ <tr><th>Evicted Keys</th><td> <%= humanize.numberFormat @model.get("info").evicted_keys, 0 %></td></tr>
65
+ <tr><th>Expired Keys</th><td> <%= humanize.numberFormat @model.get("info").expired_keys, 0 %></td></tr>
66
+ <tr><th>Fragmentation</th><td> <%= humanize.numberFormat @model.get("info").fragmentation, 2 %></td></tr>
67
+ <tr><th>&nbsp;</th><td> &nbsp;</td></tr>
68
+ </table>
69
+ </div>
70
+
71
+ </div>
72
+
73
+
@@ -0,0 +1,32 @@
1
+ <h3> Overview </h3>
2
+ <br/>
3
+ <table class="table table-striped table-bordered">
4
+ <tbody>
5
+ <tr><th>Hostname</th><td><%=@model.get("source")%></td></tr>
6
+ <tr><th>Service</th><td>Nutcracker Ver. <%=@model.get("version")%></td></tr>
7
+ <tr><th>Uptime</th><td><%=humanize.relativeTime(((new Date())-@model.get("uptime")*1000)/1000)%></td></tr>
8
+ <tr><th>Server Connections</th><td><%=@model.get("serverConnections")%></td></tr>
9
+ <tr><th>Client Connections</th><td><%=@model.get("clientConnections")%></td></tr>
10
+
11
+ <tr>
12
+ <th>Total Clusters</th>
13
+ <td>
14
+ <% for cluster in @model.get("clusters").models: %>
15
+ <a href="<%=cluster.get("routeURL")%>"><%=cluster.get("name")%></a><br/>
16
+ <%end%>
17
+ </td>
18
+ </tr>
19
+
20
+ <tr>
21
+ <th>Total Nodes</th>
22
+ <td>
23
+ <% for node in @model.nodes().models: %>
24
+ <a href="<%=node.get('routeURL')%>"><%=node.get('hostname')%></a><br/>
25
+ <%end%>
26
+ </td>
27
+ </tr>
28
+
29
+
30
+ </tbody>
31
+ </table>
32
+
@@ -0,0 +1,51 @@
1
+ require 'haml'
2
+ require 'sinatra'
3
+ require 'eco'
4
+ require 'sprockets'
5
+ require 'json'
6
+
7
+ module Nutcracker
8
+ module Web
9
+ class App < Sinatra::Base
10
+ enable :inline_templates
11
+ set :root, File.expand_path('../'*4,__FILE__)
12
+ set :assets, Sprockets::Environment.new { |env|
13
+ %w(javascripts stylesheets templates).each { |asset|
14
+ env.append_path File.join(settings.root,"assets/#{asset}")
15
+ }
16
+ }
17
+
18
+ get '/' do
19
+ haml :index
20
+ end
21
+
22
+ def overview
23
+ Thread.current[:nutcracker].overview rescue
24
+ JSON.parse File.read File.join(settings.root,"example.json")
25
+ end
26
+
27
+ end
28
+ end
29
+ end
30
+
31
+ __END__
32
+
33
+ @@ layout
34
+ %html
35
+ %head
36
+ %title Nutcracker-Web
37
+ %script(type='text/javascript' src='http://www.google.com/jsapi')
38
+ %script(type='text/javascript' src='assets/application.js')
39
+ %link(rel='stylesheet' href='assets/application.css')
40
+ %link(rel="shortcut icon" href="http://publishers.kontera.com/favicon.ico")
41
+ %body
42
+ = yield
43
+
44
+ @@ index
45
+ #navbar
46
+ .container
47
+ #container{ "data-clusters" => overview.to_json }
48
+ loading...
49
+ #footer
50
+ - 3.times do
51
+ %br
@@ -0,0 +1,5 @@
1
+ module Nutcracker
2
+ module Web
3
+ VERSION="0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,29 @@
1
+ require "rack"
2
+
3
+ module Nutcracker
4
+ module Web
5
+ def self.start nutcracker, options
6
+ @thread = Thread.new do
7
+ Thread.current.abort_on_exception=true
8
+ Thread.current[:nutcracker] = nutcracker
9
+ Rack::Server.start(
10
+ {
11
+ :environment => 'development',
12
+ :pid => nil,
13
+ :Port => 9393,
14
+ :Host => '0.0.0.0',
15
+ :AccessLog => [],
16
+ :config => File.expand_path("../../../config.ru", __FILE__)
17
+ }.merge( options )
18
+ )
19
+ end
20
+ self
21
+ end
22
+
23
+ def self.stop
24
+ @thread.kill
25
+ end
26
+
27
+ autoload :App, 'nutcracker/web/app'
28
+ end
29
+ end
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nutcracker-web
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Eran Barak Levi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-07-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: minitest
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 5.0.0
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 5.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: mocha
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 0.14.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 0.14.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: nutcracker
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 0.2.4.5
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 0.2.4.5
55
+ description: Web interface for Nutcracker cluster
56
+ email: eran@kontera.com
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - README.md
62
+ - Rakefile
63
+ - Gemfile
64
+ - Gemfile.lock
65
+ - lib/nutcracker/web/app.rb
66
+ - lib/nutcracker/web/version.rb
67
+ - lib/nutcracker/web.rb
68
+ - assets/javascripts/application.js
69
+ - assets/javascripts/collections/clusters.js.coffee
70
+ - assets/javascripts/collections/nodes.js.coffee
71
+ - assets/javascripts/models/cluster.js.coffee
72
+ - assets/javascripts/models/node.js.coffee
73
+ - assets/javascripts/models/overview.js.coffee
74
+ - assets/javascripts/nutcracker.js.coffee
75
+ - assets/javascripts/routers/nutcracker_router.js.coffee
76
+ - assets/javascripts/utils/region_manager.js.coffee
77
+ - assets/javascripts/utils/underscore_ext.js.coffee
78
+ - assets/javascripts/vendor/backbone.js
79
+ - assets/javascripts/vendor/bootstrap.js
80
+ - assets/javascripts/vendor/google_chart.js.coffee
81
+ - assets/javascripts/vendor/humanize.js
82
+ - assets/javascripts/vendor/jquery.js
83
+ - assets/javascripts/vendor/underscore.js
84
+ - assets/javascripts/views/cluster.js.coffee
85
+ - assets/javascripts/views/config.js.coffee
86
+ - assets/javascripts/views/footer.js.coffee
87
+ - assets/javascripts/views/navbar.js.coffee
88
+ - assets/javascripts/views/node.js.coffee
89
+ - assets/javascripts/views/overview.js.coffee
90
+ - assets/stylesheets/application.css
91
+ - assets/stylesheets/bootstrap-responsive.css
92
+ - assets/stylesheets/bootstrap.css
93
+ - assets/templates/cluster.jst.eco
94
+ - assets/templates/config.jst.eco
95
+ - assets/templates/footer.jst.eco
96
+ - assets/templates/navbar.jst.eco
97
+ - assets/templates/node.jst.eco
98
+ - assets/templates/overview.jst.eco
99
+ homepage: http://www.kontera.com
100
+ licenses: []
101
+ metadata: {}
102
+ post_install_message:
103
+ rdoc_options: []
104
+ require_paths:
105
+ - lib
106
+ required_ruby_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: 1.9.1
111
+ required_rubygems_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - '>='
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ requirements: []
117
+ rubyforge_project: ruby-nutcracker-web
118
+ rubygems_version: 2.0.3
119
+ signing_key:
120
+ specification_version: 4
121
+ summary: Nutcracker Web Interface
122
+ test_files: []