riemann-dash 0.2.8 → 0.2.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 333646d7d876e408d47965ae5a0f27234e6b8821
4
- data.tar.gz: 286df1ba3416046249397560a6572cff9b87974d
3
+ metadata.gz: 1dcb96d79006cd63317f46f52072596a7e8d8191
4
+ data.tar.gz: 57dbb5238edab2d60bdb09613be4ccb58cbd977f
5
5
  SHA512:
6
- metadata.gz: 71467857647cd99ea04b87956f644897b61405e29e0b950a9dc67501e31128cc249113a27842544c61b385cd32f710da8b8ecf59f77815e91de775fd623a8af6
7
- data.tar.gz: c903a2a28580057a35bb83c7dc5e2126012704b5995c7a19b2a10db0ba521634bb5198e6ce754161851668d26656cb84c178f7b4ec3f07cd01b77310f0c6135c
6
+ metadata.gz: d6cf10ac7232174d526ae3666265e374246e89f7bb8a8e2a0a39b1199ef7c9e4f0db1f2b02ec6199c7e283a19902cda08639d81909f62cba726f07c53c90622e
7
+ data.tar.gz: 0aab886e0f0531fe1e5c075b2a54664b8e00da4d3f78028b21276c8b903c9c0cc34906fed09988d3180779e00866066917609946a9e43c274db388c5224edebe
data/Gemfile.lock CHANGED
@@ -1,8 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- riemann-dash (0.2.5)
4
+ riemann-dash (0.2.8)
5
5
  erubis (>= 2.7.0)
6
+ fog
6
7
  multi_json (= 1.3.6)
7
8
  riemann-client (>= 0.0.7)
8
9
  sass (>= 3.1.14)
@@ -12,34 +13,55 @@ PATH
12
13
  GEM
13
14
  remote: https://rubygems.org/
14
15
  specs:
15
- beefcake (0.3.7)
16
+ beefcake (0.5.0)
17
+ builder (3.2.2)
16
18
  coderay (1.0.9)
17
19
  daemons (1.1.9)
18
20
  erubis (2.7.0)
19
21
  eventmachine (1.0.3)
22
+ excon (0.31.0)
23
+ fog (1.19.0)
24
+ builder
25
+ excon (~> 0.31.0)
26
+ formatador (~> 0.2.0)
27
+ mime-types
28
+ multi_json (~> 1.0)
29
+ net-scp (~> 1.1)
30
+ net-ssh (>= 2.1.3)
31
+ nokogiri (~> 1.5)
32
+ ruby-hmac
33
+ formatador (0.2.4)
20
34
  method_source (0.8.1)
35
+ mime-types (2.0)
36
+ mini_portile (0.5.2)
21
37
  mtrc (0.0.4)
22
38
  multi_json (1.3.6)
39
+ net-scp (1.1.2)
40
+ net-ssh (>= 2.6.5)
41
+ net-ssh (2.7.0)
42
+ nokogiri (1.6.1)
43
+ mini_portile (~> 0.5.0)
23
44
  pry (0.9.12)
24
45
  coderay (~> 1.0.5)
25
46
  method_source (~> 0.8)
26
47
  slop (~> 3.4)
27
48
  rack (1.5.2)
28
- rack-protection (1.5.0)
49
+ rack-protection (1.5.2)
29
50
  rack
30
51
  riemann-client (0.2.2)
31
52
  beefcake (>= 0.3.5)
32
53
  mtrc (>= 0.0.4)
33
54
  trollop (>= 1.16.2)
34
- sass (3.2.7)
35
- sinatra (1.3.6)
55
+ ruby-hmac (0.4.0)
56
+ sass (3.3.2)
57
+ sinatra (1.4.4)
36
58
  rack (~> 1.4)
37
- rack-protection (~> 1.3)
38
- tilt (~> 1.3, >= 1.3.3)
59
+ rack-protection (~> 1.4)
60
+ tilt (~> 1.3, >= 1.3.4)
39
61
  slop (3.4.3)
40
- thin (1.5.1)
62
+ thin (1.6.2)
41
63
  daemons (>= 1.0.9)
42
- eventmachine (>= 0.12.6)
64
+ eventmachine (>= 1.0.0)
43
65
  rack (>= 1.0.0)
44
66
  tilt (1.4.1)
45
67
  trollop (2.0)
data/README.markdown CHANGED
@@ -11,7 +11,10 @@ Get started
11
11
  $ riemann-dash
