visage-app 0.2.7 → 0.3.0

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/.gitignore CHANGED
@@ -8,3 +8,4 @@ webrat*
8
8
  visage-app.gemspec
9
9
  lib/visage/config/profiles.yaml
10
10
  _site
11
+ features/data/config/*/*.yaml
data/README.md CHANGED
@@ -129,6 +129,7 @@ Run all cucumber features:
129
129
  TODO
130
130
  ----
131
131
 
132
+ * make other lines slightly opaque when hovering over labels
132
133
  * detailed point-in-time data on hover (timestamp, value)
133
134
  * give graph profile an alternate private url
134
135
  * make notes/annotations on private url
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.7
1
+ 0.3.0
@@ -0,0 +1,16 @@
1
+ Feature: Build profiles
2
+ To find out how particular systems are performing
3
+ A user
4
+ Must be able to select a host
5
+ And some metrics
6
+ And see a page of graphs
7
+
8
+ Scenario: Build a simple profile
9
+ When I go to /builder
10
+ And I fill in "hosts" with "*"
11
+ And I fill in "metrics" with "*"
12
+ And I press "metrics"
13
+ And I fill in "profile_name" with "all on all"
14
+ And I press "create"
15
+ Then I should see a list of graphs
16
+ And I should see a profile heading
data/features/cli.feature CHANGED
@@ -14,4 +14,11 @@ Feature: command line utility
14
14
  When I start the visage server helper with "visage start"
15
15
  Then I should see "Looking for RRDs in /.*collectd" on the terminal
16
16
 
17
+ Scenario: Specified configuration directory
18
+ Given the "visage" gem is installed
19
+ And there is no file at "features/data/config/with_no_profiles/profiles.yaml"
20
+ When I start the visage server helper with "visage start" and the following variables:
21
+ | CONFIG_PATH |
22
+ | features/data/config/with_no_profiles |
23
+ Then I should see a file at "features/data/config/with_no_profiles/profiles.yaml"
17
24
 
File without changes
@@ -3,11 +3,6 @@ Feature: Visit site
3
3
  A user
4
4
  Must be able to visualise the data
5
5
 
6
- Scenario: Show graphs
7
- When I go to /profiles
8
- And I visit the first profile
9
- Then I should see a list of graphs
10
-
11
6
  Scenario: List profiles
12
7
  When I go to /profiles
13
8
  Then I should see a list of profiles
@@ -16,3 +11,17 @@ Feature: Visit site
16
11
  When I follow "name"
17
12
  Then I should see a list of profiles sorted alphabetically
18
13
 
14
+ Scenario: Show profile
15
+ When I go to /profiles
16
+ And I visit the first profile
17
+ Then I should see a list of graphs
18
+ And I should see a profile heading
19
+
20
+ Scenario: Navigate profiles
21
+ When I go to /profiles
22
+ And I visit the first profile
23
+ Then I should see a list of graphs
24
+ And I should see a profile heading
25
+ When I follow "back to profiles"
26
+ Then I should see a list of profiles
27
+
@@ -7,7 +7,7 @@ end
7
7
 
8
8
  Then /^I should see a list of graphs$/ do
9
9
  doc = Nokogiri::HTML(response_body)
10
- doc.search('div#profile div.graph').size.should > 1
10
+ doc.search('div#profile div.graph').size.should > 0
11
11
  end
12
12
 
13
13
  Then /^I should see a list of profiles$/ do
@@ -25,3 +25,12 @@ Then /^I should see a list of profiles sorted alphabetically$/ do
25
25
 
26
26
  unsorted.should == sorted
27
27
  end
28
+
29
+ Then /^I should see a profile heading$/ do
30
+ doc = Nokogiri::HTML(response_body)
31
+ doc.search('div#profile h2#profile_name').size.should == 1
32
+ end
33
+
34
+ Then /^show me the page source$/ do
35
+ puts response_body
36
+ end
@@ -23,3 +23,24 @@ Then /^I should see "([^"]*)" on the terminal$/ do |string|
23
23
  output = @pipe.read(250)
24
24
  output.should =~ /#{string}/
25
25
  end
26
+
27
+ Given /^there is no file at "([^"]*)"$/ do |filename|
28
+ FileUtils.rm_f(filename).should be_true
29
+ end
30
+
31
+ When /^I start the visage server helper with "([^"]*)" and the following variables:$/ do |cmd, table|
32
+ table.hashes.each do |hash|
33
+ hash.each_pair do |variable, value|
34
+ ENV[variable] = value
35
+ end
36
+ end
37
+ When %(I start the visage server helper with "#{cmd}")
38
+ end
39
+
40
+ Then /^I should see a file at "([^"]*)"$/ do |filename|
41
+ File.exists?(filename).should be_true
42
+ end
43
+
44
+ Then /^show me the output$/ do
45
+ puts @pipe.read(250)
46
+ end
@@ -10,6 +10,8 @@ require 'spec/expectations'
10
10
  require 'rack/test'
11
11
  require 'webrat'
12
12
 
13
+ ENV['CONFIG_PATH'] = @root.join('features/data/config/default')
14
+
13
15
  require app_file
14
16
  # Force the application name because polyglot breaks the auto-detection logic.
15
17
  Sinatra::Application.app_file = app_file
@@ -1,38 +1,57 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  @root = Pathname.new(File.dirname(__FILE__)).parent.parent.parent.expand_path
4
- @config_directory = Pathname.new(File.dirname(__FILE__)).expand_path
5
4
  require @root.join('lib/visage/config')
6
5
  require 'yaml'
7
6
 
8
- Visage::Config.use do |c|
9
- # setup profiles file
10
- profile_filename = @config_directory.join('profiles.yaml')
11
- unless File.exists?(profile_filename)
12
- FileUtils.touch(profile_filename)
13
- end
14
-
15
- # setup plugin colors file
16
- plugin_colors_filename = @config_directory.join('plugin-colors.yaml')
17
- unless File.exists?(plugin_colors_filename)
18
- puts "It's highly recommended you specify graph line colors in config/plugin-colors.yaml!"
19
- end
20
-
21
- # load config from profiles + plugin colors file
22
- [profile_filename, plugin_colors_filename].each do |filename|
23
- if File.exists?(filename)
24
- config = YAML::load_file(filename) || {}
25
- config.each_pair {|key, value| c[key] = value}
7
+ module Visage
8
+ class Config
9
+ class File
10
+ @@config_directories = []
11
+ @@config_directories << Pathname.new(::File.dirname(__FILE__)).expand_path
12
+ @@config_directories << Pathname.new(ENV["CONFIG_PATH"]).expand_path if ENV["CONFIG_PATH"]
13
+ @@config_directories.reverse!
14
+
15
+ def self.find(filename, opts={})
16
+ range = opts[:ignore_bundled] ? (0..-2) : (0..-1)
17
+ potential_filenames = @@config_directories[range].map {|d| d.join(filename)}
18
+ potential_filenames.find { |f| ::File.exists?(f) }
19
+ end
20
+
21
+ def self.load(filename, opts={})
22
+ unless path = self.find(filename, opts)
23
+ if opts[:create]
24
+ path = @@config_directories.first.join(filename)
25
+ begin
26
+ FileUtils.touch(path)
27
+ rescue Errno::EACCES => e
28
+ raise Errno::EACCES, "Couldn't write #{path}. Do you have CONFIG_PATH set?"
29
+ end
30
+ end
31
+ end
32
+
33
+ YAML::load_file(path)
34
+ end
35
+
36
+ def self.open(filename, &block)
37
+ path = self.find(filename)
38
+ ::File.open(path, 'r+') do |f|
39
+ block.call(f)
40
+ end
41
+ end
42
+
43
+ def initialize(filename, opts={})
44
+ unless ::File.exists?(filename)
45
+ path = @@config_directories.first.join(filename)
46
+ FileUtils.touch(path)
47
+ end
48
+ @file = ::File.open(filename, 'r+')
49
+ end
50
+
51
+ def to_s
52
+ @file.path
53
+ end
26
54
  end
27
55
  end
28
-
29
- # load fallback colors
30
- c['fallback_colors'] = YAML::load(File.read(@config_directory.join('fallback-colors.yaml')))
31
-
32
- # Location of collectd's RRD - you may want to edit this!
33
- c['rrddir'] = "/var/lib/collectd/rrd"
34
-
35
- # whether to shade in graphs
36
- c['shade'] = false
37
56
  end
38
57
 
@@ -1,67 +1,60 @@
1
1
  ---
2
- plugin_colors:
3
- memory:
4
- memory-used:
5
- value: "#cc0000"
6
- memory-buffered:
7
- value: "#edd400"
8
- memory-cached:
9
- value: "#3465a4"
10
- memory-free:
11
- value: "#73d216"
12
- cpu:
13
- cpu-idle:
14
- value: "#eeeeec"
15
- cpu-wait:
16
- value: "#edd400"
17
- cpu-user:
18
- value: "#3465a4"
19
- cpu-system:
20
- value: "#cc0000"
21
- cpu-nice:
22
- value: "#73d216"
23
- cpu-softirq:
24
- value: "#ad7fa8"
25
- cpu-interrupt:
26
- value: "#5c3566"
27
- cpu-steal:
28
- value: "#2e3436"
29
- swap:
30
- swap-used:
31
- value: "#cc0000"
32
- swap-free:
33
- value: "#73d216"
34
- swap-cached:
35
- value: "#3465a4"
36
- swap_io-in:
37
- value: "#edd400"
38
- swap_io-out:
39
- value: "#5c3566"
2
+ memory:
3
+ memory-used:
4
+ value: "#cc0000"
5
+ memory-buffered:
6
+ value: "#edd400"
7
+ memory-cached:
8
+ value: "#3465a4"
9
+ memory-free:
10
+ value: "#73d216"
11
+ cpu:
12
+ cpu-idle:
13
+ value: "#eeeeec"
14
+ cpu-wait:
15
+ value: "#edd400"
16
+ cpu-user:
17
+ value: "#3465a4"
18
+ cpu-system:
19
+ value: "#cc0000"
20
+ cpu-nice:
21
+ value: "#73d216"
22
+ cpu-softirq:
23
+ value: "#ad7fa8"
24
+ cpu-interrupt:
25
+ value: "#5c3566"
26
+ cpu-steal:
27
+ value: "#2e3436"
28
+ swap:
29
+ swap-used:
30
+ value: "#cc0000"
31
+ swap-free:
32
+ value: "#73d216"
33
+ swap-cached:
34
+ value: "#3465a4"
35
+ swap_io-in:
36
+ value: "#edd400"
37
+ swap_io-out:
38
+ value: "#5c3566"
39
+ load:
40
40
  load:
41
- load:
42
- longterm: "#ef2929"
43
- shortterm: "#73d216"
44
- midterm: "#3465a4"
41
+ longterm: "#ef2929"
42
+ shortterm: "#73d216"
43
+ midterm: "#3465a4"
44
+ df:
45
45
  df:
46
- df:
47
- used: "#cc0000"
48
- free: "#73d216"
49
- disk:
50
- disk_merged:
51
- read: "#8ae234"
52
- write: "#ef2929"
53
- disk_time:
54
- read: "#729fcf"
55
- write: "#fcaf3e"
56
- disk_ops:
57
- read: "#ad7fa8"
58
- write: "#fce94f"
59
- disk_octets:
60
- read: "#c17d11"
61
- write: "#888a85"
62
-
63
-
64
-
65
-
66
-
67
-
46
+ used: "#cc0000"
47
+ free: "#73d216"
48
+ disk:
49
+ disk_merged:
50
+ read: "#8ae234"
51
+ write: "#ef2929"
52
+ disk_time:
53
+ read: "#729fcf"
54
+ write: "#fcaf3e"
55
+ disk_ops:
56
+ read: "#ad7fa8"
57
+ write: "#fce94f"
58
+ disk_octets:
59
+ read: "#c17d11"
60
+ write: "#888a85"
data/lib/visage/config.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  module Visage
2
2
  class Config
3
-
4
3
  class << self
5
4
  def use
6
5
  @configuration ||= {}
@@ -11,18 +11,15 @@ module Visage
11
11
  attr_reader :options, :selected_hosts, :hosts, :selected_metrics, :metrics,
12
12
  :name, :errors
13
13
 
14
- @@root = Pathname.new(File.dirname(__FILE__)).parent.parent.expand_path
15
- @@profiles_filename = @@root.join('lib/visage/config/profiles.yaml')
16
-
17
14
  def self.get(id)
18
15
  url = id.downcase.gsub(/[^\w]+/, "+")
19
- profiles = YAML::load_file(@@profiles_filename) || {}
16
+ profiles = Visage::Config.profiles || {}
20
17
  profiles[url] ? self.new(profiles[url]) : nil
21
18
  end
22
19
 
23
20
  def self.all(opts={})
24
21
  sort = opts[:sort]
25
- profiles = YAML::load_file(@@profiles_filename) || {}
22
+ profiles = Visage::Config.profiles || {}
26
23
  profiles = sort == "name" ? profiles.sort.map {|i| i.last } : profiles.values
27
24
  profiles.map { |prof| self.new(prof) }
28
25
  end
@@ -66,10 +63,10 @@ module Visage
66
63
  :url => @options[:profile_name].downcase.gsub(/[^\w]+/, "+") }
67
64
 
68
65
  # Save it.
69
- profiles = YAML::load_file(@@profiles_filename) || {}
66
+ profiles = Visage::Config.profiles || {}
70
67
  profiles[attrs[:url]] = attrs
71
68
 
72
- File.open(@@profiles_filename, 'w') do |file|
69
+ Visage::Config::File.open('profiles.yaml') do |file|
73
70
  file << profiles.to_yaml
74
71
  end
75
72
 
@@ -76,7 +76,10 @@ var visageBase = new Class({
76
76
  header = $chk(this.options.name) ? this.options.name : this.options.plugin
77
77
  this.graphHeader = new Element('h3', {
78
78
  'class': 'graph-title',
79
- 'html': header
79
+ 'html': header,
80
+ 'styles': {
81
+ 'color': "#121212"
82
+ }
80
83
  });
81
84
  $(this.parentElement).grab(this.graphHeader);
82
85
  },
@@ -15,10 +15,9 @@ a {
15
15
  /* styles */
