visage-app 0.1.8 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -8,7 +8,7 @@ body {
8
8
  padding: 0;
9
9
  }
10
10
 
11
- a {
11
+ a {
12
12
  text-decoration: none;
13
13
  }
14
14
 
@@ -24,33 +24,168 @@ p {
24
24
  margin: 0 0 1em;
25
25
  }
26
26
 
27
- li {
28
- margin: 0.55em 0 0.55em 1em;
29
- list-style-type: none;
30
- }
31
-
32
27
  body {
33
28
  font-family: Bitstream Vera Serif, Baskerville, Garamond, serif;
34
29
  font-size: 1.2em;
35
30
  }
36
31
 
37
32
  div#header {
33
+ height: 40px;
34
+ background-color: #3465a4;
35
+ margin-bottom: 16px;
36
+ border-bottom: 6px solid #c5d6ed;
37
+ }
38
+
39
+ div#nav {
40
+ padding-top: 10px;
41
+ color: white;
42
+ font-family: sans-serif;
43
+ text-align: right;
44
+ font-size: 16px;
45
+ }
46
+
47
+ div#nav a {
48
+ margin-top: 8px;
49
+ margin-left: 12px;
50
+ color: white;
51
+ font-weight: bold;
52
+ }
53
+
54
+ div#nav a:hover {
55
+ text-shadow: 0 1px 6px rgba(115,157,211,0.9);
56
+ background-color: #3465a4;
57
+ }
58
+
59
+ div#content, div#nav {
60
+ width: 950px;
61
+ margin: auto;
62
+ }
63
+
64
+ div#hosts {
65
+ clear: left;
66
+ }
67
+
68
+ div#profile-meta, div#profile-preview {
38
69
  float: left;
70
+ margin-left: 25px;
71
+ width: 450px;
72
+ }
73
+
74
+ div#profile-meta input.text {
75
+ border: 1px solid #bbb;
76
+ font-size: 16px;
77
+ padding: 4px;
39
78
  width: 20em;
79
+ -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
80
+ -webkit-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.25);
40
81
  }
41
82
 
42
- div.nav {
83
+ div#profile-meta input.create.profile {
84
+ -moz-box-shadow: 0 1px 3px rgba(0,0,0,0.5);
85
+ -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.5);
86
+ -moz-border-radius: 5px;
87
+ -webkit-border-radius: 5px;
88
+ text-shadow: 0 -1px 1px rgba(0,0,0,0.25);
89
+ background: #888;
90
+ color: white;
91
+ padding: 5px 10px 6px;
92
+ text-shadow: 0 -1px 1px rgba(0,0,0,0.25);
93
+ border-bottom: 1px solid rgba(0,0,0,0.25);
94
+ position: relative;
95
+ cursor: pointer;
96
+ font-weight: bold;
97
+ background-image: -webkit-gradient(
98
+ linear,
99
+ left bottom,
100
+ left top,
101
+ color-stop(0.1, rgb(136,136,136)),
102
+ color-stop(0.5, rgb(153,153,153))
103
+ );
104
+ background-image: -moz-linear-gradient(
105
+ center bottom,
106
+ rgb(136,136,136) 10%,
107
+ rgb(153,153,153) 50%
108
+ );
109
+ }
110
+
111
+ p.error {
112
+ color: red;
113
+ font-size: 80%;
114
+ }
115
+
116
+ div.builder {
43
117
  float: left;
44
- margin: 1em;
45
- margin-right: 2em;
118
+ margin-left: 25px;
119
+ width: 450px;
120
+ margin-bottom: 24px;
46
121
  }
47
122
 
48
- div.nav li {
49
- margin-left: 2px;
123
+ div.builder input.text {
124
+ border: 1px solid #bbb;
125
+ font-size: 16px;
126
+ padding: 4px;
127
+ width: 20em;
128
+ -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
129
+ -webkit-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.25);
50
130
  }
51
131
 
