ardtweeno 0.3.1 → 0.4.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.
@@ -2,18 +2,17 @@
2
2
  # @author David Kirwan https://github.com/davidkirwan/ardtweeno
3
3
  # @description Ardtweeno dispatcher system
4
4
  #
5
- # @date 14-06-2013
5
+ # @date 2013-08-18
6
6
  ####################################################################################################
7
7
 
8
8
  # Imports
9
- require 'rubygems'
10
9
  require 'serialport'
11
10
  require 'logger'
12
11
  require 'yaml'
13
12
  require 'json'
14
13
  require 'singleton'
15
- require 'ardtweeno'
16
14
  require 'mongo'
15
+ require 'ardtweeno'
17
16
 
18
17
  module Ardtweeno
19
18
 
@@ -43,6 +42,8 @@ module Ardtweeno
43
42
  @running = false
44
43
  @parser = nil
45
44
 
45
+ @statusbuffer = Ardtweeno::RingBuffer.new(90)
46
+
46
47
  if Ardtweeno.options[:test]
47
48
  @confdata = Ardtweeno.options[:confdata]
48
49
  else
@@ -52,6 +53,51 @@ module Ardtweeno
52
53
  end
53
54
 
54
55
 
56
+
57
+ ##
58
+ # Ardtweeno::Dispatcher#constructPunchcard method for constructing the punchcard graph
59
+ #
60
+ # * *Args* :
61
+ # - ++ ->
62
+ # * *Returns* :
63
+ # - Array data containing the 168 hourly packet totals for the last week,
64
+ # Array of strings containing the names of the last 7 days
65
+ # * *Raises* :
66
+ #
67
+ #
68
+ def constructPunchcard(params)
69
+ theData, theDays, theDateRange = Ardtweeno::API.buildPunchcard(@nodeManager.nodeList, params)
70
+
71
+ return theData, theDays, theDateRange
72
+ end
73
+
74
+
75
+
76
+ ##
77
+ # Ardtweeno::Dispatcher#constructTopology method for constructing the topology graph
78
+ #
79
+ # * *Args* :
80
+ # - ++ -> Hash params, not really used for the moment
81
+ # * *Returns* :
82
+ # - String containing the Raphael.js code to generate the graph
83
+ # * *Raises* :
84
+ #
85
+ #
86
+ def constructTopology(params=nil)
87
+ apitimer = Time.now
88
+
89
+ nodes = Ardtweeno::API.retrievenodes(@nodeManager.nodeList, params)
90
+ zones = Ardtweeno::API.retrievezones(@confdata, params)
91
+
92
+ topology = Ardtweeno::API.parseTopology(zones, nodes)
93
+ result = Ardtweeno::API.buildTopology(topology)
94
+
95
+ @log.debug "Duration: #{Time.now - apitimer} seconds"
96
+ return result
97
+ end
98
+
99
+
100
+
55
101
  ##
56
102
  # Ardtweeno::Dispatcher#flush method for flushing packet data to the Database
57
103
  #
@@ -73,7 +119,7 @@ module Ardtweeno
73
119
  db_collection = @confdata["db"]["dbPacketsColl"]
74
120
 
75
121
  if @db == nil
76
- @log.fatal "The database connector is not connected to a database!"
122
+ @log.warn "The database connector is not connected to a database!"
77
123
  @log.debug "Attempting to construct the MongoDB driver instance"
78
124
 
79
125
  begin
@@ -140,6 +186,7 @@ module Ardtweeno
140
186
  end
141
187
 
142
188
 
189
+
143
190
  ##
144
191
  # Ardtweeno::Dispatcher#retrieve_zones method for retrieving zone data from the system
145
192
  #
@@ -198,6 +245,38 @@ module Ardtweeno
198
245
  return result
199
246
  end
200
247
 
248
+
249
+
250
+ ##
251
+ # Ardtweeno::Dispatcher#watchList method to return Array of Hash containing watched node information
252
+ #
253
+ # * *Args* :
254
+ # - ++ ->
255
+ # * *Returns* :
256
+ # - Array of Hash { String :node, String :notifyURL,
257
+ # String :method, String :timeouts }
258
+ # * *Raises* :
259
+ #
260
+ def watchList
261
+ return {:watched=>@nodeManager.watchList}
262
+ end
263
+
264
+
265
+
266
+ ##
267
+ # Ardtweeno::Dispatcher#watched? method to discover if a node is being watched
268
+ #
269
+ # * *Args* :
270
+ # - ++ -> params Hash containing: {:node String name of the node}
271
+ # * *Returns* :
272
+ # - Hash {watched=>true|false}
273
+ # * *Raises* :
274
+ #
275
+ def watched?(params)
276
+ return {:watched=>@nodeManager.watched?(params[:node])}
277
+ end
278
+
279
+
201
280
 
