my-ruby-deployer 1.3.1
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.
- checksums.yaml +7 -0
- data/lib/my-ruby-deployer.rb +502 -0
- metadata +187 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 011acb5e8ea3b1f472cdc7762bbe8c28c9af0d71d0e794c400941878d58c2dc0
|
4
|
+
data.tar.gz: 2b804b60e3f7112fa281444b3209b5c4bbcdf42e09d6267ecc15a8e2a325f841
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 46f6485783a33b8907d82b6973075b2b75d0bb53874a28c28f7608e7cff689ab27a1da72263525e20399aa8330b7f4cea434c7ca7758762a3ba80334a6313aaa
|
7
|
+
data.tar.gz: 50643d4b9906e09f1ffd7a8a578ed8482e787464224b4d7d7089309fd5a85980fa9becca7362305a902cb9dc0432f6ed04e7c48abf9806ff6a48822aaa022992
|
@@ -0,0 +1,502 @@
|
|
1
|
+
require 'blackstack-nodes'
|
2
|
+
require 'pg'
|
3
|
+
require 'sequel'
|
4
|
+
require 'colorize'
|
5
|
+
require 'simple_cloud_logging'
|
6
|
+
|
7
|
+
module BlackStack
|
8
|
+
# Deployer is a library that can be used to deploy a cluster of nodes.
|
9
|
+
module Deployer
|
10
|
+
@@nodes = []
|
11
|
+
@@routines = []
|
12
|
+
|
13
|
+
# get the array of nodes assigned to the module
|
14
|
+
def self.nodes
|
15
|
+
@@nodes
|
16
|
+
end # def self.nodes
|
17
|
+
|
18
|
+
# get the array of routines assigned to the module
|
19
|
+
def self.routines
|
20
|
+
@@routines
|
21
|
+
end # def self.routines
|
22
|
+
|
23
|
+
# inherit BlackStack::Infrastructure::NodeModule, including features of deployer.
|
24
|
+
module NodeModule
|
25
|
+
attr_accessor :deployment_routine, :parameters
|
26
|
+
|
27
|
+
include BlackStack::Infrastructure::NodeModule
|
28
|
+
|
29
|
+
def self.eth0_ip(insterface)
|
30
|
+
ret = nil
|
31
|
+
a = `ip addr show dev #{insterface}`.scan(/inet [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/)
|
32
|
+
if a.size > 0
|
33
|
+
ret = a.last.to_s.gsub(/inet /, '')
|
34
|
+
else
|
35
|
+
raise "Cannot get ip address of the interface #{insterface}"
|
36
|
+
end
|
37
|
+
ret
|
38
|
+
end
|
39
|
+
|
40
|
+
# get the IP address for an interface using the ip addr command.
|
41
|
+
# this is a helper method for installing cockroachdb nodes.
|
42
|
+
def eth0_ip()
|
43
|
+
ret = nil
|
44
|
+
a = self.ssh.exec!("ip addr show dev #{parameters[:laninterface]}").scan(/inet [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/)
|
45
|
+
if a.size > 0
|
46
|
+
ret = a.last.to_s.gsub(/inet /, '')
|
47
|
+
else
|
48
|
+
raise "Cannot get ip address of the interface #{parameters[:laninterface]}"
|
49
|
+
end
|
50
|
+
ret
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.descriptor_errors(h)
|
54
|
+
errors = BlackStack::Infrastructure::NodeModule.descriptor_errors(h)
|
55
|
+
|
56
|
+
# validate: does not exist any other element in @@nodes with the same value for the parameter h[:name]
|
57
|
+
errors << "The parameter h[:name] is not unique" if BlackStack::Deployer.nodes.select{|n| n.name == h[:name]}.length > 0
|
58
|
+
|
59
|
+
# validate: h[:deployment_routine] is not nil
|
60
|
+
errors << "The parameter h[:deployment_routine] is required" if h[:deployment_routine].nil?
|
61
|
+
|
62
|
+
# validate: h[:deployment_routine] is a string
|
63
|
+
# This value is no longer mandatory
|
64
|
+
#errors << "The parameter h[:deployment_routine] is not a string" unless h[:deployment_routine].is_a?(String)
|
65
|
+
|
66
|
+
# return list of errors
|
67
|
+
errors.uniq
|
68
|
+
end
|
69
|
+
|
70
|
+
def initialize(h, i_logger=nil)
|
71
|
+
self.parameters = h
|
72
|
+
errors = BlackStack::Deployer::NodeModule.descriptor_errors(h)
|
73
|
+
raise "The node descriptor is not valid: #{errors.uniq.join(".\n")}" if errors.length > 0
|
74
|
+
super(h, i_logger)
|
75
|
+
self.deployment_routine = h[:deployment_routine]
|
76
|
+
end # def self.create(h)
|
77
|
+
|
78
|
+
def to_hash
|
79
|
+
h = super
|
80
|
+
h[:deployment_routine] = self.deployment_routine
|
81
|
+
h
|
82
|
+
end # def to_hash
|
83
|
+
|
84
|
+
def deploy(routine_name=nil, l=nil)
|
85
|
+
l = BlackStack::DummyLogger.new(nil) if l.nil?
|
86
|
+
s = routine_name || self.deployment_routine
|
87
|
+
BlackStack::Deployer::run_routine(self.name, s, l);
|
88
|
+
end
|
89
|
+
end # module NodeModule
|
90
|
+
|
91
|
+
# define attributes and methods of a deployer routine
|
92
|
+
module RoutineModule
|
93
|
+
attr_accessor :name, :commands
|
94
|
+
|
95
|
+
def self.descriptor_errors(h)
|
96
|
+
errors = []
|
97
|
+
|
98
|
+
# validate: the parameter h is a hash
|
99
|
+
errors << "The parameter h is not a hash" unless h.is_a?(Hash)
|
100
|
+
|
101
|
+
# validate: the paramerer h has a key :name
|
102
|
+
errors << "The parameter h does not have a key :name" unless h.has_key?(:name)
|
103
|
+
|
104
|
+
# validate: the paramerer h has a key :command
|
105
|
+
errors << "The parameter h does not have a key :commands" unless h.has_key?(:commands)
|
106
|
+
|
107
|
+
# validate: the parameter h[:name] is a string or a symbol
|
108
|
+
errors << "The parameter h[:name] is not a string" unless h[:name].is_a?(String)
|
109
|
+
|
110
|
+
# validate: the parameter h[:name] is not 'reboot' because it is a reserved name
|
111
|
+
errors << "The parameter h[:name] is a reserved name (#{h[:name].to_s})" if h[:name] == 'reboot'
|
112
|
+
|
113
|
+
# validate: the parameter h[:commands] is required
|
114
|
+
errors << "The parameter h[:commands] is required" if h[:commands].nil?
|
115
|
+
|
116
|
+
# validate: the parametrer h[:commands] is an array
|
117
|
+
errors << "The parameter h[:commands] is not an array" unless h[:commands].is_a?(Array)
|
118
|
+
|
119
|
+
# validate: the parameter h[:commands] has at least one element
|
120
|
+
errors << "The parameter h[:commands] does not have at least one element" unless h[:commands].size > 0
|
121
|
+
|
122
|
+
# validate: each element of the array h[:commands] is a hash
|
123
|
+
h[:commands].each do |c|
|
124
|
+
errors += BlackStack::Deployer::CommandModule.descriptor_errors(c)
|
125
|
+
end # h[:commands].each do |c|
|
126
|
+
|
127
|
+
errors.uniq
|
128
|
+
end # def self.descriptor_error(h)
|
129
|
+
|
130
|
+
def initialize(h)
|
131
|
+
errors = BlackStack::Deployer::RoutineModule.descriptor_errors(h)
|
132
|
+
raise "The node descriptor is not valid: #{errors.uniq.join(".\n")}" if errors.length > 0
|
133
|
+
self.name = h[:name]
|
134
|
+
self.commands = []
|
135
|
+
h[:commands].each do |c|
|
136
|
+
self.commands << BlackStack::Deployer::Command.new(c)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def to_hash
|
141
|
+
h = {}
|
142
|
+
h[:name] = self.name
|
143
|
+
h[:commands] = []
|
144
|
+
self.commands.each do |c|
|
145
|
+
h[:commands] << c.to_hash
|
146
|
+
end
|
147
|
+
h
|
148
|
+
end
|
149
|
+
|
150
|
+
def run(node, l=nil)
|
151
|
+
l = BlackStack::DummyLogger.new(nil) if l.nil?
|
152
|
+
l.logs "Running routine #{self.name.blue} on node #{node.name.blue}... "
|
153
|
+
i = 0
|
154
|
+
self.commands.each do |c|
|
155
|
+
i += 1
|
156
|
+
l.logs "Command #{i.to_s.blue}... "
|
157
|
+
c.run(node, l)
|
158
|
+
l.logf 'done'.green
|
159
|
+
end
|
160
|
+
l.logf 'done'.green
|
161
|
+
end # def run(node)
|
162
|
+
end # module RoutineModule
|
163
|
+
|
164
|
+
# define attributes and methods of a routine's command
|
165
|
+
module CommandModule
|
166
|
+
attr_accessor :command
|
167
|
+
|
168
|
+
def self.descriptor_errors(c)
|
169
|
+
errors = []
|
170
|
+
|
171
|
+
# validate: h is a hash
|
172
|
+
errors << "The command descriptor is not a hash" unless c.is_a?(Hash)
|
173
|
+
|
174
|
+
# validate: the hash c has a key :command
|
175
|
+
errors << "The command descriptor does not have a key :command" unless c.has_key?(:command)
|
176
|
+
|
177
|
+
# validate: the value of c[:command] is a string or symbol
|
178
|
+
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)
|
179
|
+
|
180
|
+
# if the parameter h[:name] is a symbol
|
181
|
+
if c[:command].is_a?(Symbol)
|
182
|
+
if c[:command] == :reboot
|
183
|
+
# :reboot is a reserved word, so it is fine to call :reboot
|
184
|
+
else
|
185
|
+
# validate: existis a routine with a the value c[:command].to_s on its :name key
|
186
|
+
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
|
187
|
+
end
|
188
|
+
else
|
189
|
+
c[:command].strip.split("\n").each { |l|
|
190
|
+
l.strip!
|
191
|
+
}
|
192
|
+
end
|
193
|
+
|
194
|
+
#
|
195
|
+
errors.uniq
|
196
|
+
end # def self.descriptor_error(h)
|
197
|
+
|
198
|
+
def initialize(h)
|
199
|
+
errors = BlackStack::Deployer::CommandModule.descriptor_errors(h)
|
200
|
+
raise "The node descriptor is not valid: #{errors.uniq.join(".\n")}" if errors.length > 0
|
201
|
+
self.command = h[:command]
|
202
|
+
end # def initialize(h)
|
203
|
+
|
204
|
+
def to_hash
|
205
|
+
h = {}
|
206
|
+
h[:command] = self.command
|
207
|
+
h
|
208
|
+
end # def to_hash
|
209
|
+
|
210
|
+
# running pre-defined commands: :root
|
211
|
+
# calling to other routines: :'change-name'
|
212
|
+
# calling
|
213
|
+
def run(n, l=nil)
|
214
|
+
l = BlackStack::DummyLogger.new(nil) if l.nil?
|
215
|
+
|
216
|
+
# if self.command is a symbol
|
217
|
+
if self.command.is_a?(Symbol)
|
218
|
+
|
219
|
+
# if self.command is equel than :reboot
|
220
|
+
if self.command == :reboot
|
221
|
+
# call the n reboot method
|
222
|
+
n.reboot
|
223
|
+
else
|
224
|
+
# look for a routine with this name
|
225
|
+
r = BlackStack::Deployer.routines.select { |r| r.name == self.command.to_s }.first
|
226
|
+
if !r.nil?
|
227
|
+
r.run(n)
|
228
|
+
else
|
229
|
+
raise "The routine #{self.command.to_s} does not exist"
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# if self.command is a string
|
234
|
+
elsif self.command.is_a?(String)
|
235
|
+
s = self.command.dup
|
236
|
+
|
237
|
+
l.logs "Replacing merge-tags... "
|
238
|
+
s.scan(/%[a-zA-Z0-9\_]+%/).uniq.each do |p|
|
239
|
+
l.logs "Replacing #{p.blue}... "
|
240
|
+
if p == '%timestamp%' # reserved parameter
|
241
|
+
# TODO: move this to a timestamp function on blackstack-core
|
242
|
+
s.gsub!(p, Time.now.to_s.gsub(/\D/, ''))
|
243
|
+
else
|
244
|
+
if n.parameters.has_key?(p.gsub(/%/, '').to_sym)
|
245
|
+
s.gsub!(p, n.parameters[p.gsub(/%/, '').to_sym].to_s)
|
246
|
+
else
|
247
|
+
raise "The parameter #{p} does not exist in the node descriptor #{n.parameters.to_s}"
|
248
|
+
end
|
249
|
+
end
|
250
|
+
l.logf 'done'.green
|
251
|
+
end
|
252
|
+
l.logf 'done'.green
|
253
|
+
|
254
|
+
l.logs "Running command... "
|
255
|
+
n.ssh.exec!(s)
|
256
|
+
l.logf 'done'.green
|
257
|
+
end # elsif code.is_a?(String)
|
258
|
+
end # def run(n)
|
259
|
+
end # module CommandModule
|
260
|
+
|
261
|
+
# TODO: declare these classes (stub and skeleton) using blackstack-rpc
|
262
|
+
#
|
263
|
+
# Stub Classes
|
264
|
+
# These classes represents a node, without using connection to the database.
|
265
|
+
# Use this class at the client side.
|
266
|
+
class Node
|
267
|
+
include BlackStack::Deployer::NodeModule
|
268
|
+
end # class Node
|
269
|
+
|
270
|
+
class Command
|
271
|
+
include BlackStack::Deployer::CommandModule
|
272
|
+
end # class Command
|
273
|
+
|
274
|
+
class Routine
|
275
|
+
include BlackStack::Deployer::RoutineModule
|
276
|
+
end # class Routine
|
277
|
+
|
278
|
+
# add a node to the list of nodes.
|
279
|
+
def self.add_node(h)
|
280
|
+
errors = BlackStack::Deployer::NodeModule.descriptor_errors(h)
|
281
|
+
raise errors.join(".\n") unless errors.empty?
|
282
|
+
@@nodes << BlackStack::Deployer::Node.new(h)
|
283
|
+
end # def
|
284
|
+
|
285
|
+
# add an array of nodes to the list of nodes.
|
286
|
+
def self.add_nodes(a)
|
287
|
+
# validate: the parameter a is an array
|
288
|
+
raise "The parameter a is not an array" unless a.is_a?(Array)
|
289
|
+
a.each { |h| BlackStack::Deployer.add_node(h) }
|
290
|
+
end # def
|
291
|
+
|
292
|
+
# remove all exisiting nodes in he list of nodes.
|
293
|
+
# then, add the nodes in the parameter a to the list of nodes.
|
294
|
+
def self.set_nodes(a)
|
295
|
+
@@nodes.clear
|
296
|
+
BlackStack::Deployer.add_nodes(a)
|
297
|
+
end # def
|
298
|
+
|
299
|
+
# add a routine to the list of routines.
|
300
|
+
def self.add_routine(h)
|
301
|
+
errors = BlackStack::Deployer::RoutineModule.descriptor_errors(h)
|
302
|
+
raise errors.join(".\n") unless errors.empty?
|
303
|
+
@@routines << BlackStack::Deployer::Routine.new(h)
|
304
|
+
end # def
|
305
|
+
|
306
|
+
# add an array of routines to the list of routines.
|
307
|
+
def self.add_routines(a)
|
308
|
+
# validate: the parameter a is an array
|
309
|
+
raise "The parameter a is not an array" unless a.is_a?(Array)
|
310
|
+
a.each { |h| BlackStack::Deployer.add_routine(h) }
|
311
|
+
end # def
|
312
|
+
|
313
|
+
# remove all exisiting routines in he list of routines.
|
314
|
+
# then, add the routines in the parameter a to the list of routines.
|
315
|
+
def self.set_routines(a)
|
316
|
+
@@routines.clear
|
317
|
+
BlackStack::Deployer.add_routines(a)
|
318
|
+
end # def
|
319
|
+
|
320
|
+
# running a routine on a node
|
321
|
+
def self.run_routine(node_name, routine_name, l=nil)
|
322
|
+
l = BlackStack::DummyLogger.new(nil) if l.nil?
|
323
|
+
errors = []
|
324
|
+
|
325
|
+
# find the node with the value node_name in the key :name
|
326
|
+
n = @@nodes.select { |n| n.name == node_name }.first
|
327
|
+
|
328
|
+
# find the routine with the value routine_name in the key :name
|
329
|
+
r = @@routines.select { |r| r.name == routine_name }.first
|
330
|
+
|
331
|
+
# validate: the node n exists
|
332
|
+
errors << "Node #{node_name} not found" unless n
|
333
|
+
|
334
|
+
# validate: the routine r exists
|
335
|
+
errors << "Routine #{routine_name} not found" unless r
|
336
|
+
|
337
|
+
# raise exception if any error has been found
|
338
|
+
raise "The routine #{routine_name} cannot be run on the node #{node_name}: #{errors.uniq.join(".\n")}" if errors.length > 0
|
339
|
+
|
340
|
+
# connect the node
|
341
|
+
l.logs "Connecting to node #{n.name}... "
|
342
|
+
n.connect
|
343
|
+
l.done
|
344
|
+
|
345
|
+
# run the routine
|
346
|
+
l.logs "Running routine #{r.name}... "
|
347
|
+
r.run(n, l)
|
348
|
+
l.done
|
349
|
+
|
350
|
+
# disconnect the node
|
351
|
+
l.logs "Disconnecting from node #{n.name}... "
|
352
|
+
n.disconnect
|
353
|
+
l.done
|
354
|
+
end # def self.run_routine
|
355
|
+
|
356
|
+
module DB
|
357
|
+
LOCKFILE = './blackstack-deployer.lock'
|
358
|
+
@@checkpoint = nil
|
359
|
+
@@superhuser = nil
|
360
|
+
@@ndb = nil
|
361
|
+
@@folder = nil
|
362
|
+
|
363
|
+
def self.set_checkpoint(s)
|
364
|
+
@@checkpoint = s
|
365
|
+
end
|
366
|
+
|
367
|
+
def self.checkpoint
|
368
|
+
@@checkpoint
|
369
|
+
end
|
370
|
+
|
371
|
+
def self.save_checkpoint(lockfilename=BlackStack::Deployer::DB::LOCKFILE)
|
372
|
+
File.new(lockfilename, "w").write(@@checkpoint)
|
373
|
+
end
|
374
|
+
|
375
|
+
def self.load_checkpoint(lockfilename=BlackStack::Deployer::DB::LOCKFILE)
|
376
|
+
if File.exists?(lockfilename)
|
377
|
+
@@checkpoint = File.new(lockfilename, "r").read
|
378
|
+
else
|
379
|
+
@@checkpoint = nil
|
380
|
+
end
|
381
|
+
@@checkpoint
|
382
|
+
end
|
383
|
+
|
384
|
+
def self.connect(s)
|
385
|
+
@@db = Sequel::connect(s)
|
386
|
+
end # def
|
387
|
+
|
388
|
+
def self.set_folder(s)
|
389
|
+
@@folder = s
|
390
|
+
end # def
|
391
|
+
|
392
|
+
|
393
|
+
# 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.
|
394
|
+
# Otherwise, return `false`.
|
395
|
+
# This method should not be called directly by user code.
|
396
|
+
def self.is_transactions_file?(filename)
|
397
|
+
filename =~ /\.transactions\./ && filename !~ /\.sentences\./ && filename.scan(/\.transactions\./).size == 1
|
398
|
+
end
|
399
|
+
|
400
|
+
# 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.
|
401
|
+
# Otherwise({, return `false`.
|
402
|
+
# This method should not be called directly by user code.
|
403
|
+
def self.is_sentences_file?(filename)
|
404
|
+
filename =~ /\.sentences\./ && filename !~ /\.transactions\./ && filename.scan(/\.sentences\./).size == 1
|
405
|
+
end
|
406
|
+
|
407
|
+
# Method to process an `.sql` file with transactions code, separated by `BEGIN;` and `COMMIT;` statements.
|
408
|
+
# Reference: https://stackoverflow.com/questions/64066344/import-large-sql-files-with-ruby-sequel-gem
|
409
|
+
# This method is called by `BlackStack::Deployer::db_execute_file` if the filename matches with `/\.tsql\./`.
|
410
|
+
# This method should not be called directly by user code.
|
411
|
+
def self.execute_transactions(sql)
|
412
|
+
# TODO: Code Me!
|
413
|
+
end # def db_execute_tsql
|
414
|
+
|
415
|
+
# Method to process an `.sql` file with one sql sentence by line.
|
416
|
+
# Reference: https://stackoverflow.com/questions/64066344/import-large-sql-files-with-ruby-sequel-gem
|
417
|
+
# This method is called by `BlackStack::Deployer::db_execute_file` if the filename matches with `/\.sentences\./`.
|
418
|
+
# This method should not be called directly by user code.
|
419
|
+
def self.execute_sentences(sql, chunk_size=200, l=nil)
|
420
|
+
l = BlackStack::DummyLogger.new(nil) if l.nil?
|
421
|
+
|
422
|
+
# Fix issue: Ruby `split': invalid byte sequence in UTF-8 (ArgumentError)
|
423
|
+
# Reference: https://stackoverflow.com/questions/11065962/ruby-split-invalid-byte-sequence-in-utf-8-argumenterror
|
424
|
+
#
|
425
|
+
# Fix issue: `PG::SyntaxError: ERROR: at or near "��truncate": syntax error`
|
426
|
+
#
|
427
|
+
sql.encode!('UTF-8', :invalid => :replace, :replace => '')
|
428
|
+
|
429
|
+
# Remove null bytes to avoid error: `String contains null byte`
|
430
|
+
# Reference: https://stackoverflow.com/questions/29320369/coping-with-string-contains-null-byte-sent-from-users
|
431
|
+
sql.gsub!("\u0000", "")
|
432
|
+
|
433
|
+
# Get the array of sentences
|
434
|
+
l.logs "Splitting the sql sentences... "
|
435
|
+
sentences = sql.split(/;/i)
|
436
|
+
l.logf "done (#{sentences.size})"
|
437
|
+
|
438
|
+
# Chunk the array into parts of chunk_size elements
|
439
|
+
# Reference: https://stackoverflow.com/questions/2699584/how-to-split-chunk-a-ruby-array-into-parts-of-x-elements
|
440
|
+
l.logs "Bunlding the array of sentences into chunks of #{chunk_size} each... "
|
441
|
+
chunks = sentences.each_slice(chunk_size).to_a
|
442
|
+
l.logf "done (#{chunks.size})"
|
443
|
+
|
444
|
+
chunk_number = -1
|
445
|
+
chunks.each { |chunk|
|
446
|
+
chunk_number += 1
|
447
|
+
statement = chunk.join(";\n").to_s.strip
|
448
|
+
l.logs "lines #{chunk_size*chunk_number+1} to #{chunk_size*chunk_number+chunk.size} of #{sentences.size}... "
|
449
|
+
begin
|
450
|
+
@@db.execute(statement) #if statement.to_s.strip.size > 0
|
451
|
+
l.done
|
452
|
+
rescue => e
|
453
|
+
l.logf e.to_s
|
454
|
+
raise "Error executing statement: #{statement}\n#{e.message}"
|
455
|
+
end
|
456
|
+
}
|
457
|
+
l.done
|
458
|
+
end # def db_execute_sql_sentences_file
|
459
|
+
|
460
|
+
# Run a series of `.sql` files with updates to the database.
|
461
|
+
#
|
462
|
+
def self.deploy(save_checkpoints=false, lockfilename=BlackStack::Deployer::DB::LOCKFILE, l=nil)
|
463
|
+
l = BlackStack::DummyLogger.new(nil) if l.nil?
|
464
|
+
# get list of `.sql` files in the directory `sql_path`, with a name higher than `last_filename`, sorted by name.
|
465
|
+
Dir.entries(@@folder).select {
|
466
|
+
|filename| filename =~ /\.sql$/ && filename > @@checkpoint.to_s
|
467
|
+
}.uniq.sort.each { |filename|
|
468
|
+
fullfilename = "#{@@folder}/#{filename}"
|
469
|
+
|
470
|
+
l.logs "#{fullfilename}... "
|
471
|
+
BlackStack::Deployer::DB::execute_sentences( File.open(fullfilename).read )
|
472
|
+
l.done
|
473
|
+
|
474
|
+
l.logs "Updating checkpoint... "
|
475
|
+
BlackStack::Deployer::DB::set_checkpoint filename
|
476
|
+
l.done
|
477
|
+
|
478
|
+
l.logs 'Saving checkpoint... '
|
479
|
+
if save_checkpoints
|
480
|
+
BlackStack::Deployer::DB::save_checkpoint(lockfilename)
|
481
|
+
l.done
|
482
|
+
else
|
483
|
+
l.logf 'disabled'
|
484
|
+
end
|
485
|
+
}
|
486
|
+
end # def
|
487
|
+
end # module DB
|
488
|
+
|
489
|
+
# deploying all db-updates and run all routines on all nodes
|
490
|
+
def self.deploy(routine_name=nil, l=nil)
|
491
|
+
l = BlackStack::DummyLogger.new(nil) if l.nil?
|
492
|
+
|
493
|
+
@@nodes.each { |n|
|
494
|
+
l.logs "Node #{n.name}... "
|
495
|
+
n.deploy(routine_name, l)
|
496
|
+
l.done
|
497
|
+
}
|
498
|
+
end # def
|
499
|
+
|
500
|
+
end # module Deployer
|
501
|
+
|
502
|
+
end # module BlackStack
|
metadata
ADDED
@@ -0,0 +1,187 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: my-ruby-deployer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.3.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Leandro Daniel Sardi
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-09-18 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.12
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.2.12
|
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.12
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.2.12
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: pg
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 1.3.5
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 1.3.5
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 1.3.5
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 1.3.5
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: sequel
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - "~>"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: 5.56.0
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 5.56.0
|
63
|
+
type: :runtime
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 5.56.0
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: 5.56.0
|
73
|
+
- !ruby/object:Gem::Dependency
|
74
|
+
name: websocket
|
75
|
+
requirement: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - "~>"
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: 1.2.8
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.2.8
|
83
|
+
type: :runtime
|
84
|
+
prerelease: false
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 1.2.8
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: 1.2.8
|
93
|
+
- !ruby/object:Gem::Dependency
|
94
|
+
name: json
|
95
|
+
requirement: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - "~>"
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: 2.3.0
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: 2.3.0
|
103
|
+
type: :runtime
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - "~>"
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 2.3.0
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: 2.3.0
|
113
|
+
- !ruby/object:Gem::Dependency
|
114
|
+
name: colorize
|
115
|
+
requirement: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - "~>"
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: 0.8.1
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: 0.8.1
|
123
|
+
type: :runtime
|
124
|
+
prerelease: false
|
125
|
+
version_requirements: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - "~>"
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: 0.8.1
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: 0.8.1
|
133
|
+
- !ruby/object:Gem::Dependency
|
134
|
+
name: simple_cloud_logging
|
135
|
+
requirement: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - "~>"
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: 1.2.2
|
140
|
+
- - ">="
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: 1.2.2
|
143
|
+
type: :runtime
|
144
|
+
prerelease: false
|
145
|
+
version_requirements: !ruby/object:Gem::Requirement
|
146
|
+
requirements:
|
147
|
+
- - "~>"
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: 1.2.2
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 1.2.2
|
153
|
+
description: "Deployer automates what you already know how to do manually, but in
|
154
|
+
a repeatable, scalable fashion. There is no magic here!\nDeployer dutifully connects
|
155
|
+
to your server(s) via SSH and executes the steps necessary to deploy your project.
|
156
|
+
\nYou can define those steps yourself, or by using pre-built task libraries provided
|
157
|
+
by the Deployer community.\n "
|
158
|
+
email: leandro.sardi@expandedventure.com
|
159
|
+
executables: []
|
160
|
+
extensions: []
|
161
|
+
extra_rdoc_files: []
|
162
|
+
files:
|
163
|
+
- lib/my-ruby-deployer.rb
|
164
|
+
homepage: https://rubygems.org/gems/my-ruby-deployer
|
165
|
+
licenses:
|
166
|
+
- MIT
|
167
|
+
metadata: {}
|
168
|
+
post_install_message:
|
169
|
+
rdoc_options: []
|
170
|
+
require_paths:
|
171
|
+
- lib
|
172
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
173
|
+
requirements:
|
174
|
+
- - ">="
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
version: '0'
|
177
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
178
|
+
requirements:
|
179
|
+
- - ">="
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: '0'
|
182
|
+
requirements: []
|
183
|
+
rubygems_version: 3.3.7
|
184
|
+
signing_key:
|
185
|
+
specification_version: 4
|
186
|
+
summary: Deployer is a deployment automation tool built on Ruby and SSH.
|
187
|
+
test_files: []
|