52
- div#header {
53
- margin: 1em 0.5em;
132
+ div.builder input.text:focus {
133
+ border: 1px solid #666;
134
+ }
135
+
136
+ div.builder input.submit {
137
+ opacity: 0;
138
+ }
139
+
140
+ div.builder ul {
141
+ margin-top: 16px;
142
+ }
143
+
144
+ div.builder img.icon {
145
+ float: right;
146
+ }
147
+
148
+ div.builder li {
149
+ list-style-type: none;
150
+ padding: 4px 8px;
151
+ }
152
+
153
+ div.builder h5 {
154
+ margin-top: 8px;
155
+ margin-left: 8px;
156
+ }
157
+
158
+ div.builder ul.available {
159
+ margin-top: 4px;
160
+ }
161
+
162
+ div.builder ul.selected {
163
+ background-color: #fffaba;
164
+ }
165
+
166
+ div.builder li:hover {
167
+ /*background-color: #fffaba;*/
168
+ }
169
+
170
+ div.builder li td {
171
+ padding: 4px;
172
+ }
173
+
174
+ div.builder li td.name {
175
+ width: 350px;
176
+ }
177
+
178
+ div.builder li td.meta {
179
+ width: 80px;
180
+ text-align: right;
181
+ padding-right: 8px;
182
+ }
183
+
184
+ span.glob.example {
185
+ display: block;
186
+ font-size: 80%;
187
+ font-style: italic;
188
+ margin-top: 8px;
54
189
  }
55
190
 
56
191
  div#graphs {
@@ -69,8 +204,11 @@ h1, h2, h3, h4, h5 {
69
204
  font-family: Bitstream Vera Sans, Helvetica Neue, sans-serif;
70
205
  }
71
206
 