202
281
  ##
203
282
  # Ardtweeno::Dispatcher#addWatch method to add a watch on a node
@@ -217,6 +296,8 @@ module Ardtweeno
217
296
  begin
218
297
  apitimer = Time.now
219
298
 
299
+ params = params.each_with_object({}){|(k,v), h| h[k.to_sym] = v}
300
+
220
301
  if params.has_key? :node and
221
302
  params.has_key? :notifyURL and
222
303
  params.has_key? :method and
@@ -227,13 +308,14 @@ module Ardtweeno
227
308
  raise Ardtweeno::InvalidWatch, "Invalid Parameters"
228
309
  end
229
310
 
230
- unless params[:timeout] >= 0
311
+ unless params[:timeout].to_i >= 0
231
312
  raise Ardtweeno::InvalidWatch, "Invalid Parameters"
232
313
  end
233
314
 
234
315
  @log.debug "Watch API call seems valid, passing to NodeManager"
235
316
  @nodeManager.addWatch(params)
236
317
  else
318
+ @log.debug params.inspect
237
319
  raise Ardtweeno::InvalidWatch, "Invalid Parameters"
238
320
  end
239
321
 
@@ -242,10 +324,11 @@ module Ardtweeno
242
324
  rescue Ardtweeno::AlreadyWatched => e
243
325
  raise e, "This node already has a watch associated with it"
244
326
  rescue Ardtweeno::InvalidWatch => e
245
- raise e
327
+ raise e, "Invalid Parameters"
246
328
  end
247
329
  end
248
330
 
331
+
249
332
 
250
333
  ##
251
334
  # Ardtweeno::Dispatcher#store stores a packet retrieved by the API into the system
@@ -280,7 +363,7 @@ module Ardtweeno
280
363
  node.enqueue(packet)
281
364
 
282
365
  @log.debug "Check if its being watched"
283
- if @nodeManager.watched?(node)
366
+ if @nodeManager.watched?(node.node)
284
367
  @log.debug "There is a watch on this node, pushing notifications"
285
368
  @nodeManager.pushNotification(node.node)
286
369
  else
@@ -301,6 +384,7 @@ module Ardtweeno
301
384
 
302
385
  return true
303
386
  end
387
+
304
388
 
305
389
 
306
390
  ##
@@ -369,6 +453,7 @@ module Ardtweeno
369
453
  return false
370
454
 
371
455
  end
456
+
372
457
 
373
458
 
374
459
  ##
@@ -411,9 +496,11 @@ module Ardtweeno
411
496
  return false
412
497
 
413
498
  end
499
+
500
+
414
501
 
415
502
  ##
416
- # Ardtweeno::Dispatcher#reboot which reboots the Ardtweeno Gateway host
503
+ # Ardtweeno::Dispatcher#reboot which flushes data then reboots the Ardtweeno Gateway host
417
504
  #
418
505
  # * *Args* :
419
506
  # - ++ ->
@@ -425,61 +512,96 @@ module Ardtweeno
425
512
  @log.debug "Dispatcher#reboot has been called, restarting the gateway host.."
426
513
 
427
514
  cmd = 'ls -l' #'sudo reboot'
