pampa 2.0.12 → 2.0.14

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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/pampa.rb +177 -34
  3. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: efa42c22ec0a02a9ae9e1ff633d6b034606a78f944f842cf782b13adeb59242e
4
- data.tar.gz: 8efad57c243fc4de08f64d3fd6935d8393fb965cdfe2174749e466d2f571aa4a
3
+ metadata.gz: 0137672f5c0b7c0cd2be75ddf221d84d65d824c8ba4bdf87b5cfd369bf9eef14
4
+ data.tar.gz: 7d8bb53cfd11c3d37b69b8408c544f1718fc0178f130f5f16785771e84af9ac9
5
5
  SHA512:
6
- metadata.gz: '08d7f6166b24bcc2abd501bf62f6acae0d60aefe1283b14bbea5f079bd3a9a6b38307cb80d3dd626a49a5652093d9120793274d4816e9e7a4380c039f95a4ae8'
7
- data.tar.gz: 6ec308ec2f54ca6e81c7e3b2089d60fc1fd2c88e36f97ad8dad8dab7231eaf2c2cb62a8d3ed6000d03615315ddbd2fe364b722edd725437b8652427fd5f8dd95
6
+ metadata.gz: '00540329934fd5d5d22cae40967fee37ba4eba39a4383d324999da4902ea0a8e83c489a320820102ec3c8175a37fdace4a2147b0be490ec22e6c8380ab29f1a2'
7
+ data.tar.gz: 4efb7d405e0aa5d6a7c6f8b613b83fe14511d2f15a14f9338c48da4676204631a0c99fc34491474571c164779ad730e5820b397f2dc93a3abb3ff5bee6ec1851
data/lib/pampa.rb CHANGED
@@ -9,6 +9,11 @@ module BlackStack
9
9
  module Pampa
10
10
  # activate this flag if you want to add pampa nodes to blackstack-deployer.
11
11
  @@integrate_with_blackstack_deployer = false
12
+ # setup custom locations for config and worker files.
13
+ @@config_filename = "config.rb"
14
+ @@worker_filename = "worker.rb"
15
+ # setu the directory where the worker.rb file will be lauched, and the log files will be stored.
16
+ @@working_directory = "$HOME/pampa"
12
17
  # arrays of workers, nodes, and jobs.
13
18
  @@nodes = []
14
19
  @@jobs = []
@@ -17,7 +22,43 @@ module BlackStack
17
22
  @@logger = BlackStack::DummyLogger.new(nil)
18
23
  # Connection string to the database. Example: mysql2://user:password@localhost:3306/database
19
24
  @@connection_string = nil
20
-
25
+
26
+ # @@integrate_with_blackstack_deployer
27
+ def self.integrate_with_blackstack_deployer()
28
+ @@integrate_with_blackstack_deployer
29
+ end
30
+
31
+ def self.set_integrate_with_blackstack_deployer(b)
32
+ @@integrate_with_blackstack_deployer = b
33
+ end
34
+
35
+ # @@config_filename
36
+ def self.config_filename()
37
+ @@config_filename
38
+ end
39
+
40
+ def self.set_config_filename(s)
41
+ @@config_filename = s
42
+ end
43
+
44
+ # @@worker_filename
45
+ def self.worker_filename()
46
+ @@worker_filename
47
+ end
48
+
49
+ def self.set_worker_filename(s)
50
+ @@worker_filename = s
51
+ end
52
+
53
+ ## @@working_directory
54
+ def self.working_directory()
55
+ @@working_directory
56
+ end
57
+
58
+ def self.set_working_directory(s)
59
+ @@working_directory = s
60
+ end
61
+
21
62
  # define a filename for the log file.
22
63
  def self.set_log_filename(s)
23
64
  @@log_filename = s
@@ -33,15 +74,6 @@ module BlackStack
33
74
  @@logger = l
34
75
  end
35
76
 