16
16
 
17
17
  a { color: #3465a4; padding: 2px 0px; }
18
- a:hover { color: white; background-color: #3465a4; }
18
+ a:hover { text-decoration: underline; }
19
19
  a:visited { color: #75507b; }
20
- a:hover:visited { color: white; background-color: #75507b; }
21
- a:active { color: white; background-color: #cc0000; }
20
+ a:hover:visited { text-decoration: underline; }
22
21
 
23
22
  p {
24
23
  margin: 0 0 1em;
@@ -34,6 +33,8 @@ div#header {
34
33
  background-color: #3465a4;
35
34
  margin-bottom: 16px;
36
35
  border-bottom: 6px solid #c5d6ed;
36
+ background: -moz-linear-gradient(100% 100% 90deg, #3465a4, #142e52);
37
+ background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#142e52), to(#3465a4));
37
38
  }
38
39
 
39
40
  div#nav {
@@ -53,7 +54,7 @@ div#nav a {
53
54
 
54
55
  div#nav a:hover {
55
56
  text-shadow: 0 1px 6px rgba(115,157,211,0.9);
56
- background-color: #3465a4;
57
+ text-decoration: none;
57
58
  }
58
59
 
59
60
  div#content, div#nav {
@@ -206,7 +207,7 @@ h1, h2, h3, h4, h5 {
206
207
 
207
208
  h2 {
208
209
  font-weight: bold;
209
- color: #666;
210
+ color: #333;
210
211
  border-bottom: 4px solid #888;
211
212
  margin-bottom: 12px;
212
213
  }
@@ -221,6 +222,27 @@ h1 span.project-name {
221
222
  color: white;
222
223
  }
223
224
 
225
+ h2#profile_name {
226
+ margin: 36px 0;
227
+ }
228
+
229
+ h4.error {
230
+ margin: 8px 0;
231
+ }
232
+
233
+ div.graph pre {
234
+ line-height: 1.6em;
235
+ font-size: 90%;
236
+ margin-top: -10px;
237
+ }
238
+
239
+ div#bottom_nav {
240
+ margin: 32px 0;
241
+ border-top: 1px dotted #aaa;
242
+ padding-top: 12px;
243
+ font-size: 85%;
244
+ }
245
+
224
246
  div#footer {
225
247
  font-size: 0.6em;
226
248
  color: gray;
@@ -255,5 +277,8 @@ div#profiles ul {
255
277
  }
256
278
 
257
279
  div#profiles p.create {
280
+ border-top: 1px dotted #aaa;
281
+ padding-top: 8px;
282
+ margin-top: 24px;
258
283
  font-size: 85%;
259
284
  }
@@ -10,7 +10,6 @@
10
10
  %script{:type => "text/javascript", :src => link_to("/javascripts/mootools-1.2.3-core.js")}
11
11
  %script{:type => "text/javascript", :src => link_to("/javascripts/mootools-1.2.3.1-more.js")}
12
12
  %script{:type => "text/javascript", :src => link_to("/javascripts/graph.js")}
13
- %script{:type => "text/javascript", :src => link_to("/javascripts/application.js")}
14
13
 
15
14
  %body
16
15
  %div#wrapper
@@ -1,6 +1,8 @@
1
- - page_title @profile.options[:profile_name]
1
+ - profile_name = @profile.options[:profile_name]
2
+ - page_title(profile_name)
2
3
 
3
4
  %div#profile
5
+ %h2#profile_name= profile_name
4
6
  - @profile.graphs.each do |graph|
5
7
  %div{:id => graph.id, :class => 'graph'}
6
8
  :javascript
@@ -17,4 +19,17 @@
17
19
  finish: '#{@finish}'
18
20
  });