72
- h2, h3, h4, h5 {
73
- /*text-transform: uppercase;*/
207
+ h2 {
208
+ font-weight: bold;
209
+ color: #666;
210
+ border-bottom: 4px solid #888;
211
+ margin-bottom: 12px;
74
212
  }
75
213
 
76
214
  h1 {
@@ -94,3 +232,22 @@ div#nothing {
94
232
  margin-top: 1em;
95
233
  }
96
234
 
235
+
236
+ div#profiles {
237
+ float: left;
238
+ margin-left: 25px;
239
+ width: 450px;
240
+ }
241
+
242
+ div#profiles ul li {
243
+ margin-bottom: 8px;
244
+ list-style-type: none;
245
+ }
246
+
247
+ div#profiles ul {
248
+ margin-bottom: 16px;
249
+ }
250
+
251
+ div#profiles p.create {
252
+ font-size: 85%;
253
+ }
@@ -0,0 +1,52 @@
1
+ - page_title "Profile builder"
2
+
3
+ %div#builder
4
+ %form{:action => "/builder", :method => :get}
5
+
6
+ - if @profile.selected_hosts.size > 0 && @profile.selected_metrics.size > 0
7
+ %div#profile-preview
8
+ %h2 Preview
9
+ %div#graph
10
+ %p Coming soon!
11
+ %div#profile-meta
12
+ %h2 Profile name
13
+ %p
14
+ %input{:name => "profile_name", :value => params[:profile_name], :type => "text", :class => "text"}
15
+ %p.error
16
+ = @profile.errors[:profile_name]
17
+ %p
18
+ %input{:type => "submit", :value => "create", :class => "create", :name => "submit"}
19
+
20
+ %div#hosts.builder
21
+ %h2 Hosts
22
+ %input{:name => "hosts", :type => "text", :class => "text", :value => params[:hosts]}
23
+ %input{:name => "submit", :type => "submit", :class => "submit", :value => "hosts"}
24
+ %img{:src => link_to("/images/hosts.png"), :class => "icon hosts"}
25
+ %span{:class => "glob example"} e.g. “charlie”, “*.bravo*”, “echo, foxtrot*”
26
+
27
+ %ul.selected
28
+ - @profile.selected_hosts.each do |name|
29
+ %li= name
30
+
31
+ %h5 Available
32
+ %ul.available
33
+ - @profile.hosts.each do |name|
34
+ %li= name
35
+
36
+ %div#metrics.builder
37
+ %h2 Metrics
38
+ %input{:name => "metrics", :type => "text", :class => "text", :value => params[:metrics]}
39
+ %input{:name => "submit", :type => "submit", :class => "submit", :value => "metrics"}
40
+ %img{:src => link_to("/images/metrics.png"), :class => "icon metrics"}
41
+ %span{:class => "glob example"} e.g. “cpu*/*”, “disk*/*ops, disk*/*time”
42
+
43
+ %ul.selected
44
+ - @profile.selected_metrics.each do |name|
45
+ %li= name
46
+
47
+ %h5 Available
48
+ %ul.available
49
+ - @profile.metrics.each do |name|
50
+ %li= name
51
+
52
+
@@ -1,22 +1,24 @@
1
- !!!
1
+ !!!
2
2
  %html
3
3
  %head
4
- %title Visage
4
+ %title= include_page_title
5
5
  %link{:rel => "icon", :type => "image/gif", :href => "/favicon.gif"}
6
6
  %link{:rel => 'stylesheet', :href => '/stylesheets/screen.css', :type => 'text/css'}
7
- %script{:type => "text/javascript", :src => "/javascripts/raphael-min.js"}
8
- %script{:type => "text/javascript", :src => "/javascripts/g.raphael.js"}
9
- %script{:type => "text/javascript", :src => "/javascripts/g.line.js"}
10
- %script{:type => "text/javascript", :src => "/javascripts/mootools-1.2.3-core.js"}
11
- %script{:type => "text/javascript", :src => "/javascripts/mootools-1.2.3.1-more.js"}
12
- %script{:type => "text/javascript", :src => "/javascripts/graph.js"}
13
- %script{:type => "text/javascript", :src => "/javascripts/application.js"}
7
+ %script{:type => "text/javascript", :src => link_to("/javascripts/raphael.js")}
8
+ %script{:type => "text/javascript", :src => link_to("/javascripts/g.raphael.js")}
9
+ %script{:type => "text/javascript", :src => link_to("/javascripts/g.line.js")}
10
+ %script{:type => "text/javascript", :src => link_to("/javascripts/mootools-1.2.3-core.js")}
11
+ %script{:type => "text/javascript", :src => link_to("/javascripts/mootools-1.2.3.1-more.js")}
12
+ %script{:type => "text/javascript", :src => link_to("/javascripts/graph.js")}
13
+ %script{:type => "text/javascript", :src => link_to("/javascripts/application.js")}
14
14
 
15
15
  %body
16
16
  %div#wrapper
17
17
  %div#header
18
- %h1.project
19
- %span.project-name Visage
18
+ %div#nav
19
+ %a{:href => link_to("/profiles")} profiles
20
+ %a{:href => link_to("/builder")} builder
21
+
20
22
  %div#content
21
23
  = yield
22
24
 
@@ -0,0 +1,18 @@
1
+ - page_title @profile.options[:profile_name]
2
+
3
+ %div#profile
4
+ - @profile.graphs.each do |graph|
5
+ %div{:id => graph.id, :class => 'graph'}
6
+ :javascript
7
+ window.addEvent('domready', function() {
8
+ var graph = new visageGraph('#{graph.id}', '#{graph.host}', '#{graph.plugin}', {
9
+ width: 900,
10
+ height: 220,
11
+ gridWidth: 800,
12
+ gridHeight: 200,
13
+ shade: false,
14
+ pluginInstance: '#{graph.instances.join(',')}',
15
+ name: '#{graph.plugin} on #{graph.host}'
16
+ });
17
+ });
18
+
@@ -0,0 +1,13 @@
1
+ - page_title 'Profiles'
2
+
3
+ %div#profiles
4
+ %h2 Profiles
5
+
6
+ %ul
7
+ - @profiles.each do |prof|
8
+ %li
9
+ %a{:href => link_to("/profiles/#{prof.url}")}= prof.profile_name
10
+
11
+ %p.create
12
+ %a{:href => link_to("/builder")} Create a new profile.
13
+
data/lib/visage-app.rb CHANGED
@@ -4,78 +4,113 @@ require 'pathname'
4
4
  @root = Pathname.new(File.dirname(__FILE__)).parent.expand_path
5
5
  $: << @root.to_s
6
6
 
7
- require 'sinatra'
8
- require 'errand'
9
- require 'yajl'
7
+ require 'sinatra/base'
10
8
  require 'haml'
9
+ require 'lib/visage/profile'
11
10
  require 'lib/visage/config'
12
11
  require 'lib/visage/helpers'
13
12
  require 'lib/visage/config/init'
13
+ require 'lib/visage/collectd/rrds'
14
14
  require 'lib/visage/collectd/json'
15
+ require 'yajl/json_gem'
15
16
 
16
- set :public, @root.join('lib/visage/public')
17
- set :views, @root.join('lib/visage/views')
17
+ module Visage
18
+ class Application < Sinatra::Base
19
+ @root = Pathname.new(File.dirname(__FILE__)).parent.expand_path
20
+ set :public, @root.join('lib/visage/public')
21
+ set :views, @root.join('lib/visage/views')
18
22
 
19
- configure do
20
- CollectdJSON.rrddir = Visage::Config.rrddir
21
- Visage::Config::Profiles.profiles = Visage::Config.profiles
22
- end
23
+ helpers Sinatra::LinkToHelper
24
+ helpers Sinatra::PageTitleHelper
25
+ end
26
+
27
+ class Profiles < Application
28
+ get '/' do
29
+ redirect '/profiles'
30
+ end
23
31
 
24
- # infrastructure for embedding
25
- get '/javascripts/visage.js' do
26
- javascript = ""
27
- %w{raphael-min g.raphael g.line mootools-1.2.3-core mootools-1.2.3.1-more graph}.each do |js|
28
- javascript += File.read(File.join(__DIR__, 'public', 'javascripts', "#{js}.js"))
32
+ get '/profiles/:url' do
33
+ @profile = Visage::Profile.get(params[:url])
34
+ raise Sinatra::NotFound unless @profile
35
+ haml :profile
36
+ end
37
+
38
+ get '/profiles' do
39
+ @profiles = Visage::Profile.all
40
+ haml :profiles
41
+ end
29
42
  end
30
- javascript
31
- end
32
43
 
33
- # user facing
34
- get '/' do
35
- @hosts = CollectdJSON.hosts
36
- haml :index
37
- end
38
44
 
39
- get '/:host' do
40
- @hosts = CollectdJSON.hosts
41
- @profiles = Visage::Config::Profiles.all
45
+ class Builder < Application
42
46
 
43
- haml :index
44
- end
47
+ get "/builder" do
48
+ if params[:submit] == "create"
49
+ @profile = Visage::Profile.new(params)
45
50
 
46
- get '/:host/:profile' do
47
- @hosts = CollectdJSON.hosts
48
- @profiles = Visage::Config::Profiles.all
49
- @profile = Visage::Config::Profiles.get(params[:profile])
51
+ if @profile.save
52
+ redirect "/profiles/#{@profile.url}"
53
+ else
54
+ haml :builder
55
+ end
56
+ else
57
+ @profile = Visage::Profile.new(params)
50
58
 
51
- haml :index
52
- end
59
+ haml :builder
60
+ end
61
+ end
53
62
 
54
- # JSON data backend
55
-
56
- # /data/:host/:plugin/:optional_plugin_instance
57
- get %r{/data/([^/]+)/([^/]+)((/[^/]+)*)} do
58
- host = params[:captures][0]
59
- plugin = params[:captures][1]
60
- plugin_instances = params[:captures][2]
61
-
62
- collectd = CollectdJSON.new(:rrddir => Visage::Config.rrddir,
63
- :fallback_colors => Visage::Config.fallback_colors)
64
- json = collectd.json(:host => host,
65
- :plugin => plugin,
66
- :plugin_instances => plugin_instances,
67
- :start => params[:start],
68
- :finish => params[:finish],
69
- :plugin_colors => Visage::Config.plugin_colors)
70
- # if the request is cross-domain, we need to serve JSONP
71
- maybe_wrap_with_callback(json)
72
- end
63
+ # infrastructure for embedding
64
+ get '/javascripts/visage.js' do
65
+ javascript = ""
66
+ %w{raphael-min g.raphael g.line mootools-1.2.3-core mootools-1.2.3.1-more graph}.each do |js|
67
+ javascript += File.read(@root.join('lib/visage/public/javascripts', "#{js}.js"))
68
+ end
69
+ javascript
70
+ end
71
+
72
+ end
73
+
74
+ class JSON < Application
75
+
76
+ # JSON data backend
77
+
78
+ # /data/:host/:plugin/:optional_plugin_instance
79
+ get %r{/data/([^/]+)/([^/]+)((/[^/]+)*)} do
80
+ host = params[:captures][0]
81
+ plugin = params[:captures][1]
82
+ plugin_instances = params[:captures][2]
83
+
84
+ collectd = CollectdJSON.new(:rrddir => Visage::Config.rrddir,
85
+ :fallback_colors => Visage::Config.fallback_colors)
86
+ json = collectd.json(:host => host,
87
+ :plugin => plugin,
88
+ :plugin_instances => plugin_instances,
89
+ :start => params[:start],
90
+ :finish => params[:finish],
91
+ :plugin_colors => Visage::Config.plugin_colors)
92
+ # if the request is cross-domain, we need to serve JSONP
93
+ maybe_wrap_with_callback(json)
94
+ end
95
+
96
+ get %r{/data/([^/]+)} do
97
+ host = params[:captures][0]
98
+ metrics = Visage::Collectd::RRDs.metrics(:host => host)
99
+
100
+ json = { host => metrics }.to_json
101
+ maybe_wrap_with_callback(json)
102
+ end
103
+
104
+ get %r{/data(/)*} do
105
+ hosts = Visage::Collectd::RRDs.hosts
106
+ json = { :hosts => hosts }.to_json
107
+ maybe_wrap_with_callback(json)
108
+ end
109
+
110
+ # wraps json with a callback method that JSONP clients can call
111
+ def maybe_wrap_with_callback(json)
112
+ params[:callback] ? params[:callback] + '(' + json + ')' : json
113
+ end
73
114
 
74
- # wraps json with a callback method that JSONP clients can call
75
- def maybe_wrap_with_callback(json)
76
- if params[:callback]
77
- params[:callback] + '(' + json + ')'
78
- else
79
- json
80
115
  end
81
116
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 1
8
- - 8
9
- version: 0.1.8
7
+ - 2
8
+ - 0
9
+ version: 0.2.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Lindsay Holmwood
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-06-25 00:00:00 -07:00
17
+ date: 2010-06-27 00:00:00 +10:00
18
18
  default_executable: visage
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -113,18 +113,26 @@ files:
113
113
  - lib/visage-app.rb
114
114
  - lib/visage/collectd/json.rb
115
115
  - lib/visage/collectd/profile.rb
116
+ - lib/visage/collectd/rrds.rb
116
117
  - lib/visage/config.rb
117
118
  - lib/visage/config.ru
118
119
  - lib/visage/config/fallback-colors.yaml
119
120
  - lib/visage/config/init.rb
120
121
  - lib/visage/config/plugin-colors.yaml
121
- - lib/visage/config/profiles.yaml
122
122
  - lib/visage/config/profiles.yaml.sample
123
+ - lib/visage/graph.rb
123
124
  - lib/visage/helpers.rb
124
125
  - lib/visage/patches.rb
126
+ - lib/visage/profile.rb
125
127
  - lib/visage/public/favicon.gif
128
+ - lib/visage/public/images/add.png
129
+ - lib/visage/public/images/hosts.png
130
+ - lib/visage/public/images/metrics.png
131
+ - lib/visage/public/images/search.png
126
132
  - lib/visage/public/javascripts/application.js
133
+ - lib/visage/public/javascripts/g.line-min.js
127
134
  - lib/visage/public/javascripts/g.line.js
135
+ - lib/visage/public/javascripts/g.raphael-min.js
128
136
  - lib/visage/public/javascripts/g.raphael.js
129
137
  - lib/visage/public/javascripts/graph.js
130
138
  - lib/visage/public/javascripts/mootools-1.2.3-core.js
@@ -132,8 +140,10 @@ files:
132
140
  - lib/visage/public/javascripts/raphael-min.js
133
141
  - lib/visage/public/javascripts/raphael.js
134
142
  - lib/visage/public/stylesheets/screen.css
135
- - lib/visage/views/index.haml
143
+ - lib/visage/views/builder.haml
136
144
  - lib/visage/views/layout.haml
145
+ - lib/visage/views/profile.haml
146
+ - lib/visage/views/profiles.haml
137
147
  has_rdoc: true
138
148
  homepage: http://auxesis.github.com/visage
139
149
  licenses: []
@@ -1,35 +0,0 @@
1
- ---
2
- profiles:
3
- CPU + Load:
4
- plugins:
5
- - cpu-0/cpu-user/cpu-system/cpu-idle/cpu-wait/cpu-interrupt
6
- - cpu-1
7
- - load/load
8
- - battery-0
9
- splat: cpu+load
10
- order: 1
11
- Memory:
12
- plugins:
13
- - memory
14
- - swap
15
- splat: memory
16
- order: 2
17
- Disk Usage:
18
- plugins:
19
- - df/df-root
20
- - disk-sda
21
- splat: disk+usage
22
- order: 3
23
- Networking:
24
- plugins:
25
- - tcpconns-9393-local
26
- - tcpconns-80-local
27
- - tcpconns-22-local
28
- splat: network
29
- order: 4
30
- Processes:
31
- plugins:
32
- - processes
33
- - processes-collectd
34
- splat: processes
35
- order: 5
@@ -1,48 +0,0 @@
1
- %div#nav
2
- %div#hosts.nav
3
- %h2 Hosts
4
- %ul
5
- - if !Visage::Config.rrddir
6
- %li
7
- You need to specify <strong>rrddir</strong> in config/init.rb!
8
- - elsif @hosts.empty?
9
- %li
10
- No hosts found. Please check <strong>rrddir</strong> in config/init.rb!
11
- - else
12
- - @hosts.each do |host|
13
- %li
14
- %a{:href => link_to("/#{host}")}= host
15
-
16
- - if host = params[:host]
17
- %div#profiles.nav
18
- %h2 Profiles
19
-
20
- %ul
21
- - @profiles.each do |profile|
22
- %li
23
- %a{:href => link_to("/#{host}/#{profile.splat}")}= profile.name
24
-
25
- %div#graphs
26
- - if @profile && @profile.plugins
27
- - @profile.plugins.each do |graph|
28
- - plugin, plugin_instances = graph.split('/', 2)
29
- - graph_id = "graph#{graph.gsub(/[^\w+]/, '_')}"
30
- %div.graph
31
- %div{:id => graph_id}
32
- :javascript
33
- window.addEvent('domready', function() {
34
- var graph = new visageGraph('#{graph_id}', '#{params[:host]}', '#{plugin}', {
35
- width: 900,
36
- height: 220,
37
- gridWidth: 800,
38
- gridHeight: 200,
39
- shade: #{Visage::Config.shade || false},
40
- pluginInstance: '#{plugin_instances || ''}',
41
- name: '#{plugin} on #{host}'
42
- });
43
- });
44
-
45
- - else
46
- %div#nothing
47
- Sorry, nothing to display!
48
-