36
- # @@integrate_with_blackstack_deployer
37
- def self.integrate_with_blackstack_deployer()
38
- @@integrate_with_blackstack_deployer
39
- end
40
-
41
- def self.set_integrate_with_blackstack_deployer(b)
42
- @@integrate_with_blackstack_deployer = b
43
- end
44
-
45
77
  # return the log filename.
46
78
  def self.log_filename()
47
79
  @@log_filename
@@ -297,10 +329,10 @@ module BlackStack
297
329
 
298
330
  # connect the nodes via ssh.
299
331
  # kill all Ruby processes except this one.
300
- # rename any existing folder ~/pampa to ~/pampa.<current timestamp>.
301
- # create a new folder ~/pampa.
302
- # build the file ~/pampa/config.rb in the remote node.
303
- # copy the file ~/pampa/worker.rb to the remote node.
332
+ # rename any existing folder $HOME/pampa to $HOME/pampa.<current timestamp>.
333
+ # create a new folder $HOME/pampa.
334
+ # build the file $HOME/pampa/config.rb in the remote node.
335
+ # copy the file $HOME/pampa/worker.rb to the remote node.
304
336
  # run the number of workers specified in the configuration of the Pampa module.
305
337
  # return an array with the IDs of the workers.
306
338
  #
@@ -308,7 +340,7 @@ module BlackStack
308
340
  # - config: relative path of the configuration file. Example: '../config.rb'
309
341
  # - worker: relative path of the worker.rb file. Example: '../worker.rb'
310
342
  #
311
- def self.deploy(config_filename='./config.rb', worker_filename='./worker.rb')
343
+ def self.deploy()
312
344
  # validate: the connection string is not nil
313
345
  raise "The connection string is nil" if @@connection_string.nil?
314
346
  # validate: the connection string is not empty
@@ -326,33 +358,33 @@ module BlackStack
326
358
  l.done
327
359
  # kill all ruby processes except this one
328
360
  l.logs("Killing all Ruby processes except this one... ")
329
- `ps ax | grep ruby | grep -v grep | grep -v #{Process.pid} | cut -b3-7 | xargs -t kill;`
361
+ node.exec("ps ax | grep ruby | grep -v grep | grep -v #{Process.pid} | cut -b3-7 | xargs -t kill;", false);
330
362
  l.done
331
363
  # rename any existing folder ~/code/pampa to ~/code/pampa.<current timestamp>.
332
364
  l.logs("Renaming old folder... ")
333
- `mv ~/pampa ~/pampa.#{Time.now().to_i.to_s}`
365
+ node.exec("mv #{BlackStack::Pampa.working_directory} #{BlackStack::Pampa.working_directory}.#{Time.now().to_i.to_s}", false);
334
366
  l.done
335
367
  # create a new folder ~/code. - ignore if it already exists.
336
368
  l.logs("Creating new folder... ")
337
- `mkdir ~/pampa`
369
+ node.exec("mkdir #{BlackStack::Pampa.working_directory}", false);
338
370
  l.done
339
- # build the file ~/pampa/config.rb in the remote node. - Be sure the BlackStack::Pampa.to_hash.to_s don't have single-quotes (') in the string.
371
+ # build the file $HOME/pampa/config.rb in the remote node. - Be sure the BlackStack::Pampa.to_hash.to_s don't have single-quotes (') in the string.
340
372
  l.logs("Building config file... ")
341
- s = "echo \"#{File.read(config_filename)}\" > ~/pampa/config.rb"
342
- `#{s}`
373
+ s = "echo \"#{File.read(config_filename)}\" > #{BlackStack::Pampa.working_directory}/#{BlackStack::Pampa.config_filename}"
374
+ node.exec("#{s}", false);
343
375
  l.done
344
- # copy the file ~/pampa/worker.rb to the remote node. - Be sure the script don't have single-quotes (') in the string.
376
+ # copy the file $HOME/pampa/worker.rb to the remote node. - Be sure the script don't have single-quotes (') in the string.
345
377
  l.logs("Copying worker file... ")