19
21
  });
22
+ - if @profile.graphs.size == 0
23
+ %div.graph
24
+ %h4.error Oops! Looks like there aren't any graphs matching the specified patterns.
25
+ %p These are the patterns:
26
+ %pre
27
+ :preserve
28
+ Host: #{@profile.options[:hosts]}
29
+ Metrics: #{@profile.options[:metrics]}
30
+
31
+ %div#bottom_nav
32
+ %a{:href => link_to("/profiles")} &larr; Back to profiles
33
+
34
+
20
35
 
@@ -14,5 +14,5 @@
14
14
  %a{:href => link_to("/profiles/#{prof.url}")}= prof.profile_name
15
15
 
16
16
  %p.create
17
- %a{:href => link_to("/builder")} Create a new profile.
17
+ %a{:href => link_to("/builder")} Create a profile
18
18
 
data/lib/visage-app.rb CHANGED
@@ -22,6 +22,19 @@ module Visage
22
22
 
23
23
  helpers Sinatra::LinkToHelper
24
24
  helpers Sinatra::PageTitleHelper
25
+
26
+ configure do
27
+ Visage::Config.use do |c|
28
+ # Base configuration files.
29
+ c['profiles'] = Visage::Config::File.load('profiles.yaml', :create => true, :ignore_bundled => true)
30
+ c['plugin_colors'] = Visage::Config::File.load('plugin-colors.yaml')
31
+ c['fallback_colors'] = Visage::Config::File.load('fallback-colors.yaml')
32
+
33
+ # FIXME: make this configurable through file
34
+ c['shade'] = false
35
+ c['rrddir'] = ENV["RRDDIR"] ? Pathname.new(ENV["RRDDIR"]).expand_path : Pathname.new("/var/lib/collectd/rrd").expand_path
36
+ end
37
+ end
25
38
  end
