pampa 2.0.12 → 2.0.15

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 +210 -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: a8627e0b3e3f9d923c9dc750fde056078bfd202a74e3abd36eecfa27566c93f3
4
+ data.tar.gz: 27990d2b64539c229974280e5d80b630b7e6dfb05b4b6533ef8976031e791a7d
5
5
  SHA512:
6
- metadata.gz: '08d7f6166b24bcc2abd501bf62f6acae0d60aefe1283b14bbea5f079bd3a9a6b38307cb80d3dd626a49a5652093d9120793274d4816e9e7a4380c039f95a4ae8'
7
- data.tar.gz: 6ec308ec2f54ca6e81c7e3b2089d60fc1fd2c88e36f97ad8dad8dab7231eaf2c2cb62a8d3ed6000d03615315ddbd2fe364b722edd725437b8652427fd5f8dd95
6
+ metadata.gz: 71fb9a3ab3965c5aa591412c358ff6074b12d9e7ff6b8409d941ac28e42ba2ccb85288f1987a20758fd81c795d22323c597c2f15be040d5e1b628fed008aaecb
7
+ data.tar.gz: e33cfc7bca76c0a3031c4bfdc96417cfba6fadbcf7593b499a9eb2b5cefd996371b05548f159149ff2d204ae8035c524ac77c2dadbb081bde93693f0e64da1d9
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,48 @@ 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.kill_workers()
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
+
387
+ # write bash command to initialize bash file
388
+ s = "echo \"
389
+ export RUBYLIB=$HOME/code/mysaas;
390
+ source $HOME/.profile;
391
+ source /usr/local/rvm/scripts/rvm;
392
+ cd ~/code/mysaas; rvm install 3.1.2;
393
+ rvm --default use 3.1.2;
394
+ cd #{BlackStack::Pampa.working_directory};
395
+ nohup ruby #{worker_filename} id=#{worker.id} config=#{self.config_filename} >/dev/null 2>&1 &
396
+ \" > #{BlackStack::Pampa.working_directory}/#{worker.id}.sh"
397
+ node.exec(s, false);
398
+
399
+ #s = "nohup bash #{BlackStack::Pampa.working_directory}/worker.sh >/dev/null 2>&1 &"
400
+ s = "bash #{BlackStack::Pampa.working_directory}/#{worker.id}.sh"
401
+ node.exec(s, false);
402
+
356
403
  l.done
357
404
  }
358
405
  # disconnect the node
@@ -368,7 +415,7 @@ module BlackStack
368
415
  # run the number of workers specified in the configuration of the Pampa module.
369
416
  # return an array with the IDs of the workers.
370
417
  #
371
- def self.start(config_filename='~/pampa/config.rb', worker_filename='~/pampa/worker.rb')
418
+ def self.start()
372
419
  # validate: the connection string is not nil
373
420
  raise "The connection string is nil" if @@connection_string.nil?
374
421
  # validate: the connection string is not empty
@@ -386,15 +433,31 @@ module BlackStack
386
433
  l.done
387
434
  # kill all ruby processes except this one
388
435
  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;`
436
+ node.kill_workers()
390
437
  l.done
391
438
  # run the number of workers specified in the configuration of the Pampa module.
392
439
  node.workers.each { |worker|
393
440
  # run the worker
394
441
  # add these parameters for debug: debug=yes pampa=~/code/pampa/lib/pampa.rb
442
+ # run a bash command that sources the .profile file and runs the ruby script in the background, returning immediatelly.
443
+
395
444
  l.logs "Running worker #{worker.id}... "
396
- s = "nohup ruby #{worker_filename} id=#{worker.id} config=#{config_filename} >/dev/null 2>&1 &"
397
- `#{s}`
445
+
446
+ # write bash command to initialize bash file
447
+ s = "echo \"
448
+ export RUBYLIB=$HOME/code/mysaas;
449
+ source $HOME/.profile;
450
+ source /usr/local/rvm/scripts/rvm;
451
+ cd ~/code/mysaas; rvm install 3.1.2;
452
+ rvm --default use 3.1.2;
453
+ cd #{BlackStack::Pampa.working_directory};
454
+ nohup ruby #{worker_filename} id=#{worker.id} config=#{self.config_filename} >/dev/null 2>&1 &
455
+ \" > #{BlackStack::Pampa.working_directory}/#{worker.id}.sh"
456
+ #binding.pry
457
+ node.exec(s, false);
458
+ s = "nohup bash #{BlackStack::Pampa.working_directory}/#{worker.id}.sh >/dev/null 2>&1 &"
459
+ node.exec(s, false);
460
+
398
461
  l.done