428
-
429
- rebootFork = fork do
430
- Signal.trap("SIGTERM") { exit }
431
- `#{cmd}`
515
+ sh "#{cmd}"
516
+ end
517
+
518
+
519
+
520
+ ##
521
+ # Ardtweeno::Dispatcher#bootstrap which configures the Dispatcher instance for initial operation
522
+ #
523
+ # * *Args* :
524
+ # - ++ ->
525
+ # * *Returns* :
526
+ # -
527
+ # * *Raises* :
528
+ #
529
+ def diskUsage()
530
+ return Ardtweeno::API.diskUsage
531
+ end
532
+
533
+
534
+
535
+ ##
536
+ # Ardtweeno::Dispatcher#statuslist returns a Array of Hash containing system statuses for
537
+ # the last 15 minutes
538
+ #
539
+ # * *Args* :
540
+ # - ++ ->
541
+ # * *Returns* :
542
+ # - Array [Hash {Boolean running, String cpuload, String memload}]
543
+ # * *Raises* :
544
+ #
545
+ def statuslist()
546
+ @log.debug "Ardtweeno::Dispatcher#statuslist executing"
547
+ begin
548
+ rawdata = @statusbuffer.to_a
549
+
550
+ cpu = Array.new
551
+ mem = Array.new
552
+ running = Array.new
553
+
554
+ now = (Time.now.to_i * 1000) # Get the milliseconds since the epoch
555
+ start = now - (rawdata.size * 10000) # Get the milliseconds from the start of the buffer
556
+
557
+ rawdata.each do |i|
558
+ cpu << [start, i[:cpuload]]
559
+ mem << [start, i[:memload]]
560
+ running << [start, i[:running]]
561
+
562
+ start += 10000
563
+ end
564
+
565
+ cpuseries = {:label=>"CPU &#37;", :data=>cpu, :color=>"#ED0E0E"}
566
+ memseries = {:label=>"MEM &#37;", :data=>mem, :color=>"#0E7AED"}
567
+ runningseries = {:label=>"Active", :data=>running}
568
+
569
+ return [cpuseries, memseries, runningseries]
570
+
571
+ rescue Exception => e
572
+ raise e
432
573
  end
433
574
  end
434
575
 
435
576
 
577
+
436
578
  ##
437
579
  # Ardtweeno::Dispatcher#status? returns the system status of the Ardtweeno Gateway host
438
580
  #
439
581
  # * *Args* :
440
582
  # - ++ ->
441
583
  # * *Returns* :
442
- # - Hash theResponse containing: bool running, String cpuload, String memload
584
+ # - Hash {Boolean running, String cpuload, String memload}
443
585
  # * *Raises* :
444
586
  #
445
587
  def status?()
446
588
  @log.debug "Ardtweeno::Dispatcher#status? executing"
447
589
  begin
448
590
  unless Ardtweeno.options[:test] ||= false
449
- # Get CPU
450
- maxLoad = calculateCPUCores()
451
-
452
- # Get Avgload
453
- currentLoadPercentage = calculateAvgLoad(maxLoad)
454
-
455
- # Get MEM Usage
456
- usedMem, totalMem = calculateMemLoad()
457
-
458
-
459
- thecpuload = '%.2f' % currentLoadPercentage
460
- thememload = '%.2f' % ((usedMem / totalMem.to_f) * 100)
461
-
462
- theResponse = {:running=>@running,
463
- :cpuload=>thecpuload,
464
- :memload=>thememload}
465
-
466
- @log.debug theResponse.inspect
467
-
591
+ theResponse = Ardtweeno::API.status
592
+ theResponse[:running] = @running
468
593
  return theResponse
469
-
470
594
  else # When in testing mode, return blank data
471
595
  theResponse = {:running=>@running,
472
- :cpuload=>0.0,
473
- :memload=>0.0}
474
-
475
- @log.debug theResponse.inspect
596
+ :cpuload=>0.0,
597
+ :memload=>0.0}
476
598
 
599
+ @log.debug theResponse.inspect
477
600
  return theResponse
478
601
  end
479
-
480
602
  rescue Exception => e
481
-
482
- end
603
+ raise e
604
+ end
483
605
  end
484
606
 
485
607
 
@@ -498,6 +620,7 @@ module Ardtweeno
498
620
  end
499
621
 
500
622
 
623
+
501
624
  ##
502
625
  # Ardtweeno::Dispatcher#authenticate? Checks the API key provided with that in the DB
503
626
  #
@@ -522,6 +645,7 @@ module Ardtweeno
522
645
  end
523
646
  end
524
647
 
648
+
525
649
 
526
650
  ##
527
651
  # Ardtweeno::Dispatcher#getPostsURI returns the front page news URI ~/.ardtweeno/conf.yaml
@@ -554,6 +678,7 @@ module Ardtweeno
554
678
  return Array.new
555
679
  end
556
680
  end
681
+
557
682
 
558
683
 
559
684
  ##
@@ -569,6 +694,7 @@ module Ardtweeno
569
694
  @posts["posts"] = newPosts
570
695
  Ardtweeno::ConfigReader.save(@posts, Ardtweeno::POSTPATH)
571
696
  end
697
+
572
698
 
573
699
 
574
700
  ##
@@ -586,6 +712,7 @@ module Ardtweeno
586
712
  end
587
713
 
588
714
 
715
+
589
716
  ##