346
- s = "echo \"#{File.read(worker_filename)}\" > ~/pampa/worker.rb"
347
- `#{s}`
378
+ s = "echo \"#{File.read(worker_filename)}\" > #{BlackStack::Pampa.working_directory}/#{BlackStack::Pampa.worker_filename}"
379
+ node.exec("#{s}", false);
348
380
  l.done
349
381
  # run the number of workers specified in the configuration of the Pampa module.
350
382
  node.workers.each { |worker|
351
383
  # run the worker
352
384
  # add these parameters for debug: debug=yes pampa=~/code/pampa/lib/pampa.rb
353
385
  l.logs "Running worker #{worker.id}... "
354
- s = "nohup ruby worker.rb id=#{worker.id} config=~/pampa/config.rb >/dev/null 2>&1 &"
355
- `#{s}`
386
+ s = "nohup ruby #{BlackStack::Pampa.worker_filename} id=#{worker.id} config=#{BlackStack::Pampa.working_directory}/#{BlackStack::Pampa.config_filename} >/dev/null 2>&1 &"
387
+ node.exec("#{s}", false);
356
388
  l.done
357
389
  }
358
390
  # disconnect the node
@@ -368,7 +400,7 @@ module BlackStack
368
400
  # run the number of workers specified in the configuration of the Pampa module.
369
401
  # return an array with the IDs of the workers.
370
402
  #
371
- def self.start(config_filename='~/pampa/config.rb', worker_filename='~/pampa/worker.rb')
403
+ def self.start()
372
404
  # validate: the connection string is not nil
373
405
  raise "The connection string is nil" if @@connection_string.nil?
374
406
  # validate: the connection string is not empty
@@ -386,15 +418,23 @@ module BlackStack
386
418
  l.done
387
419
  # kill all ruby processes except this one
388
420
  l.logs("Killing all Ruby processes except this one... ")
389
- `ps ax | grep ruby | grep -v grep | grep -v #{Process.pid} | cut -b3-7 | xargs -t kill;`
421
+ node.exec("ps ax | grep ruby | grep -v grep | grep -v #{Process.pid} | cut -b3-7 | xargs -t kill;", true);
390
422
  l.done
391
423
  # run the number of workers specified in the configuration of the Pampa module.
392
424
  node.workers.each { |worker|
393
425
  # run the worker
394
426
  # add these parameters for debug: debug=yes pampa=~/code/pampa/lib/pampa.rb
427
+ # run a bash command that sources the .profile file and runs the ruby script in the background, returning immediatelly.
428
+
395
429
  l.logs "Running worker #{worker.id}... "
396
- s = "nohup ruby #{worker_filename} id=#{worker.id} config=#{config_filename} >/dev/null 2>&1 &"
397
- `#{s}`
430
+
431
+ # write bash command to initialize bash file
432
+ s = "echo \"source $HOME/.profile; cd #{BlackStack::Pampa.working_directory}; nohup ruby #{worker_filename} id=#{worker.id} config=#{self.config_filename} >/dev/null 2>&1 &\" > #{BlackStack::Pampa.working_directory}/worker.sh"
433
+ node.exec(s, false);
434
+
435
+ s = "nohup bash #{BlackStack::Pampa.working_directory}/worker.sh >/dev/null 2>&1 &"
436
+ node.exec(s, false);
437
+
398
438
  l.done
399
439
  }
400
440
  # disconnect the node
@@ -411,7 +451,7 @@ module BlackStack
411
451
  # Parameters:
412
452
  # - config: relative path of the configuration file. Example: '../config.rb'
413
453
  #
414
- def self.stop(config_filename='./config.rb')
454
+ def self.stop()
415
455
  # validate: the connection string is not nil
416
456
  raise "The connection string is nil" if @@connection_string.nil?
417
457
  # validate: the connection string is not empty
@@ -429,7 +469,7 @@ module BlackStack
429
469
  l.done
430
470
  # kill all ruby processes except this one
431
471
  l.logs("Killing all Ruby processes except this one... ")