12
12
  ```
13
13
 
14
- Then open http://localhost:4567 in a browser. Riemann-dash will connect to the local host (relative to your browser) by default, and show you a small manual.
14
+ Then open http://localhost:4567 in a browser. Riemann-dash will connect to the
15
+ local host (relative to your browser) by default, and show you a small manual.
16
+ Change the IP address in the top right field to point to your Riemann server's
17
+ websocket port.
15
18
 
16
19
  Configuring
17
20
  ===========
@@ -19,7 +22,8 @@ Configuring
19
22
  Riemann-dash takes an optional config file, which you can specify as the first
20
23
  command-line argument. If none is given, it looks for a file in the local
21
24
  directory: config.rb. That file can override any configuration options on the
22
- Dash class, and hence, all Sinatra configuration.
25
+ Dash class, and hence, all Sinatra configuration. You'll find a few usage
26
+ examples in "example/config.rb".
23
27
 
24
28
  ``` ruby
25
29
  set :port, 6000 # HTTP server on port 6000
@@ -27,7 +31,19 @@ set :bind, "1.2.3.4" # Bind to a different interface
27
31
  config[:ws_config] = 'custom/config.json' # Specify custom workspace config
28
32
  ```
29
33
 
34
+ Putting in production
35
+ =====================
30
36
 
37
+ If you expect more than a couple of simultaneous users, you should consider
38
+ running Riemann-dash in a proper application server. The easiest way is to
39
+ install thin or puma. Riemann-dash will automatically use one of them if they
40
+ are present. You'll need the C/C++ compiler, as well as the ruby and openssl
41
+ libraries and headers installed.
42
+
43
+ ``` bash
44
+ $ gem install riemann-dash thin
45
+ $ riemann-dash
46
+ ```
31
47
 
32
48
  Development
33
49
  ===========
data/example/config.rb CHANGED
@@ -15,3 +15,8 @@ config.store[:ws_config] = "#{riemann_base}/config/config.json"
15
15
 
16
16
  # Serve static files from this directory
17
17
  config.store[:public] = "#{riemann_src}/public"
18
+
19
+ # Save workspace configuration to Amazon S3 (you'll need to have the "fog"
20
+ # gem installed)
21
+ # config.store[:ws_config] = 's3://my-bucket/config.json'
22
+ # config.store[:s3_config] = {:aws_access_key_id => "123ABC", :aws_secret_access_key => "789XYZ"}
data/lib/riemann/dash.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'rubygems'
2
2
  require 'sinatra/base'
3
3
  require 'riemann/dash/version'
4
+ require 'riemann/dash/browser_config'
4
5
  require 'riemann/dash/config'
5
6
  require 'riemann/dash/app'
@@ -26,6 +26,7 @@ module Riemann
26
26
  config.load_controllers
27
27
  config.setup_views
28
28
  config.setup_public_dir
29
+ config.setup_storage_backend
29
30
  end
30
31
  end
31
32
  end
@@ -0,0 +1,72 @@
1
+ module Riemann::Dash::BrowserConfig
2
+ require 'multi_json'
3
+ require 'fileutils'
4
+ require 'pp'
5
+
6
+ def self.backend
7
+ @backend
8
+ end
9
+
10
+ def self.backend=(backend)
11
+ @backend = backend
12
+ end
13
+
14
+ # TODO: this is gonna take significant restructuring of the dashboard itself,
15
+ # but we should move to http://arxiv.org/abs/1201.1784 or equivalent CRDTs.
16
+
17
+ # Given a function to extract a key from an element, and a list of elements,
18
+ # returns a map of keys to elements. Keys are assumed unique.
19
+ def self.index_by(keyfn, list)
20
+ list.reduce({}) do |index, element|
21
+ index[keyfn.call(element)] = element
22
+ index
23
+ end
24
+ end
25
+
26
+ # Merges two lists, given a key function which determines equivalent
27
+ # elements, and a merge function to combine equivalent elements.
28
+ def self.merge_lists(keyfn, mergefn, as, bs)
29
+ asi = index_by keyfn, as
30
+ bsi = index_by keyfn, bs
31
+ ids = (as + bs).map(&keyfn).uniq.map do |key|
32
+ mergefn.call asi[key], bsi[key]
33
+ end
34
+ end
35
+
36
+ # Merge two workspaces together
37
+ def self.merge_workspace(a, b)
38
+ # TODO: workspace versions
39
+ return a unless b
40
+ return b unless a
41
+ if (a['view']['version'] || 0) < (b['view']['version'] || 0)
42
+ b
43
+ else
44
+ a
45
+ end
46
+ end
47
+
48
+ # Merge a list of workspaces together
49
+ def self.merge_workspaces(as, bs)
50
+ return as unless bs
51
+ return bs unless as
52
+ merge_lists(lambda { |x| x['name'] },
53
+ method(:merge_workspace),
54
+ as,
55
+ bs)
56
+ end
57
+
58
+ # Merge two configs together
59
+ def self.merge_configs(a, b)
60
+ a.merge 'server' => (a['server'] or b['server']),
61
+ 'server_type' => (a['server_type'] or b['server_type']),
62
+ 'workspaces' => merge_workspaces(a['workspaces'], b['workspaces'])
63
+ end
64
+
65
+ def self.read
66
+ backend.read
67
+ end
68
+
69
+ def self.update(update)
70
+ backend.update(update)
71
+ end
72
+ end
@@ -0,0 +1,39 @@
1
+ class Riemann::Dash::BrowserConfig::File
2
+ require 'multi_json'
3
+ require 'fileutils'
4
+
5
+ def initialize(path)
6
+ @path = path
7
+ end
8
+
9
+ def read
10
+ if ::File.exists? @path
11
+ ::File.open(@path, 'r') do |f|
12
+ f.flock ::File::LOCK_SH
13
+ f.read
14
+ end
15
+ else
16
+ MultiJson.encode({})
17
+ end
18
+ end
19
+
20
+ def update(update)
21
+ update = MultiJson.decode update
22
+
23
+ # Read old config
24
+ old = MultiJson.decode read
25
+
26
+ new = Riemann::Dash::BrowserConfig.merge_configs update, old
27
+
28
+ # Save new config
29
+ FileUtils.mkdir_p ::File.dirname(@path)
30
+ begin
31
+ ::File.open(@path, ::File::RDWR|::File::CREAT, 0644) do |f|
32
+ f.flock ::File::LOCK_EX
33
+ f.write(MultiJson.encode(new, :pretty => true))
34
+ f.flush
35
+ f.truncate f.pos
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,30 @@
1
+ class Riemann::Dash::BrowserConfig::S3
2
+ require 'multi_json'
3
+ require 'fog'
4
+
5
+ def initialize(bucket, path, config = {})
6
+ @bucket = bucket
7
+ @path = path
8
+ @config = config
9
+
10
+ @storage = Fog::Storage::AWS.new(config)
11
+ end
12
+
13
+ def read
14
+ begin
15
+ @storage.get_object(@bucket, @path).body
16
+ rescue Excon::Errors::NotFound
17
+ MultiJson.encode({})
18
+ end
19
+ end
20
+
21
+ def update(update)
22
+ update = MultiJson.decode update
23
+
24
+ # Read old config
25
+ old = MultiJson.decode read
26
+
27
+ new = Riemann::Dash::BrowserConfig.merge_configs update, old
28
+ @storage.put_object @bucket, @path, MultiJson.encode(new, :pretty => true)
29
+ end
30
+ end
@@ -1,4 +1,6 @@
1
1
  class Riemann::Dash::Config
2
+ require 'uri'
3
+
2
4
  attr_accessor :config_path
3
5
  attr_accessor :store
4
6
 
@@ -62,6 +64,25 @@ class Riemann::Dash::Config
62
64
  Riemann::Dash::App.use Riemann::Dash::Static, :root => store[:public]
63
65
  end
64
66
 
67
+ def setup_storage_backend
68
+ uri = URI.parse(ws_config_file)
69
+ backend = case uri.scheme
70
+ when "s3"
71
+ begin
72
+ require 'riemann/dash/browser_config/s3'
73
+ Riemann::Dash::BrowserConfig::S3.new(uri.host, uri.path.sub(/^\//, ''), store[:s3_config])
74
+ rescue LoadError
75
+ raise Exception.new 'Fog library required to save to S3. Run: "gem install fog"'
76
+ end
77
+ when nil, "file"
78
+ require 'riemann/dash/browser_config/file'
79
+ Riemann::Dash::BrowserConfig::File.new(uri.path)
80
+ else
81
+ raise Exception.new "Unknown backend for #{ws_config_file}"
82
+ end
83
+ Riemann::Dash::BrowserConfig.backend = backend
84
+ end
85
+
65
86
  # Load controllers.
66
87
  def load_controllers_from(dir)
67
88
  sorted_controller_list(dir).each do |r|
@@ -113,45 +134,4 @@ class Riemann::Dash::Config
113
134
  end
114
135
  end
115
136
  end
116
-
117
-
118
- require 'multi_json'
119
- require 'fileutils'
120
-
121
-
122
- def read_ws_config
123
- if File.exists? ws_config_file
124
- File.read(ws_config_file)
125
- else
126
- MultiJson.encode({})
127
- end
128
- end
129
-
130
- def update_ws_config(update)
131
- update = MultiJson.decode(update)
132
-
133
- # Read old config
134
- if File.exists? ws_config_file
135
- old = MultiJson.decode File.read(ws_config_file)
136
- else
137
- old = {}
138
- end
139
-
140
- new_config = {}
141
-
142
- # Server
143
- new_config['server'] = update['server'] or old['server']
144
-
145
- # Server Type
146
- new_config['server_type'] = update['server_type'] or old['server_type']
147
-
148
- #p update['workspaces']
149
- new_config['workspaces'] = update['workspaces'] or old['workspaces']
150
-
151
- # Save new config
152
- FileUtils.mkdir_p File.dirname(ws_config_file)
153
- File.open(ws_config_file, 'w') do |f|
154
- f.write(MultiJson.encode(new_config, :pretty => true))
155
- end
156
- end
157
137
  end
@@ -5,16 +5,16 @@ class Riemann::Dash::App
5
5
 
6
6
  get '/config', :provides => 'json' do
7
7
  content_type "application/json"
8
- config.read_ws_config
8
+ Riemann::Dash::BrowserConfig.read
9
9
  end
10
10
 
11
11
  post '/config' do
12
12
  # Read update
13
13
  request.body.rewind
14
- config.update_ws_config(request.body.read)
14
+ Riemann::Dash::BrowserConfig.update request.body.read
15
15
 
16
16
  # Return current config
17
17
  content_type "application/json"
18
- config.read_ws_config
18
+ Riemann::Dash::BrowserConfig.read
19
19
  end
20
- end
20
+ end
@@ -193,17 +193,20 @@ dash = (function() {
193
193
  '<li><b>e</b>: edit the view</li>' +
194
194
  '<li><b>?</b>: display this help box</li>' +
195
195
  '<li><b>s</b>: save the dashboard</li>' +
196
+ '<li><b>r</b>: reload the dashboard from last saved config</li>' +
196
197
  '<li><b>+</b>: increase the size of the view</li>' +
197
198
  '<li><b>-</b>: decrease the size of the view</li>' +
198
199
  '<li><b>v</b>: split the view vertically</li>' +
199
200
  '<li><b>h</b>: split the view horizontally</li>' +
200
201
  '<li><b>&#8592;</b>: left arrow move the view to the left</li>' +
201
202
  '<li><b>&#8594;</b>: right arrow move the view to the right</li>' +
202
- '<li><b>&#8593;</b>: up arrow move the view up>' +
203
+ '<li><b>&#8593;</b>: up arrow move the view up</li>' +
203
204
  '<li><b>&#8595;</b>: down arrow move the view down</li>' +
205
+ '<li><b>pageup</b>: select the parent of the current view</li>' +
204
206
  '<li><b>d</b>: delete a view</li>' +
205
207
  '<li><b>delete</b>: delete a view</li>' +
206
208
  '<li><b>alt-1, alt-2, etc</b>: switch to a different workplace</li>' +
209
+ '<li><b>p</b>: pause/unpause the event stream(s)</li>' +
207
210
  '</ul></div>'
208
211
  );
209
212
 
@@ -0,0 +1,63 @@
1
+ // Pane at the bottom of the dashboard for displaying events in context.
2
+
3
+ var eventPane = (function() {
4
+ var el = $('#event-pane');
5
+ var fixedFields = ['host', 'service', 'time', 'state', 'metric', 'ttl', 'description', 'tags'];
6
+ var fixedTemplate =
7
+ _.template(
8
+ '<div class="host">{{-host}}</div>' +
9
+ '<div class="service">{{-service}}</div>' +
10
+ '<div class="state {{-state}}">{{-state}}</div>' +
11
+ '<div class="metric">{{-metric}}</div>' +
12
+ '<time class="absolute">{{-time}}</time>' +
13
+ '<div class="ttl">{{-ttl}}</div>' +
14
+ '<div class="tags">{{-tags}}</div>' +
15
+ '<div class="description">{{-description}}</description>');
16
+
17
+ var rowTemplate =
18
+ _.template("<tr><td>{{-field}}</td><td>{{-value}}</td></tr>");
19
+
20
+ // Hide the pane
21
+ var hide = function() {
22
+ if (el.hasClass("active")) {
23
+ el.empty();
24
+ el.removeClass("active");
25
+ }
26
+ };
27
+
28
+ // Show an event in the pane
29
+ var show = function(event) {
30
+ hide();
31
+
32
+ if (! el.hasClass("active")) {
33
+ el.addClass("active");
34
+ }
35
+
36
+ el.append(
37
+ fixedTemplate(
38
+ _.defaults(
39
+ util.merge(event, {time: new Date(event.time)}),
40
+ {host: "nil",
41
+ service: "nil",
42
+ state: "nil",
43
+ metric: "nil",
44
+ ttl: "nil",
45
+ tags: "nil",
46
+ description: "nil"})));
47
+
48
+ var table = el.append('<table></table>');
49
+
50
+ // Remaining fields
51
+ _.each(event, function(value, field) {
52
+ if (! _.contains(fixedFields, field)) {
53
+ table.append(rowTemplate({field: field, value: value}));
54
+ }
55
+ });
56
+ };
57
+
58
+ // Hide on escape.
59
+ keys.bind(27, hide);
60
+
61
+ return {show: show,
62
+ hide: hide};
63
+ })();