590
717
  # Ardtweeno::Dispatcher#bootstrap which configures the Dispatcher instance for initial operation
591
718
  #
@@ -597,6 +724,14 @@ module Ardtweeno
597
724
  #
598
725
  def bootstrap
599
726
 
727
+ # Create a thread which updates the statusbuffer
728
+ @statusthread = Thread.new do
729
+ loop do
730
+ @statusbuffer.push(status?)
731
+ sleep(10)
732
+ end
733
+ end
734
+
600
735
  # Read in the configuration files
601
736
  begin
602
737
  @log.debug "Reading in the configuration files"
@@ -606,8 +741,6 @@ module Ardtweeno
606
741
  @posts = Ardtweeno::ConfigReader.load(Ardtweeno::POSTPATH)
607
742
 
608
743
  rescue Exception => e
609
- @log.fatal e.message
610
- @log.fatal e.backtrace
611
744
  raise e
612
745
  end
613
746
 
@@ -636,8 +769,6 @@ module Ardtweeno
636
769
 
637
770
  @nodeManager = Ardtweeno::NodeManager.new(nmoptions)
638
771
  rescue Exception => e
639
- @log.debug e.message
640
- @log.debug e.backtrace
641
772
  raise e
642
773
  end
643
774
 
@@ -668,93 +799,11 @@ module Ardtweeno
668
799
  rescue Exception => e
669
800
  raise e
670
801
  end
671
-
672
-
673
- end # End of the bootstrap()
674
-
675
-
676
- def calculateMemLoad()
677
- begin
678
- memhash = Hash.new
679
- meminfo = File.read('/proc/meminfo')
680
- meminfo.each_line do |i|
681
- key, val = i.split(':')
682
- if val.include?('kB') then val = val.gsub(/\s+kB/, ''); end
683
- memhash["#{key}"] = val.strip
684
- end
685
-
686
- totalMem = memhash["MemTotal"].to_i
687
- freeMem = memhash["MemFree"].to_i + memhash["Buffers"].to_i + memhash["Cached"].to_i
688
- usedMem = totalMem - freeMem
689
-
690
- @log.debug "Total Memory: #{totalMem} (100%)"
691
- @log.debug "Used Memory: #{usedMem} (#{'%.2f' % ((usedMem / totalMem.to_f) * 100)}%)"
692
- @log.debug "Free Memory: #{freeMem} (#{'%.2f' % ((freeMem / totalMem.to_f) * 100)}%)"
693
-
694
- return usedMem, totalMem
695
-
696
- rescue Exception => e
697
- @log.debug "Some issue accessing /proc/meminfo"
698
- usedMem, totalMem = 0, 0
699
-
700
- return usedMem, totalMem
701
- end
702
- end
703
-
704
- def calculateAvgLoad(maxLoad)
705
- begin
706
- loadavg = File.read('/proc/loadavg')
707
- loads = loadavg.scan(/\d+.\d+/)
708
- onemin = loads[0]
709
- fivemin = loads[1]
710
- fifteenmin = loads[2]
711
-
712
- @log.debug "LoadAvg are as follows: 1min #{onemin}, 5min #{fivemin}, 15min #{fifteenmin}"
713
802
 
714
- loadval = (onemin.to_f / maxLoad)
715
- currentLoadPercentage = loadval * 100
716
-
717
- @log.debug "Currently running at #{'%.2f' % currentLoadPercentage}% of max load"
718
-
719
- return currentLoadPercentage
720
-
721
- rescue Exception => e
722
- @log.debug "Some issue accessing /proc/loadavg"
723
- onemin, fivemin, fifteenmin = 0, 0, 0
724
-
725
- loadval = (onemin.to_f / maxLoad)
726
- currentLoadPercentage = loadval * 100
727
-
728
- return currentLoadPercentage
729
- end
730
- end
731
-
732
-
733
- def calculateCPUCores()
734
- begin # Checking for multi-core CPU
735
- cpuinfo = File.read('/proc/cpuinfo')
736
- coreinfo = cpuinfo.scan(/cpu cores\s+:\s+\d+/)
737
-
738
- tempVal = coreinfo[0]
739
- numOfCores = tempVal.scan(/\d+/)[0].to_i
740
- numOfThreadsPerCore = coreinfo.size / numOfCores
741
- maxLoad = (numOfThreadsPerCore * numOfCores).to_f
742
-
743
- @log.debug "Found #{numOfCores} cores with #{numOfThreadsPerCore} threads per core"
744
- @log.debug "Max desirable cpu load: #{maxLoad}"
745
-
746
- return maxLoad
747
-
748
- rescue Exception => e
749
- @log.debug "Unable to find cpu core info in /proc/cpuinfo, assuming system has a single core"
750
- maxLoad = 1.0
751
-
752
- return maxLoad
753
- end
754
- end
803
+ end # End of the bootstrap()
755
804
 
