pampa 2.0.12 → 2.0.15

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