26
39
 
27
40
  class Profiles < Application
@@ -32,7 +45,7 @@ module Visage
32
45
  get '/profiles/:url' do
33
46
  @profile = Visage::Profile.get(params[:url])
34
47
  raise Sinatra::NotFound unless @profile
35
- @start = params[:start]
48
+ @start = params[:start]
36
49
  @finish = params[:finish]
37
50
  haml :profile
38
51
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 2
8
- - 7
9
- version: 0.2.7
7
+ - 3
8
+ - 0
9
+ version: 0.3.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-09-26 00:00:00 +10:00
17
+ date: 2010-10-15 00:00:00 +11:00
18
18
  default_executable: visage
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -101,9 +101,11 @@ files:
101
101
  - Rakefile
102
102
  - VERSION
103
103
  - bin/visage
104
+ - features/builder.feature
104
105
  - features/cli.feature
106
+ - features/data/config/with_no_profiles/.stub
105
107
  - features/json.feature
106
- - features/site.feature
108
+ - features/profiles.feature
107
109
  - features/step_definitions/form_steps.rb
108
110
  - features/step_definitions/json_steps.rb
109
111
  - features/step_definitions/result_steps.rb
@@ -129,7 +131,6 @@ files:
129
131
  - lib/visage/public/images/hosts.png
130
132
  - lib/visage/public/images/metrics.png
131
133
  - lib/visage/public/images/search.png
132
- - lib/visage/public/javascripts/application.js
133
134
  - lib/visage/public/javascripts/g.line-min.js
134
135
  - lib/visage/public/javascripts/g.line.js
135
136
  - lib/visage/public/javascripts/g.raphael-min.js
@@ -1,4 +0,0 @@
1
- window.addEvent('domready', function () {
2
-
3
- });
4
-