432
- `ps ax | grep ruby | grep -v grep | grep -v #{Process.pid} | cut -b3-7 | xargs -t kill;`
472
+ node.exec("ps ax | grep ruby | grep -v grep | grep -v #{Process.pid} | cut -b3-7 | xargs -t kill;", false);
433
473
  l.done
434
474
  # disconnect the node
435
475
  l.logs("Disconnecting... ")
@@ -439,10 +479,43 @@ module BlackStack
439
479
  } # @@nodes.each do |node|
440
480
  end
441
481
 
482
+ # get the node by `node_name`
483
+ # connect the nodes via ssh.
484
+ # get how many minutes the worker wrote the log file
485
+ # close the connection
486
+ def self.log_minutes_ago(node_name, worker_id)
487
+ # get the node
488
+ n = self.nodes.select { |n| n.name == node_name }.first
489
+ return nil if !n
490
+ # connect the node
491
+ n.connect()
492
+ # get the time of the last time the worker wrote the log file
493
+ s = n.exec("cat #{BlackStack::Pampa.working_directory}/worker.#{worker_id}.log | tail -n 1 | cut -b1-19", false).to_s.strip
494
+ # run bash command to get the difference in minutes beteen now and the last time the worker wrote the log file
495
+ s = n.exec("echo \"$(($(date +%s) - $(date -d '#{s}' +%s))) / 60\" | bc", false).to_s.strip
496
+ # disconnect the node
497
+ n.disconnect
498
+ # return the number of minutes
499
+ s
500
+ end # log_minutes_ago
501
+
502
+ # get the node usage of CPU, RAM, DISK, and NETWORK
503
+ # return a hash with the usage of CPU, RAM, DISK, and NETWORK
504
+ #
505
+ # sudo apt install sysstat
506
+ #
507
+ def self.node_usage(node_name)
508
+ ret = {}
509
+ # get the node
510
+ n = self.nodes.select { |n| n.name == node_name }.first
511
+ return nil if !n
512
+ n.usage
513
+ end # node_usage
514
+
442
515
  # stub worker class
443
516
  class Worker
444
517
  # name to identify uniquely the worker
445
- attr_accessor :id, :assigned_job, :attached
518
+ attr_accessor :id, :assigned_job, :attached, :node
446
519
  # return an array with the errors found in the description of the job
447
520
  def self.descriptor_errors(h)
448
521
  errors = []
@@ -471,6 +544,10 @@ module BlackStack
471
544
  def detach()
472
545
  self.attached = false
473
546
  end
547
+ # get the latest n lines of the log of this worker
548
+ def tail(n=10)
549
+ self.node.tail("#{BlackStack::Pampa.working_directory}/worker.#{self.id}.log", n)
550
+ end
474
551
  end
475
552
 
476
553
  # stub node class
@@ -500,7 +577,9 @@ module BlackStack
500
577
  self.max_workers = h[:max_workers]
501
578
  self.workers = []
502
579
  self.max_workers.times do |i|
503
- self.workers << BlackStack::Pampa::Worker.new({:id => "#{self.name}.#{(i+1).to_s}", :node => self.to_hash})
580
+ new_worker = BlackStack::Pampa::Worker.new({:id => "#{self.name}.#{(i+1).to_s}", :node => self.to_hash})
581
+ new_worker.node = self
582
+ self.workers << new_worker
504
583
  end
505
584
  end # def self.create(h)
506
585
  # returh a hash descriptor of the node
@@ -569,6 +648,8 @@ module BlackStack
569
648
  # stretch assignation/unassignation of workers
570
649
  attr_accessor :max_pending_tasks
571
650
  attr_accessor :max_assigned_workers
651
+ # tags in order to choose on which nodes the job will be executed
652
+ attr_accessor :tags
572
653
 
573
654
  # return a hash descriptor of the job
574
655
  def to_hash()
@@ -596,6 +677,7 @@ module BlackStack
596
677
  :processing_function => self.processing_function.to_s,
597
678
  :max_pending_tasks => self.max_pending_tasks,
