ardtweeno 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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