blackstack-deployer 1.2.2

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 +7 -0
  2. data/lib/blackstack-deployer.rb +616 -0
  3. metadata +87 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 963efdf1e53a2270ab7e7c1708b402481874ba05fe54a32efc4effedefdc08eb
4
+ data.tar.gz: d36e372a881be2f6e89517c4d194bf35f7f84d38319e0c413010e32903f146de
5
+ SHA512:
6
+ metadata.gz: 930142455038b2a8a5a4a367002c46fad30aecd52b3c41ce15c47da599c009fcb0bd7cfba9efa5985efaae805b9d50f662009930a4740fac99da2f66c5bdb0e7
7
+ data.tar.gz: 3177ece62e6ed4c45909c9bf25e357998c2d97f30f91a5820806849a8f3f134a38a522eb46a992fb47775c1f4c756bc8404096b7c5ca803e900fa2482ac35fd6
@@ -0,0 +1,616 @@
1
+ require 'blackstack-nodes'
2
+ require 'sequel'
3
+
4
+ module BlackStack
5
+ # Deployer is a library that can be used to deploy a cluster of nodes.
6
+ module Deployer
7
+ @@logger = BlackStack::BaseLogger.new(nil)
8
+ @@nodes = []
9
+ @@routines = []
10
+
11
+ # get the logger assigned to the module
12
+ def self.logger
13
+ @@logger
14
+ end # def self.errors
15
+
16
+ # get the array of nodes assigned to the module
17
+ def self.nodes
18
+ @@nodes
19
+ end # def self.nodes
20
+
21
+ # get the array of routines assigned to the module
22
+ def self.routines
23
+ @@routines
24
+ end # def self.routines
25
+
26
+ # inherit BlackStack::Infrastructure::NodeModule, including features of deployer.
27
+ module NodeModule
28
+ attr_accessor :deployment_routine, :parameters
29
+
30
+ include BlackStack::Infrastructure::NodeModule
31
+
32
+ # get the IP address for an interface using the ip addr command.
33
+ # this is a helper method for installing cockroachdb nodes.
34
+ def eth0_ip(interface='eth0')
35
+ a = self.ssh.exec!('ip addr show dev eth0').scan(/inet [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/)
36
+ return nil if a.size == 0
37
+ return a.last.to_s.gsub(/inet /, '')
38
+ end
39
+
40
+ def self.descriptor_errors(h)
41
+ errors = BlackStack::Infrastructure::NodeModule.descriptor_errors(h)
42
+
43
+ # validate: does not exist any other element in @@nodes with the same value for the parameter h[:name]
44
+ errors << "The parameter h[:name] is not unique" if BlackStack::Deployer.nodes.select{|n| n.name == h[:name]}.length > 0
45
+
46
+ # validate: h[:deployment_routine] is not nil
47
+ errors << "The parameter h[:deployment_routine] is required" if h[:deployment_routine].nil?
48
+
49
+ # validate: h[:deployment_routine] is a string
50
+ errors << "The parameter h[:deployment_routine] is not a string" unless h[:deployment_routine].is_a?(String)
51
+
52
+ # return list of errors
53
+ errors.uniq
54
+ end
55
+
56
+ def initialize(h, i_logger=nil)
57
+ self.parameters = h
58
+ errors = BlackStack::Deployer::NodeModule.descriptor_errors(h)
59
+ raise "The node descriptor is not valid: #{errors.uniq.join(".\n")}" if errors.length > 0
60
+ super(h, i_logger)
61
+ self.deployment_routine = h[:deployment_routine]
62
+ end # def self.create(h)
63
+
64
+ def to_hash
65
+ h = super
66
+ h[:deployment_routine] = self.deployment_routine
67
+ h
68
+ end # def to_hash
69
+ end # module NodeModule
70
+
71
+ # define attributes and methods of a deployer routine
72
+ module RoutineModule
73
+ attr_accessor :name, :commands
74
+
75
+ def self.descriptor_errors(h)
76
+ errors = []
77
+
78
+ # validate: the parameter h is a hash
79
+ errors << "The parameter h is not a hash" unless h.is_a?(Hash)
80
+
81
+ # validate: the paramerer h has a key :name
82
+ errors << "The parameter h does not have a key :name" unless h.has_key?(:name)
83
+
84
+ # validate: the paramerer h has a key :command
85
+ errors << "The parameter h does not have a key :commands" unless h.has_key?(:commands)
86
+
87
+ # validate: the parameter h[:name] is a string or a symbol
88
+ errors << "The parameter h[:name] is not a string" unless h[:name].is_a?(String)
89
+
90
+ # validate: the parameter h[:name] is not 'reboot' because it is a reserved name
91
+ errors << "The parameter h[:name] is a reserved name (#{h[:name].to_s})" if h[:name] == 'reboot'
92
+
93
+ # validate: the parameter h[:commands] is required
94
+ errors << "The parameter h[:commands] is required" if h[:commands].nil?
95
+
96
+ # validate: the parametrer h[:commands] is an array
97
+ errors << "The parameter h[:commands] is not an array" unless h[:commands].is_a?(Array)
98
+
99
+ # validate: the parameter h[:commands] has at least one element
100
+ errors << "The parameter h[:commands] does not have at least one element" unless h[:commands].size > 0
101
+
102
+ # validate: each element of the array h[:commands] is a hash
103
+ h[:commands].each do |c|
104
+ errors += BlackStack::Deployer::CommandModule.descriptor_errors(c)
105
+ end # h[:commands].each do |c|
106
+
107
+ errors.uniq
108
+ end # def self.descriptor_error(h)
109
+
110
+ def initialize(h)
111
+ errors = BlackStack::Deployer::RoutineModule.descriptor_errors(h)
112
+ raise "The node descriptor is not valid: #{errors.uniq.join(".\n")}" if errors.length > 0
113
+ self.name = h[:name]
114
+ self.commands = []
115
+ h[:commands].each do |c|
116
+ self.commands << BlackStack::Deployer::Command.new(c)
117
+ end
118
+ end
119
+
120
+ def to_hash
121
+ h = {}
122
+ h[:name] = self.name
123
+ h[:commands] = []
124
+ self.commands.each do |c|
125
+ h[:commands] << c.to_hash
126
+ end
127
+ h
128
+ end
129
+
130
+ def run(node)
131
+ ret = []
132
+ self.commands.each do |c|
133
+ BlackStack::Deployer.logger.logs "Running command: #{c.command.to_s}... "
134
+ h = c.run(node)
135
+ ret << h
136
+
137
+ BlackStack::Deployer.logger.logs "Result: "
138
+ BlackStack::Deployer.logger.logf h.to_s
139
+
140
+ if h[:errors].size == 0
141
+ BlackStack::Deployer.logger.done
142
+ else
143
+ BlackStack::Deployer.logger.logf('error: ' + h.to_s)
144
+ raise "Error running command: #{h.to_s}"
145
+ end
146
+ end
147
+ ret
148
+ end # def run(node)
149
+ end # module RoutineModule
150
+
151
+ # define attributes and methods of a routine's command
152
+ module CommandModule
153
+ attr_accessor :command, :matches, :nomatches, :sudo
154
+
155
+ def self.descriptor_errors(c)
156
+ errors = []
157
+
158
+ # validate: h is a hash
159
+ errors << "The command descriptor is not a hash" unless c.is_a?(Hash)
160
+
161
+ # validate: the hash c has a key :command
162
+ errors << "The command descriptor does not have a key :command" unless c.has_key?(:command)
163
+
164
+ # validate: the value of c[:command] is a string or symbol
165
+ errors << "The value of c[:command] is not a string and is not a symbol" unless c[:command].is_a?(String) || c[:command].is_a?(Symbol)
166
+
167
+ # validate: if the key :sudo exists, then its value is a boolean
168
+ if c.has_key?(:sudo)
169
+ errors << "The value of c[:sudo] is not a boolean" unless c[:sudo].is_a?(TrueClass) || c[:sudo].is_a?(FalseClass)
170
+ end
171
+
172
+ # if the parameter h[:name] is a symbol
173
+ if c[:command].is_a?(Symbol)
174
+ if c[:command] == :reboot
175
+ # :reboot is a reserved word, so it is fine to call :reboot
176
+ else
177
+ # validate: existis a routine with a the value c[:command].to_s on its :name key
178
+ errors << "The routine with the name #{c[:command].to_s} does not exist" unless BlackStack::Deployer::routines.select { |r| r.name == c[:command].to_s }.size > 0
179
+ end
180
+ end
181
+
182
+ # if c[:matches] exists
183
+ if c.has_key?(:matches)
184
+ # validate: the value of c[:matches] must by a regex or an array
185
+ errors << "The value of the key :matches is not a regex nor an array" unless c[:matches].is_a?(Regexp) || c[:matches].is_a?(Array)
186
+ # if c[:matches] is a array
187
+ if c[:matches].is_a?(Array)
188
+ # validate: each element in the the array c[:matches] is a regex
189
+ c[:matches].each do |m|
190
+ errors += BlackStack::Deployer::MatchModule.descriptor_errors(m)
191
+ end # each
192
+ end # if c[:matches].is_a?(Array)
193
+ end # if :matches exists
194
+
195
+ # if c[:nomatches] exists
196
+ if c.has_key?(:nomatches)
197
+ # validate: the value of c[:nomatches] must by a regex or an array
198
+ errors << "The value of the key :nomatches is not a regex nor an array" unless c[:nomatches].is_a?(Regexp) || c[:nomatches].is_a?(Array)
199
+ # if c[:nomatches] is a array
200
+ if c[:nomatches].is_a?(Array)
201
+ # validate: each element in the the array c[:nomatches] is a hash
202
+ c[:nomatches].each do |m|
203
+ errors += BlackStack::Deployer::NoMatchModule.descriptor_errors(m)
204
+ end # each
205
+ end # if c[:matches].is_a?(Array)
206
+ end # if :matches exists
207
+ #
208
+ errors.uniq
209
+ end # def self.descriptor_error(h)
210
+
211
+ def initialize(h)
212
+ errors = BlackStack::Deployer::CommandModule.descriptor_errors(h)
213
+ raise "The node descriptor is not valid: #{errors.uniq.join(".\n")}" if errors.length > 0
214
+ self.command = h[:command]
215
+ self.sudo = h[:sudo].nil? ? true : h[:sudo]
216
+ self.matches = []
217
+ self.nomatches = []
218
+ if h.has_key?(:matches)
219
+ if h[:matches].is_a?(Regexp)
220
+ self.matches << BlackStack::Deployer::Match.new(h[:matches])
221
+ else
222
+ h[:matches].each do |m|
223
+ self.matches << BlackStack::Deployer::Match.new(m)
224
+ end
225
+ end
226
+ end
227
+ if h.has_key?(:nomatches)
228
+ if h[:nomatches].is_a?(Regexp)
229
+ self.nomatches << BlackStack::Deployer::NoMatch.new(h[:nomatches])
230
+ else
231
+ h[:nomatches].each do |m|
232
+ self.nomatches << BlackStack::Deployer::NoMatch.new(m)
233
+ end
234
+ end
235
+ end
236
+ end # def initialize(h)
237
+
238
+ def to_hash
239
+ h = {}
240
+ h[:command] = self.command
241
+ h[:sudo] = self.sudo
242
+ h[:matches] = []
243
+ h[:nomatches] = []
244
+ self.matches.each do |m|
245
+ h[:matches] << m.to_hash
246
+ end
247
+ self.nomatches.each do |m|
248
+ h[:nomatches] << m.to_hash
249
+ end
250
+ h
251
+ end # def to_hash
252
+
253
+ def run(node)
254
+ errors = []
255
+ code = self.command
256
+ output = nil
257
+
258
+ # if code is a symbol
259
+ if code.is_a?(Symbol)
260
+
261
+ # if code is equel than :reboot
262
+ if code == :reboot
263
+ # call the node reboot method
264
+ node.reboot
265
+ else
266
+ # look for a routine with this name
267
+ r = BlackStack::Deployer.routines.select { |r| r.name == code.to_s }.first
268
+ if !r.nil?
269
+ r.run(node)
270
+ else
271
+ raise "The routine #{code.to_s} does not exist"
272
+ end
273
+ end
274
+
275
+ # if code is a string
276
+ elsif code.is_a?(String)
277
+ # replacing parameters
278
+ code.scan(/%[a-zA-Z0-9\_]+%/).each do |p|
279
+ if p == '%eth0_ip%' # reserved parameter
280
+ # TODO: move the method eth0_ip to the blackstack-nodes library
281
+ code.gsub!(p, node.eth0_ip)
282
+ elsif p == '%timestamp%' # reserved parameter
283
+ # TODO: move this to a timestamp function on blackstack-core
284
+ code.gsub!(p, Time.now.to_s.gsub(/\D/, ''))
285
+ else
286
+ if node.parameters.has_key?(p.gsub(/%/, '').to_sym)
287
+ code.gsub!(p, node.parameters[p.gsub(/%/, '').to_sym].to_s)
288
+ else
289
+ raise "The parameter #{p} does not exist in the node descriptor #{node.parameters.to_s}"
290
+ end
291
+ end
292
+ end
293
+
294
+ # running the command
295
+ if self.sudo
296
+ # escale the single quotes in the code variable
297
+ code.gsub!(/'/, "\\\\'")
298
+
299
+ if node.ssh_private_key_file.nil?
300
+ code = "echo '#{node.ssh_password.to_s.gsub("'", "\\\\'")}' | sudo -S su root -c '#{code.to_s}'"
301
+ else
302
+ code = "sudo -S su root -c '#{code.to_s}'"
303
+ end
304
+ else
305
+ code = code.to_s
306
+ end
307
+ #puts
308
+ #puts code
309
+ #exit(0)
310
+ output = node.ssh.exec!(code)
311
+
312
+ # validation: at least one of the matches should happen
313
+ if self.matches.size > 0
314
+ i = 0
315
+ self.matches.each do |m|
316
+ if m.validate(output).size == 0 # no errors
317
+ i += 1
318
+ end
319
+ end
320
+ errors << "Command output doesn't match with any of the :matches" if i == 0
321
+ end # if self.matches.size > 0
322
+
323
+ # validation: no one of the nomatches should happen
324
+ self.nomatches.each do |m|
325
+ errors += m.validate(output)
326
+ end
327
+ end # elsif code.is_a?(String)
328
+
329
+ # return a hash descriptor of the command result
330
+ {
331
+ :command => self.command,
332
+ :code => code,
333
+ :output => output,
334
+ :errors => errors,
335
+ }
336
+ end # def run(node)
337
+ end # module CommandModule
338
+
339
+ # define attributes and methods of a command's match
340
+ module MatchModule
341
+ attr_accessor :match
342
+
343
+ def self.descriptor_errors(m)
344
+ errors = []
345
+ # validate the match is a regular expresion
346
+ errors << "The match is not a regex" unless m.is_a?(Regexp)
347
+ #
348
+ errors.uniq
349
+ end # def self.descriptor_error(h)
350
+
351
+ def initialize(h)
352
+ errors = BlackStack::Deployer::MatchModule.descriptor_errors(h)
353
+ raise "The node descriptor is not valid: #{errors.uniq.join(".\n")}" if errors.length > 0
354
+ self.match = h
355
+ end
356
+
357
+ def to_hash
358
+ h = {}
359
+ h[:match] = self.match
360
+ h
361
+ end
362
+
363
+ def validate(output)
364
+ errors = []
365
+ errors << "The output of the command does not match the regular expression #{self.match.inspect}" unless output.match(self.match)
366
+ errors
367
+ end
368
+ end # module MatchModule
369
+
370
+ # define attributes and methods of a command's nomatch
371
+ module NoMatchModule
372
+ attr_accessor :nomatch, :error_description
373
+
374
+ def self.descriptor_errors(m)
375
+ errors = []
376
+ # validate the nomatch is a regular expresion
377
+ errors << "Each nomatch is not a regex nor a hash" unless m.is_a?(Hash) || m.is_a?(Regexp)
378
+ # if m is a hash
379
+ if m.is_a?(Hash)
380
+ # validate: the hash m has a key :nomatch
381
+ errors << "The hash descriptor of the nomatch does not have a key :nomatch" unless m.has_key?(:nomatch)
382
+ # validate: the value of m[:nomatch] is a string
383
+ errors << "The value of the key :nomatch is not a regex" unless m[:nomatch].is_a?(Regexp)
384
+ # validate: the hash m has a key :error_description
385
+ errors << "The hash descriptor of the nomatch does not have a key :error_description" unless m.has_key?(:error_description)
386
+ # validate: the value of m[:error_description] is a string
387
+ errors << "The value of the key :error_description is not a string" unless m[:error_description].is_a?(String)
388
+ end # if m.is_a?(Hash)
389
+ #
390
+ errors.uniq
391
+ end # def self.descriptor_error(h)
392
+
393
+ def initialize(h)
394
+ errors = BlackStack::Deployer::NoMatchModule.descriptor_errors(h)
395
+ raise "The node descriptor is not valid: #{errors.uniq.join(".\n")}" if errors.length > 0
396
+ self.nomatch = h[:nomatch]
397
+ self.error_description = h[:error_description]
398
+ end
399
+
400
+ def to_hash
401
+ h = {}
402
+ h[:nomatch] = self.nomatch
403
+ h[:error_description] = self.error_description
404
+ h
405
+ end
406
+
407
+ def validate(output)
408
+ errors = []
409
+ if !self.error_description.nil?
410
+ errors << self.error_description if output.match(self.nomatch)
411
+ else
412
+ errors << "The output of the command matches the regular expression #{self.nomatch.inspect}" if output.match(self.nomatch)
413
+ end
414
+ errors
415
+ end
416
+
417
+ end # module NoMatchModule
418
+
419
+
420
+ # TODO: declare these classes (stub and skeleton) using blackstack-rpc
421
+ #
422
+ # Stub Classes
423
+ # These classes represents a node, without using connection to the database.
424
+ # Use this class at the client side.
425
+ class Node
426
+ include BlackStack::Deployer::NodeModule
427
+ end # class Node
428
+
429
+ class Command
430
+ include BlackStack::Deployer::CommandModule
431
+ end # class Command
432
+
433
+ class Routine
434
+ include BlackStack::Deployer::RoutineModule
435
+ end # class Routine
436
+
437
+ class Match
438
+ include BlackStack::Deployer::MatchModule
439
+ end # class Match
440
+
441
+ class NoMatch
442
+ include BlackStack::Deployer::NoMatchModule
443
+ end # class NoMatch
444
+
445
+ # add a node to the list of nodes.
446
+ def self.add_node(h)
447
+ errors = BlackStack::Deployer::NodeModule.descriptor_errors(h)
448
+ raise errors.join(".\n") unless errors.empty?
449
+ @@nodes << BlackStack::Deployer::Node.new(h, @@logger)
450
+ end # def
451
+
452
+ # add an array of nodes to the list of nodes.
453
+ def self.add_nodes(a)
454
+ # validate: the parameter a is an array
455
+ raise "The parameter a is not an array" unless a.is_a?(Array)
456
+ a.each { |h| BlackStack::Deployer.add_node(h) }
457
+ end # def
458
+
459
+ # remove all exisiting nodes in he list of nodes.
460
+ # then, add the nodes in the parameter a to the list of nodes.
461
+ def self.set_nodes(a)
462
+ @@nodes.clear
463
+ BlackStack::Deployer.add_nodes(a)
464
+ end # def
465
+
466
+ # add a routine to the list of routines.
467
+ def self.add_routine(h)
468
+ errors = BlackStack::Deployer::RoutineModule.descriptor_errors(h)
469
+ raise errors.join(".\n") unless errors.empty?
470
+ @@routines << BlackStack::Deployer::Routine.new(h)
471
+ end # def
472
+
473
+ # add an array of routines to the list of routines.
474
+ def self.add_routines(a)
475
+ # validate: the parameter a is an array
476
+ raise "The parameter a is not an array" unless a.is_a?(Array)
477
+ a.each { |h| BlackStack::Deployer.add_routine(h) }
478
+ end # def
479
+
480
+ # remove all exisiting routines in he list of routines.
481
+ # then, add the routines in the parameter a to the list of routines.
482
+ def self.set_routines(a)
483
+ @@routines.clear
484
+ BlackStack::Deployer.add_routines(a)
485
+ end # def
486
+
487
+ # running a routine on a node
488
+ def self.run_routine(node_name, routine_name)
489
+ errors = []
490
+
491
+ # find the node with the value node_name in the key :name
492
+ n = @@nodes.select { |n| n.name == node_name }.first
493
+
494
+ # find the routine with the value routine_name in the key :name
495
+ r = @@routines.select { |r| r.name == routine_name }.first
496
+
497
+ # validate: the node n exists
498
+ errors << "Node #{node_name} not found" unless n
499
+
500
+ # validate: the routine r exists
501
+ errors << "Routine #{routine_name} not found" unless r
502
+
503
+ # raise exception if any error has been found
504
+ raise "The routine #{routine_name} cannot be run on the node #{node_name}: #{errors.uniq.join(".\n")}" if errors.length > 0
505
+
506
+ # connect the node
507
+ self.logger.logs "Connecting to node #{n.name}... "
508
+ n.connect
509
+ self.logger.done
510
+
511
+ # run the routine
512
+ self.logger.logs "Running routine #{r.name}... "
513
+ r.run(n)
514
+ self.logger.done
515
+
516
+ # disconnect the node
517
+ self.logger.logs "Disconnecting from node #{n.name}... "
518
+ n.disconnect
519
+ self.logger.done
520
+
521
+ end # def
522
+
523
+ module DB
524
+ @@checkpoint = nil
525
+ @@superhuser = nil
526
+ @@ndb = nil
527
+ @@folder = nil
528
+
529
+ def self.set_checkpoint(s)
530
+ @@checkpoint = s
531
+ end
532
+
533
+ def self.connect(s)
534
+ @@db = Sequel::connect(s)
535
+ end # def
536
+
537
+ def self.set_folder(s)
538
+ @@folder = s
539
+ end # def
540
+
541
+
542
+ # Return `true` if the name of the file matches with `/\.transactions\./`, and it doesn't match with `/\.sentences\./`, and the matches with `/\.transactions\./` are no more than one.
543
+ # Otherwise, return `false`.
544
+ # This method should not be called directly by user code.
545
+ def self.is_transactions_file?(filename)
546
+ filename =~ /\.transactions\./ && filename !~ /\.sentences\./ && filename.scan(/\.transactions\./).size == 1
547
+ end
548
+
549
+ # Return `true` if the name of the file matches with `/\.sentences\./`, and it doesn't match with `/\.transactions\./`, and the matches with `/\.sentences\./` are no more than one.
550
+ # Otherwise({, return `false`.
551
+ # This method should not be called directly by user code.
552
+ def self.is_sentences_file?(filename)
553
+ filename =~ /\.sentences\./ && filename !~ /\.transactions\./ && filename.scan(/\.sentences\./).size == 1
554
+ end
555
+
556
+ # Method to process an `.sql` file with transactions code, separated by `BEGIN;` and `COMMIT;` statements.
557
+ # Reference: https://stackoverflow.com/questions/64066344/import-large-sql-files-with-ruby-sequel-gem
558
+ # This method is called by `BlackStack::Deployer::db_execute_file` if the filename matches with `/\.tsql\./`.
559
+ # This method should not be called directly by user code.
560
+ def self.execute_transactions(sql)
561
+ # TODO: Code Me!
562
+ end # def db_execute_tsql
563
+
564
+ # Method to process an `.sql` file with one sql sentence by line.
565
+ # Reference: https://stackoverflow.com/questions/64066344/import-large-sql-files-with-ruby-sequel-gem
566
+ # This method is called by `BlackStack::Deployer::db_execute_file` if the filename matches with `/\.sentences\./`.
567
+ # This method should not be called directly by user code.
568
+ def self.execute_sentences(sql)
569
+ tlogger = BlackStack::Deployer::logger
570
+
571
+ # Fix issue: Ruby `split': invalid byte sequence in UTF-8 (ArgumentError)
572
+ # Reference: https://stackoverflow.com/questions/11065962/ruby-split-invalid-byte-sequence-in-utf-8-argumenterror
573
+ sql.encode!('UTF-8', :invalid => :replace)
574
+
575
+ # Keeping only ASCII characters
576
+ # Ruby: https://programming-idioms.org/idiom/147/remove-all-non-ascii-characters/1903/ruby
577
+ sql.split(/;/i).each { |statement|
578
+ statement = statement.to_s.strip
579
+ tlogger.logs "#{statement.split("\n").first}... "
580
+ begin
581
+ @@db.execute(statement) #if statement.to_s.strip.size > 0
582
+ tlogger.done
583
+ rescue => e
584
+ tlogger.logf e.to_s
585
+ raise "Error executing statement: #{statement}\n#{e.message}"
586
+ end
587
+ }
588
+ tlogger.done
589
+ end # def db_execute_sql_sentences_file
590
+
591
+ # Run a series of `.sql` files with updates to the database.
592
+ #
593
+ def self.deploy()
594
+ tlogger = BlackStack::Deployer::logger
595
+ # get list of `.sql` files in the directory `sql_path`, with a name higher than `last_filename`, sorted by name.
596
+ Dir.entries(@@folder).select {
597
+ |f| f =~ /\.sql$/ && f > @@checkpoint.to_s
598
+ }.uniq.sort.each { |filename|
599
+ fullfilename = "#{@@folder}/#{filename}"
600
+ #puts fullfilename
601
+ #puts File.open(fullfilename).read
602
+ tlogger.logs "#{fullfilename}... "
603
+ BlackStack::Deployer::DB::execute_sentences( File.open(fullfilename).read )
604
+ tlogger.done
605
+ }
606
+ end # def
607
+ end # module DB
608
+
609
+ # deploying all db-updates and run all routines on all nodes
610
+ def self.deploy()
611
+ # TODO: Code Me!
612
+ end # def
613
+
614
+ end # module Deployer
615
+
616
+ end # module BlackStack
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: blackstack-deployer
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.2
5
+ platform: ruby
6
+ authors:
7
+ - Leandro Daniel Sardi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-06-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: blackstack-nodes
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 1.2.2
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.2.2
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: 1.2.2
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.2.2
33
+ - !ruby/object:Gem::Dependency
34
+ name: sequel
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 5.56.0
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 5.56.0
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: 5.56.0
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 5.56.0
53
+ description: "BlackStack Deployer automates what you already know how to do manually,
54
+ but in a repeatable, scalable fashion. There is no magic here!\nBlackStack Deployer
55
+ dutifully connects to your server(s) via SSH and executes the steps necessary to
56
+ deploy your project. \nYou can define those steps yourself, or by using pre-built
57
+ task libraries provided by the BlackStack Deployer community.\n "
58
+ email: leandro.sardi@expandedventure.com
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - lib/blackstack-deployer.rb
64
+ homepage: https://rubygems.org/gems/blackstack-deployer
65
+ licenses:
66
+ - MIT
67
+ metadata: {}
68
+ post_install_message:
69
+ rdoc_options: []
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ requirements: []
83
+ rubygems_version: 3.3.7
84
+ signing_key:
85
+ specification_version: 4
86
+ summary: BlackStack Deployer is a deployment automation tool built on Ruby and SSH.
87
+ test_files: []