399
462
  }
400
463
  # disconnect the node
@@ -411,7 +474,7 @@ module BlackStack
411
474
  # Parameters:
412
475
  # - config: relative path of the configuration file. Example: '../config.rb'
413
476
  #
414
- def self.stop(config_filename='./config.rb')
477
+ def self.stop()
415
478
  # validate: the connection string is not nil
416
479
  raise "The connection string is nil" if @@connection_string.nil?
417
480
  # validate: the connection string is not empty
@@ -429,7 +492,7 @@ module BlackStack
429
492
  l.done
430
493
  # kill all ruby processes except this one
431
494
  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;`
495
+ node.kill_workers()
433
496
  l.done
434
497
  # disconnect the node
435
498
  l.logs("Disconnecting... ")
@@ -439,10 +502,44 @@ module BlackStack
439
502
  } # @@nodes.each do |node|
440
503
  end
441
504
 
505
+ # get the node by `node_name`
506
+ # connect the nodes via ssh.
507
+ # get how many minutes the worker wrote the log file
508
+ # close the connection
509
+ def self.log_minutes_ago(node_name, worker_id)
510
+ # get the node
511
+ n = self.nodes.select { |n| n.name == node_name }.first
512
+ return nil if !n
513
+ # connect the node
514
+ n.connect()
515
+ # get the time of the last time the worker wrote the log file
516
+ code = "cat #{BlackStack::Pampa.working_directory}/worker.#{worker_id}.log | tail -n 1 | cut -b1-19"
517
+ s = n.exec(code, false).to_s.strip
518
+ # run bash command to get the difference in minutes beteen now and the last time the worker wrote the log file
519
+ s = n.exec("echo \"$(($(date +%s) - $(date -d '#{s}' +%s))) / 60\" | bc", false).to_s.strip
520
+ # disconnect the node
521
+ n.disconnect
522
+ # return the number of minutes
523
+ s
524
+ end # log_minutes_ago
525
+
526
+ # get the node usage of CPU, RAM, DISK, and NETWORK
527
+ # return a hash with the usage of CPU, RAM, DISK, and NETWORK
528
+ #
529
+ # sudo apt install sysstat
530
+ #
531
+ def self.node_usage(node_name)
532
+ ret = {}
533
+ # get the node
534
+ n = self.nodes.select { |n| n.name == node_name }.first
535
+ return nil if !n
536
+ n.usage
537
+ end # node_usage
538
+
442
539
  # stub worker class
443
540
  class Worker
444
541
  # name to identify uniquely the worker
445
- attr_accessor :id, :assigned_job, :attached
542
+ attr_accessor :id, :assigned_job, :attached, :node
446
543
  # return an array with the errors found in the description of the job
447
544
  def self.descriptor_errors(h)
448
545
  errors = []
@@ -471,6 +568,10 @@ module BlackStack
471
568
  def detach()
472
569
  self.attached = false
473
570
  end
571
+ # get the latest n lines of the log of this worker
572
+ def tail(n=10)
573
+ self.node.tail("#{BlackStack::Pampa.working_directory}/worker.#{self.id}.log", n)
574
+ end
474
575
  end
475
576
 
476
577
  # stub node class
@@ -500,7 +601,9 @@ module BlackStack
500
601
  self.max_workers = h[:max_workers]
501
602
  self.workers = []
502
603
  self.max_workers.times do |i|
503
- self.workers << BlackStack::Pampa::Worker.new({:id => "#{self.name}.#{(i+1).to_s}", :node => self.to_hash})
604
+ new_worker = BlackStack::Pampa::Worker.new({:id => "#{self.name}.#{(i+1).to_s}", :node => self.to_hash})
605
+ new_worker.node = self
606
+ self.workers << new_worker
504
607
  end
505
608
  end # def self.create(h)
506
609
  # returh a hash descriptor of the node
@@ -513,6 +616,15 @@ module BlackStack
513
616
  end
514
617
  ret
515
618
  end
619
+ # kill all workers
620
+ def kill_workers()
621
+ self.workers.each do |worker|
622
+ self.kill_worker(worker.id)
623
+ end
624
+ end
625
+ def kill_worker(worker_id)
626
+ self.exec("kill -9 $(ps -ef | grep \"ruby worker.rb id=#{worker_id}\" | grep -v grep | awk '{print $2}')", false)
627
+ end
516
628
  end # class Node
517
629
 
518
630
  # stub job class
@@ -569,6 +681,8 @@ module BlackStack
569
681
  # stretch assignation/unassignation of workers
570
682
  attr_accessor :max_pending_tasks
571
683
  attr_accessor :max_assigned_workers
684
+ # tags in order to choose on which nodes the job will be executed
685
+ attr_accessor :tags
572
686
 
573
687
  # return a hash descriptor of the job
574
688
  def to_hash()
@@ -596,6 +710,7 @@ module BlackStack
596
710
  :processing_function => self.processing_function.to_s,
597
711
  :max_pending_tasks => self.max_pending_tasks,
598
712
  :max_assigned_workers => self.max_assigned_workers,
713
+ :tags => self.tags
599
714
  }
600
715
  end
601
716
 
@@ -631,6 +746,7 @@ module BlackStack
631
746
  self.processing_function = h[:processing_function]
632
747
  self.max_pending_tasks = h[:max_pending_tasks]
633
748
  self.max_assigned_workers = h[:max_assigned_workers]
749
+ self.tags = h[:tags].nil? ? [] : ( h[:tags].is_a?(Array) ? h[:tags] : [h[:tags].to_s] )
634
750
  end
635
751
 
636
752
  # returns an array of tasks pending to be processed by the worker.
@@ -785,6 +901,66 @@ module BlackStack
785
901
  #
786
902
  return i
787
903
  end
904
+
905
+ # reporting method: idle
906
+ # reutrn the number of idle tasks.
907
+ # if the numbr if idle tasks is higher than `max_tasks_to_show` then it returns `max_tasks_to_show`+.
908
+ def idle(max_tasks_to_show=25)
909
+ j = self
910
+ ret = j.selecting(max_tasks_to_show).size
911
+ ret = ret >= max_tasks_to_show ? "#{ret.to_label}+" : ret.to_label
912
+ ret
913
+ end # def idle
914
+
915
+ # reporting method: running
916
+ # return the number of running tasks.
917
+ # if the numbr if running tasks is higher than `max_tasks_to_show` then it returns `max_tasks_to_show`+.
918
+ def running(max_tasks_to_show=25)
919
+ j = self
920
+ ret = 0
921
+ BlackStack::Pampa::nodes.each { |n|
922
+ n.workers.each { |w|
923
+ ret += j.occupied_slots(w).size
924
+ break if ret>=max_tasks_to_show
925
+ }
926
+ }
927
+ ret = ret >= max_tasks_to_show ? "#{max_tasks_to_show}+" : ret.to_label
928
+ ret
929
+ end # def idle
930
+
931
+ # reporting method: running
932
+ # return the number of running tasks.
933
+ # if the numbr if running tasks is higher than `max_tasks_to_show` then it returns `max_tasks_to_show`+.
934
+ def failed(max_tasks_to_show=25)
935
+ j = self
936
+ q = "
937
+ SELECT *
938
+ FROM #{j.table.to_s}
939
+ WHERE COALESCE(#{j.field_success.to_s},true)=false
940
+ --AND #{j.field_end_time.to_s} IS NULL
941
+ --AND COALESCE(#{j.field_times.to_s},0) >= #{j.max_try_times.to_i}
942
+ LIMIT #{max_tasks_to_show}
943
+ "
944
+ ret = DB[q].all.size
945
+ ret = ret >= max_tasks_to_show ? "#{ret.to_label}+" : ret.to_label
946
+ ret
947
+ end # def idle
948
+
949
+ # reporting method: error_descriptions
950
+ # return an array of hashes { :id, :error_description } with the tasks that have an the success flag in false, error description.
951
+ # if the numbr if running tasks is higher than `max_tasks_to_show` then it returns `max_tasks_to_show` errors.
952
+ def error_descriptions(max_tasks_to_show=25)
953
+ j = self
954
+ q = "
955
+ SELECT #{j.field_primary_key.to_s} as id, #{j.field_error_description.to_s} as description
956
+ FROM #{j.table.to_s}
957
+ WHERE COALESCE(#{j.field_success.to_s},true)=false
958
+ --AND #{j.field_end_time.to_s} IS NULL
959
+ --AND COALESCE(#{j.field_times.to_s},0) >= #{j.max_try_times.to_i}
960
+ LIMIT #{max_tasks_to_show}
961
+ "
962
+ DB[q].all
963
+ end
788
964
  end # class Job
789
965
  end # module Pampa
790
966
  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.15
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-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sequel