598
679
  :max_assigned_workers => self.max_assigned_workers,
680
+ :tags => self.tags
599
681
  }
600
682
  end
601
683
 
@@ -631,6 +713,7 @@ module BlackStack
631
713
  self.processing_function = h[:processing_function]
632
714
  self.max_pending_tasks = h[:max_pending_tasks]
633
715
  self.max_assigned_workers = h[:max_assigned_workers]
716
+ self.tags = h[:tags].nil? ? [] : ( h[:tags].is_a?(Array) ? h[:tags] : [h[:tags].to_s] )
634
717
  end
635
718
 
636
719
  # returns an array of tasks pending to be processed by the worker.
@@ -785,6 +868,66 @@ module BlackStack
785
868
  #
786
869
  return i
787
870
  end
871
+
872
+ # reporting method: idle
873
+ # reutrn the number of idle tasks.
874
+ # if the numbr if idle tasks is higher than `max_tasks_to_show` then it returns `max_tasks_to_show`+.
875
+ def idle(max_tasks_to_show=25)
876
+ j = self
877
+ ret = j.selecting(max_tasks_to_show).size
878
+ ret = ret >= max_tasks_to_show ? "#{ret.to_label}+" : ret.to_label
879
+ ret
880
+ end # def idle
881
+
882
+ # reporting method: running
883
+ # return the number of running tasks.
884
+ # if the numbr if running tasks is higher than `max_tasks_to_show` then it returns `max_tasks_to_show`+.
885
+ def running(max_tasks_to_show=25)
886
+ j = self
887
+ ret = 0
888
+ BlackStack::Pampa::nodes.each { |n|
889
+ n.workers.each { |w|
890
+ ret += j.occupied_slots(w).size
891
+ break if ret>=max_tasks_to_show
892
+ }
893
+ }
894
+ ret = ret >= max_tasks_to_show ? "#{max_tasks_to_show}+" : ret.to_label
895
+ ret
896
+ end # def idle
897
+
898
+ # reporting method: running
899
+ # return the number of running tasks.
900
+ # if the numbr if running tasks is higher than `max_tasks_to_show` then it returns `max_tasks_to_show`+.
901
+ def failed(max_tasks_to_show=25)
902
+ j = self
903
+ q = "
904
+ SELECT *
905
+ FROM #{j.table.to_s}
906
+ WHERE COALESCE(#{j.field_success.to_s},true)=false
907
+ --AND #{j.field_end_time.to_s} IS NULL
908
+ --AND COALESCE(#{j.field_times.to_s},0) >= #{j.max_try_times.to_i}
909
+ LIMIT #{max_tasks_to_show}
910
+ "
911
+ ret = DB[q].all.size
912
+ ret = ret >= max_tasks_to_show ? "#{ret.to_label}+" : ret.to_label
913
+ ret
914
+ end # def idle
915
+
916
+ # reporting method: error_descriptions
917
+ # return an array of hashes { :id, :error_description } with the tasks that have an the success flag in false, error description.
918
+ # if the numbr if running tasks is higher than `max_tasks_to_show` then it returns `max_tasks_to_show` errors.
919
+ def error_descriptions(max_tasks_to_show=25)
920
+ j = self
921
+ q = "
922
+ SELECT #{j.field_primary_key.to_s} as id, #{j.field_error_description.to_s} as description
923
+ FROM #{j.table.to_s}
924
+ WHERE COALESCE(#{j.field_success.to_s},true)=false
925
+ --AND #{j.field_end_time.to_s} IS NULL
926
+ --AND COALESCE(#{j.field_times.to_s},0) >= #{j.max_try_times.to_i}
927
+ LIMIT #{max_tasks_to_show}
928
+ "
929
+ DB[q].all
930
+ end
788
931
  end # class Job
789
932
  end # module Pampa
790
933
  end # module BlackStack
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pampa
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.12
4
+ version: 2.0.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Leandro Daniel Sardi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-09 00:00:00.000000000 Z
11
+ date: 2022-12-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sequel