756
805
 
757
- private :bootstrap, :calculateMemLoad, :calculateAvgLoad, :calculateCPUCores
806
+ private :bootstrap
758
807
 
759
808
  end
760
809
  end
@@ -178,8 +178,8 @@ module Ardtweeno
178
178
 
179
179
  @watchlist.each do |i|
180
180
 
181
- @log.debug "Comparing " + i[:node] + " and " + node.node
182
- if i[:node] == node.node
181
+ unless node.nil? then @log.debug "Comparing " + i[:node] + " and " + node; end
182
+ if i[:node] == node
183
183
  return true
184
184
  end
185
185
  end
@@ -205,7 +205,7 @@ module Ardtweeno
205
205
  node = search({:node=>params[:node]})
206
206
  @log.debug "Found Node: " + node.inspect
207
207
 
208
- if watched?(node)
208
+ if watched?(params[:node])
209
209
  raise Ardtweeno::AlreadyWatched
210
210
  end
211
211
 
@@ -241,20 +241,44 @@ module Ardtweeno
241
241
  #
242
242
  def removeWatch(node)
243
243
  begin
244
- node = search({:node=>node})
244
+ @log.debug "removeWatch called, querying the node manager for the correct node"
245
+ @log.debug "Searching watchlist for node"
246
+ @log.debug "Size of watchlist before: " + @watchlist.size.to_s
245
247
 
246
248
  @watchlist.each do |i|
247
- if i[:node] == node.node
249
+ @log.debug "Comparing #{i[:node]} to #{node}"
250
+ if i[:node] == node
251
+ @log.debug "Node to be deleted has been found, deleting"
248
252
  @watchlist.delete(i)
249
253
  end
250
254
  end
251
255
 
256
+ @log.debug "Size of watchlist after: " + @watchlist.size.to_s
257
+
252
258
  rescue Ardtweeno::NotInNodeList => e
253
259
  raise e
254
260
  end
255
261
  end
256
262
 
257
263
 
264
+
265
+ ##
266
+ # Ardtweeno::NodeManager#watchList returns the list of nodes being watched
267
+ #
268
+ # * *Args* :
269
+ # - ++ ->
270
+ # * *Returns* :
271
+ # - Array of Hash { String :node, String :notifyURL,
272
+ # String :method, String :timeouts }
273
+ # * *Raises* :
274
+ # -
275
+ #
276
+ def watchList
277
+ return @watchlist
278
+ end
279
+
280
+
281
+
258
282
  ##
259
283
  # Ardtweeno::NodeManager#pushNotification pushes a notification to the node watcher
260
284
  #
@@ -270,28 +294,23 @@ module Ardtweeno
270
294
  @log.debug "Traversing watchlist"
271
295
  @watchlist.each do |i|
272
296
 
273
- @log.debug "Comparing " + i[:node].node + " to " + node
297
+ @log.debug "Comparing " + i[:node] + " to " + node
274
298
 
275
- if i[:node].node == node
299
+ if i[:node] == node
276
300
 
277
301
  @log.debug "Associated watch found, checking for method " + i[:method]
278
302
 
279
303
  if i[:method] == "POST"
280
304
  @log.debug "HTTP POST method executing"
281
- @log.debug "URL: #{i[:notifyURL]}"
282
- @log.debug "Title: Push notification"
283
- @log.debug "Content: #{i[:node].node}"
284
- @log.debug "Code: #{i[:node].to_s}"
285
-
286
305
  Typhoeus::Request.post(i[:notifyURL],
287
306
  :body=> { :title=>"Push notification",
288
- :content=>"#{i[:node].node}",
307
+ :content=>"#{i[:node]}",
289
308
  :code=>""})
290
309
  elsif i[:method] == "GET"
291
310
  @log.debug "HTTP GET method executing"
292
311
  Typhoeus::Request.get(i[:notifyURL],
293
312
  :body=> { :title=>"Push notification",
294
- :content=>"#{i[:node].node}",
313
+ :content=>"#{i[:node]}",
295
314
  :code=>""})
296
315
  end
297
316