etch 4.0.0 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Rakefile +7 -8
- data/lib/etch.rb +959 -399
- data/lib/etch/client.rb +265 -335
- metadata +12 -16
data/lib/etch/client.rb
CHANGED
@@ -29,7 +29,6 @@ Silently.silently do
|
|
29
29
|
require 'uri'
|
30
30
|
require 'net/http'
|
31
31
|
require 'net/https'
|
32
|
-
require 'rexml/document'
|
33
32
|
require 'fileutils' # copy, mkpath, rmtree
|
34
33
|
require 'fcntl' # Fcntl::O_*
|
35
34
|
require 'etc' # getpwnam, getgrnam
|
@@ -42,7 +41,7 @@ end
|
|
42
41
|
require 'etch'
|
43
42
|
|
44
43
|
class Etch::Client
|
45
|
-
VERSION = '
|
44
|
+
VERSION = '5.0.0'
|
46
45
|
|
47
46
|
CONFIRM_PROCEED = 1
|
48
47
|
CONFIRM_SKIP = 2
|
@@ -228,12 +227,6 @@ class Etch::Client
|
|
228
227
|
puts "Connecting to #{@filesuri}" if (@debug)
|
229
228
|
http = Net::HTTP.new(@filesuri.host, @filesuri.port)
|
230
229
|
if @filesuri.scheme == "https"
|
231
|
-
# Eliminate the OpenSSL "using default DH parameters" warning
|
232
|
-
if File.exist?(File.join(@configdir, 'etch', 'dhparams'))
|
233
|
-
dh = OpenSSL::PKey::DH.new(IO.read(File.join(@configdir, 'etch', 'dhparams')))
|
234
|
-
Net::HTTP.ssl_context_accessor(:tmp_dh_callback)
|
235
|
-
http.tmp_dh_callback = proc { dh }
|
236
|
-
end
|
237
230
|
http.use_ssl = true
|
238
231
|
if File.exist?(File.join(@configdir, 'etch', 'ca.pem'))
|
239
232
|
http.ca_file = File.join(@configdir, 'etch', 'ca.pem')
|
@@ -286,10 +279,8 @@ class Etch::Client
|
|
286
279
|
files.each do |file|
|
287
280
|
request["files[#{CGI.escape(file)}][sha1sum]"] =
|
288
281
|
get_orig_sum(file)
|
289
|
-
|
290
|
-
|
291
|
-
request["files[#{CGI.escape(file)}][local_requests]"] =
|
292
|
-
local_requests
|
282
|
+
get_local_requests(file).each_with_index do |lr, i|
|
283
|
+
request["files[#{CGI.escape(file)}][local_requests][#{i}]"] = lr
|
293
284
|
end
|
294
285
|
end
|
295
286
|
end
|
@@ -325,84 +316,43 @@ class Etch::Client
|
|
325
316
|
# Send request to server
|
326
317
|
#
|
327
318
|
|
328
|
-
responsedata = {}
|
329
319
|
if @local
|
330
|
-
|
331
|
-
# FIXME: Etch#generate returns parsed XML using whatever XML
|
332
|
-
# library it happens to use. In order to avoid re-parsing
|
333
|
-
# the XML we'd have to use the XML abstraction code from Etch
|
334
|
-
# everwhere here.
|
335
|
-
# Until then re-parse the XML using REXML.
|
336
|
-
#responsedata[:configs] = results[:configs]
|
337
|
-
responsedata[:configs] = {}
|
338
|
-
results[:configs].each {|f,c| responsedata[:configs][f] = REXML::Document.new(c.to_s) }
|
339
|
-
responsedata[:need_sums] = {}
|
340
|
-
responsedata[:need_origs] = results[:need_orig]
|
341
|
-
#responsedata[:allcommands] = results[:allcommands]
|
342
|
-
responsedata[:allcommands] = {}
|
343
|
-
results[:allcommands].each {|cn,c| responsedata[:allcommands][cn] = REXML::Document.new(c.to_s) }
|
344
|
-
responsedata[:retrycommands] = results[:retrycommands]
|
320
|
+
response = @etch.generate(@local, @facts, request)
|
345
321
|
else
|
346
322
|
puts "Sending request to server #{@filesuri}: #{request.inspect}" if (@debug)
|
347
323
|
post = Net::HTTP::Post.new(@filesuri.path)
|
348
324
|
post.set_form_data(request)
|
325
|
+
post['Accept'] = 'application/x-yaml'
|
349
326
|
sign_post!(post, @key)
|
350
|
-
|
351
|
-
if !
|
352
|
-
$stderr.puts
|
327
|
+
httpresponse = http.request(post)
|
328
|
+
if !httpresponse.kind_of?(Net::HTTPSuccess)
|
329
|
+
$stderr.puts httpresponse.body
|
353
330
|
# error! raises an exception
|
354
|
-
|
355
|
-
end
|
356
|
-
puts "Response from server:\n'#{
|
357
|
-
if
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
file = config.attributes['filename']
|
362
|
-
# We have to make a new document so that XPath paths are
|
363
|
-
# referenced relative to the configuration for this
|
364
|
-
# specific file.
|
365
|
-
#responsedata[:configs][file] = REXML::Document.new(response_xml.elements["/files/configs/config[@filename='#{file}']"].to_s)
|
366
|
-
responsedata[:configs][file] = REXML::Document.new(config.to_s)
|
367
|
-
end
|
368
|
-
responsedata[:need_sums] = {}
|
369
|
-
response_xml.elements.each('/files/need_sums/need_sum') do |ns|
|
370
|
-
responsedata[:need_sums][ns.text] = true
|
371
|
-
end
|
372
|
-
responsedata[:need_origs] = {}
|
373
|
-
response_xml.elements.each('/files/need_origs/need_orig') do |no|
|
374
|
-
responsedata[:need_origs][no.text] = true
|
375
|
-
end
|
376
|
-
responsedata[:allcommands] = {}
|
377
|
-
response_xml.elements.each('/files/allcommands/commands') do |command|
|
378
|
-
commandname = command.attributes['commandname']
|
379
|
-
# We have to make a new document so that XPath paths are
|
380
|
-
# referenced relative to the configuration for this
|
381
|
-
# specific file.
|
382
|
-
#responsedata[:allcommands][commandname] = REXML::Document.new(response_xml.root.elements["/files/allcommands/commands[@commandname='#{commandname}']"].to_s)
|
383
|
-
responsedata[:allcommands][commandname] = REXML::Document.new(command.to_s)
|
384
|
-
end
|
385
|
-
responsedata[:retrycommands] = {}
|
386
|
-
response_xml.elements.each('/files/retrycommands/retrycommand') do |rc|
|
387
|
-
responsedata[:retrycommands][rc.text] = true
|
388
|
-
end
|
389
|
-
else
|
331
|
+
httpresponse.error!
|
332
|
+
end
|
333
|
+
puts "Response from server:\n'#{httpresponse.body}'" if (@debug)
|
334
|
+
if httpresponse['Content-Type'].split(';').first != 'application/x-yaml'
|
335
|
+
raise "MIME type #{httpresponse['Content-Type']} is not yaml"
|
336
|
+
end
|
337
|
+
if httpresponse.body.nil? || httpresponse.body.empty?
|
390
338
|
puts " Response is empty" if (@debug)
|
391
339
|
break
|
392
340
|
end
|
341
|
+
response = YAML.load(httpresponse.body)
|
393
342
|
end
|
394
343
|
|
395
344
|
#
|
396
345
|
# Process the response from the server
|
397
346
|
#
|
398
347
|
|
399
|
-
# Prep a clean request hash
|
348
|
+
# Prep a clean request hash in case we need to make a
|
349
|
+
# followup request
|
400
350
|
if @local
|
401
351
|
request = {}
|
402
|
-
if !
|
352
|
+
if response[:need_orig] && !response[:need_orig].empty?
|
403
353
|
request[:files] = {}
|
404
354
|
end
|
405
|
-
if !
|
355
|
+
if response[:retrycommands] && !response[:retrycommands].empty?
|
406
356
|
request[:commands] = {}
|
407
357
|
end
|
408
358
|
else
|
@@ -418,10 +368,10 @@ class Etch::Client
|
|
418
368
|
reset_already_processed
|
419
369
|
# Process configs first, as they may contain setup entries that are
|
420
370
|
# needed to create the original files.
|
421
|
-
|
371
|
+
response[:configs].each_key do |file|
|
422
372
|
puts "Processing config for #{file}" if (@debug)
|
423
373
|
if !@listfiles
|
424
|
-
continue_processing = process_file(file,
|
374
|
+
continue_processing = process_file(file, response)
|
425
375
|
if !continue_processing
|
426
376
|
throw :stop_processing
|
427
377
|
end
|
@@ -429,7 +379,7 @@ class Etch::Client
|
|
429
379
|
files_to_list[file] = true
|
430
380
|
end
|
431
381
|
end
|
432
|
-
|
382
|
+
response[:need_sum] && response[:need_sum].each do |need_sum|
|
433
383
|
puts "Processing request for sum of #{need_sum}" if (@debug)
|
434
384
|
if @local
|
435
385
|
# If this happens we screwed something up, the local mode
|
@@ -444,13 +394,14 @@ class Etch::Client
|
|
444
394
|
if @local
|
445
395
|
request[:files][need_sum][:local_requests] = local_requests
|
446
396
|
else
|
447
|
-
|
448
|
-
local_requests
|
397
|
+
local_requests.each_with_index do |lr, i|
|
398
|
+
request["files[#{CGI.escape(need_sum)}][local_requests][#{i}]"] = lr
|
399
|
+
end
|
449
400
|
end
|
450
401
|
end
|
451
402
|
need_to_loop = true
|
452
403
|
end
|
453
|
-
|
404
|
+
response[:need_orig] && response[:need_orig].each do |need_orig|
|
454
405
|
puts "Processing request for contents of #{need_orig}" if (@debug)
|
455
406
|
if @local
|
456
407
|
request[:files][need_orig] = {:orig => save_orig(need_orig)}
|
@@ -465,20 +416,21 @@ class Etch::Client
|
|
465
416
|
if @local
|
466
417
|
request[:files][need_orig][:local_requests] = local_requests
|
467
418
|
else
|
468
|
-
|
469
|
-
local_requests
|
419
|
+
local_requests.each_with_index do |lr, i|
|
420
|
+
request["files[#{CGI.escape(need_orig)}][local_requests][#{i}]"] = lr
|
421
|
+
end
|
470
422
|
end
|
471
423
|
end
|
472
424
|
need_to_loop = true
|
473
425
|
end
|
474
|
-
|
426
|
+
response[:commands] && response[:commands].each_key do |commandname|
|
475
427
|
puts "Processing commands #{commandname}" if (@debug)
|
476
|
-
continue_processing = process_commands(commandname,
|
428
|
+
continue_processing = process_commands(commandname, response)
|
477
429
|
if !continue_processing
|
478
430
|
throw :stop_processing
|
479
431
|
end
|
480
432
|
end
|
481
|
-
|
433
|
+
response[:retrycommands] && response[:retrycommands].each_key do |commandname|
|
482
434
|
puts "Processing request to retry command #{commandname}" if (@debug)
|
483
435
|
if @local
|
484
436
|
request[:commands][commandname] = true
|
@@ -598,7 +550,7 @@ class Etch::Client
|
|
598
550
|
# Raises an exception if any fatal error is encountered
|
599
551
|
# Returns a boolean, true unless the user indicated in interactive mode
|
600
552
|
# that further processing should be halted
|
601
|
-
def process_file(file,
|
553
|
+
def process_file(file, response)
|
602
554
|
continue_processing = true
|
603
555
|
save_results = true
|
604
556
|
exception = nil
|
@@ -606,7 +558,7 @@ class Etch::Client
|
|
606
558
|
# We may not have configuration for this file, if it does not apply
|
607
559
|
# to this host. The server takes care of detecting any errors that
|
608
560
|
# might involve, so here we can just silently return.
|
609
|
-
config =
|
561
|
+
config = response[:configs][file]
|
610
562
|
if !config
|
611
563
|
puts "No configuration for #{file}, skipping" if (@debug)
|
612
564
|
return continue_processing
|
@@ -651,18 +603,18 @@ class Etch::Client
|
|
651
603
|
lock_file(file)
|
652
604
|
|
653
605
|
# Process any other files that this file depends on
|
654
|
-
config.
|
655
|
-
puts "Processing dependency #{depend
|
656
|
-
continue_processing = process_file(depend
|
606
|
+
config[:depend] && config[:depend].each do |depend|
|
607
|
+
puts "Processing dependency #{depend}" if (@debug)
|
608
|
+
continue_processing = process_file(depend, response)
|
657
609
|
if !continue_processing
|
658
610
|
throw :process_done
|
659
611
|
end
|
660
612
|
end
|
661
613
|
|
662
614
|
# Process any commands that this file depends on
|
663
|
-
config.
|
664
|
-
puts "Processing command dependency #{dependcommand
|
665
|
-
continue_processing = process_commands(dependcommand
|
615
|
+
config[:dependcommand] && config[:dependcommand].each do |dependcommand|
|
616
|
+
puts "Processing command dependency #{dependcommand}" if (@debug)
|
617
|
+
continue_processing = process_commands(dependcommand, response)
|
666
618
|
if !continue_processing
|
667
619
|
throw :process_done
|
668
620
|
end
|
@@ -672,7 +624,7 @@ class Etch::Client
|
|
672
624
|
|
673
625
|
# Check to see if the user has requested that we revert back to the
|
674
626
|
# original file.
|
675
|
-
if config
|
627
|
+
if config[:revert]
|
676
628
|
origpathbase = File.join(@origbase, file)
|
677
629
|
origpath = nil
|
678
630
|
|
@@ -729,20 +681,18 @@ class Etch::Client
|
|
729
681
|
# install a package containing a sample config file which we
|
730
682
|
# then edit with a script, and thus doing the install in <pre>
|
731
683
|
# is too late.
|
732
|
-
|
733
|
-
process_setup(file, config)
|
734
|
-
end
|
684
|
+
process_setup(file, config)
|
735
685
|
|
736
|
-
if config
|
686
|
+
if config[:file] # Regular file
|
737
687
|
newcontents = nil
|
738
|
-
if config
|
739
|
-
newcontents = Base64.decode64(config
|
688
|
+
if config[:file][:contents]
|
689
|
+
newcontents = Base64.decode64(config[:file][:contents])
|
740
690
|
end
|
741
691
|
|
742
|
-
permstring = config
|
692
|
+
permstring = config[:file][:perms].to_s
|
743
693
|
perms = permstring.oct
|
744
|
-
owner = config
|
745
|
-
group = config
|
694
|
+
owner = config[:file][:owner]
|
695
|
+
group = config[:file][:group]
|
746
696
|
uid = lookup_uid(owner)
|
747
697
|
gid = lookup_gid(group)
|
748
698
|
|
@@ -804,7 +754,12 @@ class Etch::Client
|
|
804
754
|
# Default is to show a diff of the current file and the
|
805
755
|
# newly generated file.
|
806
756
|
puts "Will make the following changes to #{file}, diff -c:"
|
807
|
-
tempfile =
|
757
|
+
tempfile = nil
|
758
|
+
if RUBY_VERSION.split('.')[0..1].join('.').to_f >= 1.9
|
759
|
+
tempfile = Tempfile.new(File.basename(file), :encoding => 'ASCII-8BIT')
|
760
|
+
else
|
761
|
+
tempfile = Tempfile.new(File.basename(file))
|
762
|
+
end
|
808
763
|
tempfile.write(newcontents)
|
809
764
|
tempfile.close
|
810
765
|
puts "============================================="
|
@@ -848,9 +803,7 @@ class Etch::Client
|
|
848
803
|
end
|
849
804
|
|
850
805
|
# Perform any pre-action commands that the user has requested
|
851
|
-
|
852
|
-
process_pre(file, config)
|
853
|
-
end
|
806
|
+
process_pre(file, config)
|
854
807
|
|
855
808
|
# If the original "file" is a directory and the user hasn't
|
856
809
|
# specifically told us we can overwrite it then raise an exception.
|
@@ -860,7 +813,7 @@ class Etch::Client
|
|
860
813
|
# originals which are directories. So we don't check until
|
861
814
|
# after any pre commands are run.
|
862
815
|
if File.directory?(file) && !File.symlink?(file) &&
|
863
|
-
!config
|
816
|
+
!config[:file][:overwrite_directory]
|
864
817
|
raise "Can't proceed, original of #{file} is a directory,\n" +
|
865
818
|
" consider the overwrite_directory flag if appropriate."
|
866
819
|
end
|
@@ -883,8 +836,7 @@ class Etch::Client
|
|
883
836
|
# only use the backup to roll back if the test fails), so don't
|
884
837
|
# bother to create a backup unless there is a test command defined.
|
885
838
|
backup = nil
|
886
|
-
if config
|
887
|
-
config.elements['/config/test']
|
839
|
+
if config[:test_before_post] || config[:test]
|
888
840
|
backup = make_backup(file)
|
889
841
|
puts "Created backup #{backup}"
|
890
842
|
end
|
@@ -896,7 +848,12 @@ class Etch::Client
|
|
896
848
|
# Write out the new contents into a temporary file
|
897
849
|
filebase = File.basename(file)
|
898
850
|
filedir = File.dirname(file)
|
899
|
-
newfile =
|
851
|
+
newfile = nil
|
852
|
+
if RUBY_VERSION.split('.')[0..1].join('.').to_f >= 1.9
|
853
|
+
newfile = Tempfile.new(filebase, filedir, :encoding => 'ASCII-8BIT')
|
854
|
+
else
|
855
|
+
newfile = Tempfile.new(filebase, filedir)
|
856
|
+
end
|
900
857
|
|
901
858
|
# Set the proper permissions on the file before putting
|
902
859
|
# data into it.
|
@@ -944,33 +901,26 @@ class Etch::Client
|
|
944
901
|
end
|
945
902
|
|
946
903
|
# Perform any test_before_post commands that the user has requested
|
947
|
-
if config
|
948
|
-
|
949
|
-
|
950
|
-
raise "test_before_post failed"
|
951
|
-
end
|
904
|
+
if !process_test_before_post(file, config)
|
905
|
+
restore_backup(file, backup)
|
906
|
+
raise "test_before_post failed"
|
952
907
|
end
|
953
908
|
|
954
909
|
# Perform any post-action commands that the user has requested
|
955
|
-
|
956
|
-
process_post(file, config)
|
957
|
-
end
|
910
|
+
process_post(file, config)
|
958
911
|
|
959
912
|
# Perform any test commands that the user has requested
|
960
|
-
if config
|
913
|
+
if config[:test]
|
961
914
|
if !process_test(file, config)
|
962
915
|
restore_backup(file, backup)
|
963
916
|
|
964
917
|
# Re-run any post commands
|
965
|
-
|
966
|
-
process_post(file, config)
|
967
|
-
end
|
918
|
+
process_post(file, config)
|
968
919
|
end
|
969
920
|
end
|
970
921
|
|
971
922
|
# Clean up the backup, we don't need it anymore
|
972
|
-
if config
|
973
|
-
config.elements['/config/test']
|
923
|
+
if config[:test_before_post] || config[:test]
|
974
924
|
puts "Removing backup #{backup}"
|
975
925
|
remove_file(backup) if (!@dryrun)
|
976
926
|
end
|
@@ -982,29 +932,29 @@ class Etch::Client
|
|
982
932
|
end
|
983
933
|
end
|
984
934
|
|
985
|
-
if config
|
935
|
+
if config[:link] # Symbolic link
|
986
936
|
|
987
|
-
dest = config
|
937
|
+
dest = config[:link][:dest]
|
988
938
|
|
989
939
|
set_link_destination = !compare_link_destination(file, dest)
|
990
940
|
absdest = File.expand_path(dest, File.dirname(file))
|
991
941
|
|
992
|
-
permstring = config
|
942
|
+
permstring = config[:link][:perms].to_s
|
993
943
|
perms = permstring.oct
|
994
|
-
owner = config
|
995
|
-
group = config
|
944
|
+
owner = config[:link][:owner]
|
945
|
+
group = config[:link][:group]
|
996
946
|
uid = lookup_uid(owner)
|
997
947
|
gid = lookup_gid(group)
|
998
948
|
|
999
949
|
# lchown and lchmod are not supported on many platforms. The server
|
1000
950
|
# always includes ownership and permissions settings with any link
|
1001
|
-
# (pulling them from defaults
|
1002
|
-
# the config
|
951
|
+
# (pulling them from defaults if the user didn't specify them in
|
952
|
+
# the config file.) As such link management would always fail
|
1003
953
|
# on systems which don't support lchown/lchmod, which seems like bad
|
1004
954
|
# behavior. So instead we check to see if they are implemented, and
|
1005
955
|
# if not just ignore ownership/permissions settings. I suppose the
|
1006
956
|
# ideal would be for the server to tell the client whether the
|
1007
|
-
# ownership/permissions were specifically requested (in config
|
957
|
+
# ownership/permissions were specifically requested (in the config)
|
1008
958
|
# rather than just defaults, and then for the client to always try to
|
1009
959
|
# manage ownership/permissions if the settings are not defaults (and
|
1010
960
|
# fail in the event that they aren't implemented.)
|
@@ -1077,7 +1027,7 @@ class Etch::Client
|
|
1077
1027
|
# expand_path should handle paths that are already absolute
|
1078
1028
|
# properly.
|
1079
1029
|
elsif ! File.exist?(absdest) && ! File.symlink?(absdest) &&
|
1080
|
-
! config
|
1030
|
+
! config[:link][:allow_nonexistent_dest]
|
1081
1031
|
puts "Destination #{dest} for link #{file} does not exist," +
|
1082
1032
|
" consider the allow_nonexistent_dest flag if appropriate."
|
1083
1033
|
throw :process_done
|
@@ -1112,9 +1062,7 @@ class Etch::Client
|
|
1112
1062
|
end
|
1113
1063
|
|
1114
1064
|
# Perform any pre-action commands that the user has requested
|
1115
|
-
|
1116
|
-
process_pre(file, config)
|
1117
|
-
end
|
1065
|
+
process_pre(file, config)
|
1118
1066
|
|
1119
1067
|
# If the original "file" is a directory and the user hasn't
|
1120
1068
|
# specifically told us we can overwrite it then raise an exception.
|
@@ -1124,7 +1072,7 @@ class Etch::Client
|
|
1124
1072
|
# originals which are directories. So we don't check until
|
1125
1073
|
# after any pre commands are run.
|
1126
1074
|
if File.directory?(file) && !File.symlink?(file) &&
|
1127
|
-
!config
|
1075
|
+
!config[:link][:overwrite_directory]
|
1128
1076
|
raise "Can't proceed, original of #{file} is a directory,\n" +
|
1129
1077
|
" consider the overwrite_directory flag if appropriate."
|
1130
1078
|
end
|
@@ -1147,8 +1095,7 @@ class Etch::Client
|
|
1147
1095
|
# only use the backup to roll back if the test fails), so don't
|
1148
1096
|
# bother to create a backup unless there is a test command defined.
|
1149
1097
|
backup = nil
|
1150
|
-
if config
|
1151
|
-
config.elements['/config/test']
|
1098
|
+
if config[:test_before_post] || config[:test]
|
1152
1099
|
backup = make_backup(file)
|
1153
1100
|
puts "Created backup #{backup}"
|
1154
1101
|
end
|
@@ -1185,33 +1132,26 @@ class Etch::Client
|
|
1185
1132
|
end
|
1186
1133
|
|
1187
1134
|
# Perform any test_before_post commands that the user has requested
|
1188
|
-
if config
|
1189
|
-
|
1190
|
-
|
1191
|
-
raise "test_before_post failed"
|
1192
|
-
end
|
1135
|
+
if !process_test_before_post(file, config)
|
1136
|
+
restore_backup(file, backup)
|
1137
|
+
raise "test_before_post failed"
|
1193
1138
|
end
|
1194
1139
|
|
1195
1140
|
# Perform any post-action commands that the user has requested
|
1196
|
-
|
1197
|
-
process_post(file, config)
|
1198
|
-
end
|
1141
|
+
process_post(file, config)
|
1199
1142
|
|
1200
1143
|
# Perform any test commands that the user has requested
|
1201
|
-
if config
|
1144
|
+
if config[:test]
|
1202
1145
|
if !process_test(file, config)
|
1203
1146
|
restore_backup(file, backup)
|
1204
1147
|
|
1205
1148
|
# Re-run any post commands
|
1206
|
-
|
1207
|
-
process_post(file, config)
|
1208
|
-
end
|
1149
|
+
process_post(file, config)
|
1209
1150
|
end
|
1210
1151
|
end
|
1211
1152
|
|
1212
1153
|
# Clean up the backup, we don't need it anymore
|
1213
|
-
if config
|
1214
|
-
config.elements['/config/test']
|
1154
|
+
if config[:test_before_post] || config[:test]
|
1215
1155
|
puts "Removing backup #{backup}"
|
1216
1156
|
remove_file(backup) if (!@dryrun)
|
1217
1157
|
end
|
@@ -1223,16 +1163,17 @@ class Etch::Client
|
|
1223
1163
|
end
|
1224
1164
|
end
|
1225
1165
|
|
1226
|
-
if config
|
1166
|
+
if config[:directory] # Directory
|
1227
1167
|
|
1228
1168
|
# A little safety check
|
1229
|
-
|
1230
|
-
|
1169
|
+
if !config[:directory][:create]
|
1170
|
+
raise "No create element found in directory section"
|
1171
|
+
end
|
1231
1172
|
|
1232
|
-
permstring = config
|
1173
|
+
permstring = config[:directory][:perms].to_s
|
1233
1174
|
perms = permstring.oct
|
1234
|
-
owner = config
|
1235
|
-
group = config
|
1175
|
+
owner = config[:directory][:owner]
|
1176
|
+
group = config[:directory][:group]
|
1236
1177
|
uid = lookup_uid(owner)
|
1237
1178
|
gid = lookup_gid(group)
|
1238
1179
|
|
@@ -1291,9 +1232,7 @@ class Etch::Client
|
|
1291
1232
|
end
|
1292
1233
|
|
1293
1234
|
# Perform any pre-action commands that the user has requested
|
1294
|
-
|
1295
|
-
process_pre(file, config)
|
1296
|
-
end
|
1235
|
+
process_pre(file, config)
|
1297
1236
|
|
1298
1237
|
# Give save_orig a definitive answer on whether or not to save the
|
1299
1238
|
# contents of an original directory.
|
@@ -1313,8 +1252,7 @@ class Etch::Client
|
|
1313
1252
|
# only use the backup to roll back if the test fails), so don't
|
1314
1253
|
# bother to create a backup unless there is a test command defined.
|
1315
1254
|
backup = nil
|
1316
|
-
if config
|
1317
|
-
config.elements['/config/test']
|
1255
|
+
if config[:test_before_post] || config[:test]
|
1318
1256
|
backup = make_backup(file)
|
1319
1257
|
puts "Created backup #{backup}"
|
1320
1258
|
end
|
@@ -1345,33 +1283,26 @@ class Etch::Client
|
|
1345
1283
|
end
|
1346
1284
|
|
1347
1285
|
# Perform any test_before_post commands that the user has requested
|
1348
|
-
if config
|
1349
|
-
|
1350
|
-
|
1351
|
-
raise "test_before_post failed"
|
1352
|
-
end
|
1286
|
+
if !process_test_before_post(file, config)
|
1287
|
+
restore_backup(file, backup)
|
1288
|
+
raise "test_before_post failed"
|
1353
1289
|
end
|
1354
1290
|
|
1355
1291
|
# Perform any post-action commands that the user has requested
|
1356
|
-
|
1357
|
-
process_post(file, config)
|
1358
|
-
end
|
1292
|
+
process_post(file, config)
|
1359
1293
|
|
1360
1294
|
# Perform any test commands that the user has requested
|
1361
|
-
if config
|
1295
|
+
if config[:test]
|
1362
1296
|
if !process_test(file, config)
|
1363
1297
|
restore_backup(file, backup)
|
1364
1298
|
|
1365
1299
|
# Re-run any post commands
|
1366
|
-
|
1367
|
-
process_post(file, config)
|
1368
|
-
end
|
1300
|
+
process_post(file, config)
|
1369
1301
|
end
|
1370
1302
|
end
|
1371
1303
|
|
1372
1304
|
# Clean up the backup, we don't need it anymore
|
1373
|
-
if config
|
1374
|
-
config.elements['/config/test']
|
1305
|
+
if config[:test_before_post] || config[:test]
|
1375
1306
|
puts "Removing backup #{backup}"
|
1376
1307
|
remove_file(backup) if (!@dryrun)
|
1377
1308
|
end
|
@@ -1383,11 +1314,12 @@ class Etch::Client
|
|
1383
1314
|
end
|
1384
1315
|
end
|
1385
1316
|
|
1386
|
-
if config
|
1317
|
+
if config[:delete] # Delete whatever is there
|
1387
1318
|
|
1388
1319
|
# A little safety check
|
1389
|
-
|
1390
|
-
|
1320
|
+
if !config[:delete][:proceed]
|
1321
|
+
raise "No proceed element found in delete section"
|
1322
|
+
end
|
1391
1323
|
|
1392
1324
|
# Proceed only if the file currently exists
|
1393
1325
|
if !File.exist?(file) && !File.symlink?(file)
|
@@ -1415,9 +1347,7 @@ class Etch::Client
|
|
1415
1347
|
end
|
1416
1348
|
|
1417
1349
|
# Perform any pre-action commands that the user has requested
|
1418
|
-
|
1419
|
-
process_pre(file, config)
|
1420
|
-
end
|
1350
|
+
process_pre(file, config)
|
1421
1351
|
|
1422
1352
|
# If the original "file" is a directory and the user hasn't
|
1423
1353
|
# specifically told us we can overwrite it then raise an exception.
|
@@ -1427,7 +1357,7 @@ class Etch::Client
|
|
1427
1357
|
# originals which are directories. So we don't check until
|
1428
1358
|
# after any pre commands are run.
|
1429
1359
|
if File.directory?(file) && !File.symlink?(file) &&
|
1430
|
-
!config
|
1360
|
+
!config[:delete][:overwrite_directory]
|
1431
1361
|
raise "Can't proceed, original of #{file} is a directory,\n" +
|
1432
1362
|
" consider the overwrite_directory flag if appropriate."
|
1433
1363
|
end
|
@@ -1443,8 +1373,7 @@ class Etch::Client
|
|
1443
1373
|
# only use the backup to roll back if the test fails), so don't
|
1444
1374
|
# bother to create a backup unless there is a test command defined.
|
1445
1375
|
backup = nil
|
1446
|
-
if config
|
1447
|
-
config.elements['/config/test']
|
1376
|
+
if config[:test_before_post] || config[:test]
|
1448
1377
|
backup = make_backup(file)
|
1449
1378
|
puts "Created backup #{backup}"
|
1450
1379
|
end
|
@@ -1453,33 +1382,26 @@ class Etch::Client
|
|
1453
1382
|
remove_file(file) if (!@dryrun)
|
1454
1383
|
|
1455
1384
|
# Perform any test_before_post commands that the user has requested
|
1456
|
-
if config
|
1457
|
-
|
1458
|
-
|
1459
|
-
raise "test_before_post failed"
|
1460
|
-
end
|
1385
|
+
if !process_test_before_post(file, config)
|
1386
|
+
restore_backup(file, backup)
|
1387
|
+
raise "test_before_post failed"
|
1461
1388
|
end
|
1462
1389
|
|
1463
1390
|
# Perform any post-action commands that the user has requested
|
1464
|
-
|
1465
|
-
process_post(file, config)
|
1466
|
-
end
|
1391
|
+
process_post(file, config)
|
1467
1392
|
|
1468
1393
|
# Perform any test commands that the user has requested
|
1469
|
-
if config
|
1394
|
+
if config[:test]
|
1470
1395
|
if !process_test(file, config)
|
1471
1396
|
restore_backup(file, backup)
|
1472
1397
|
|
1473
1398
|
# Re-run any post commands
|
1474
|
-
|
1475
|
-
process_post(file, config)
|
1476
|
-
end
|
1399
|
+
process_post(file, config)
|
1477
1400
|
end
|
1478
1401
|
end
|
1479
1402
|
|
1480
1403
|
# Clean up the backup, we don't need it anymore
|
1481
|
-
if config
|
1482
|
-
config.elements['/config/test']
|
1404
|
+
if config[:test_before_post] || config[:test]
|
1483
1405
|
puts "Removing backup #{backup}"
|
1484
1406
|
remove_file(backup) if (!@dryrun)
|
1485
1407
|
end
|
@@ -1520,7 +1442,7 @@ class Etch::Client
|
|
1520
1442
|
# Raises an exception if any fatal error is encountered
|
1521
1443
|
# Returns a boolean, true unless the user indicated in interactive mode
|
1522
1444
|
# that further processing should be halted
|
1523
|
-
def process_commands(commandname,
|
1445
|
+
def process_commands(commandname, response)
|
1524
1446
|
continue_processing = true
|
1525
1447
|
save_results = true
|
1526
1448
|
exception = nil
|
@@ -1528,7 +1450,7 @@ class Etch::Client
|
|
1528
1450
|
# We may not have configuration for this file, if it does not apply
|
1529
1451
|
# to this host. The server takes care of detecting any errors that
|
1530
1452
|
# might involve, so here we can just silently return.
|
1531
|
-
command =
|
1453
|
+
command = response[:commands][commandname]
|
1532
1454
|
if !command
|
1533
1455
|
puts "No configuration for command #{commandname}, skipping" if (@debug)
|
1534
1456
|
return continue_processing
|
@@ -1573,60 +1495,67 @@ class Etch::Client
|
|
1573
1495
|
lock_file(commandname)
|
1574
1496
|
|
1575
1497
|
# Process any other commands that this command depends on
|
1576
|
-
command.
|
1577
|
-
puts "Processing command dependency #{depend
|
1578
|
-
continue_processing = process_commands(depend
|
1498
|
+
command[:depend] && command[:depend].each do |depend|
|
1499
|
+
puts "Processing command dependency #{depend}" if (@debug)
|
1500
|
+
continue_processing = process_commands(depend, response)
|
1579
1501
|
if !continue_processing
|
1580
1502
|
throw :process_done
|
1581
1503
|
end
|
1582
1504
|
end
|
1583
1505
|
|
1584
1506
|
# Process any files that this command depends on
|
1585
|
-
command.
|
1586
|
-
puts "Processing file dependency #{dependfile
|
1587
|
-
continue_processing = process_file(dependfile
|
1507
|
+
command[:dependfile] && command[:dependfile].each do |dependfile|
|
1508
|
+
puts "Processing file dependency #{dependfile}" if (@debug)
|
1509
|
+
continue_processing = process_file(dependfile, response)
|
1588
1510
|
if !continue_processing
|
1589
1511
|
throw :process_done
|
1590
1512
|
end
|
1591
1513
|
end
|
1592
1514
|
|
1593
1515
|
# Perform each step
|
1594
|
-
command.
|
1595
|
-
|
1596
|
-
|
1597
|
-
|
1598
|
-
|
1599
|
-
|
1516
|
+
command[:steps] && command[:steps].each do |outerstep|
|
1517
|
+
if step = outerstep[:step]
|
1518
|
+
# Run guards, display only in debug (a la setup)
|
1519
|
+
guard_result = true
|
1520
|
+
step[:guard] && step[:guard].each do |guard|
|
1521
|
+
guard_result &= process_guard(guard, commandname)
|
1522
|
+
end
|
1600
1523
|
|
1601
|
-
|
1602
|
-
|
1603
|
-
|
1524
|
+
if !guard_result
|
1525
|
+
# Tell the user what we're going to do
|
1526
|
+
puts "Will run command '#{step[:command].join('; ')}'"
|
1604
1527
|
|
1605
|
-
|
1606
|
-
|
1607
|
-
|
1608
|
-
|
1609
|
-
|
1610
|
-
|
1611
|
-
|
1612
|
-
|
1613
|
-
|
1614
|
-
|
1615
|
-
|
1616
|
-
|
1617
|
-
|
1618
|
-
|
1619
|
-
|
1528
|
+
# If the user requested interactive mode ask them for
|
1529
|
+
# confirmation to proceed.
|
1530
|
+
if @interactive
|
1531
|
+
case get_user_confirmation()
|
1532
|
+
when CONFIRM_PROCEED
|
1533
|
+
# No need to do anything
|
1534
|
+
when CONFIRM_SKIP
|
1535
|
+
save_results = false
|
1536
|
+
throw :process_done
|
1537
|
+
when CONFIRM_QUIT
|
1538
|
+
continue_processing = false
|
1539
|
+
save_results = false
|
1540
|
+
throw :process_done
|
1541
|
+
else
|
1542
|
+
raise "Unexpected result from get_user_confirmation()"
|
1543
|
+
end
|
1620
1544
|
end
|
1621
|
-
end
|
1622
1545
|
|
1623
|
-
|
1624
|
-
|
1546
|
+
# Run command, always display (a la pre/post)
|
1547
|
+
step[:command] && step[:command].each do |cmd|
|
1548
|
+
process_command(cmd, commandname)
|
1549
|
+
end
|
1625
1550
|
|
1626
|
-
|
1627
|
-
|
1628
|
-
|
1629
|
-
|
1551
|
+
# Re-run guard, always display, abort if fails
|
1552
|
+
guard_recheck_result = true
|
1553
|
+
step[:guard] && step[:guard].each do |guard|
|
1554
|
+
guard_recheck_result &= process_guard(guard, commandname)
|
1555
|
+
end
|
1556
|
+
if !guard_recheck_result
|
1557
|
+
raise "Guard #{step[:guard].join('; ')} still fails for #{commandname} after running command #{step[:command].join('; ')}"
|
1558
|
+
end
|
1630
1559
|
end
|
1631
1560
|
end
|
1632
1561
|
end
|
@@ -1663,7 +1592,14 @@ class Etch::Client
|
|
1663
1592
|
# If the file currently exists and is a regular file then check to see
|
1664
1593
|
# if the new contents are the same.
|
1665
1594
|
if File.file?(file) && !File.symlink?(file)
|
1666
|
-
|
1595
|
+
# As elsewhere we have no idea how arbitrary files that the user is
|
1596
|
+
# managing are encoded, so tell Ruby to read the file in binary mode.
|
1597
|
+
contents = nil
|
1598
|
+
if RUBY_VERSION.split('.')[0..1].join('.').to_f >= 1.9
|
1599
|
+
contents = IO.read(file, :encoding => 'ASCII-8BIT')
|
1600
|
+
else
|
1601
|
+
contents = IO.read(file)
|
1602
|
+
end
|
1667
1603
|
if newcontents == contents
|
1668
1604
|
return true
|
1669
1605
|
end
|
@@ -1696,7 +1632,14 @@ class Etch::Client
|
|
1696
1632
|
# a regular file, otherwise we send back an empty string.
|
1697
1633
|
if (origpath =~ /\.ORIG$/ || origpath =~ /\.TMP$/) &&
|
1698
1634
|
File.file?(origpath) && !File.symlink?(origpath)
|
1699
|
-
|
1635
|
+
# As elsewhere we have no idea how arbitrary files that the user is
|
1636
|
+
# managing are encoded, so tell Ruby to read the file in binary mode.
|
1637
|
+
orig_contents = nil
|
1638
|
+
if RUBY_VERSION.split('.')[0..1].join('.').to_f >= 1.9
|
1639
|
+
orig_contents = IO.read(origpath, :encoding => 'ASCII-8BIT')
|
1640
|
+
else
|
1641
|
+
orig_contents = IO.read(origpath)
|
1642
|
+
end
|
1700
1643
|
else
|
1701
1644
|
orig_contents = ''
|
1702
1645
|
end
|
@@ -1970,33 +1913,15 @@ class Etch::Client
|
|
1970
1913
|
|
1971
1914
|
def get_local_requests(file)
|
1972
1915
|
requestdir = File.join(@requestbase, file)
|
1973
|
-
|
1916
|
+
requests = []
|
1974
1917
|
if File.directory?(requestdir)
|
1975
1918
|
Dir.foreach(requestdir) do |entry|
|
1976
1919
|
next if entry == '.'
|
1977
1920
|
next if entry == '..'
|
1978
1921
|
requestfile = File.join(requestdir, entry)
|
1979
|
-
|
1980
|
-
# Make sure it is valid XML
|
1981
|
-
begin
|
1982
|
-
request_xml = REXML::Document.new(request)
|
1983
|
-
rescue REXML::ParseException => e
|
1984
|
-
warn "Local request file #{requestfile} is not valid XML and will be ignored:\n" + e.message
|
1985
|
-
next
|
1986
|
-
end
|
1987
|
-
# Make sure the root element is <request>
|
1988
|
-
if request_xml.root.name != 'request'
|
1989
|
-
warn "Local request file #{requestfile} is not properly formatted and will be ignored, XML root element is not <request>"
|
1990
|
-
next
|
1991
|
-
end
|
1992
|
-
# Add it to the queue
|
1993
|
-
requestlist << request
|
1922
|
+
requests << IO.read(requestfile)
|
1994
1923
|
end
|
1995
1924
|
end
|
1996
|
-
requests = nil
|
1997
|
-
if !requestlist.empty?
|
1998
|
-
requests = "<requests>\n#{requestlist.join('')}\n</requests>"
|
1999
|
-
end
|
2000
1925
|
requests
|
2001
1926
|
end
|
2002
1927
|
|
@@ -2064,96 +1989,105 @@ class Etch::Client
|
|
2064
1989
|
end
|
2065
1990
|
|
2066
1991
|
def process_setup(file, config)
|
2067
|
-
|
2068
|
-
|
2069
|
-
|
2070
|
-
|
2071
|
-
|
2072
|
-
|
2073
|
-
|
2074
|
-
|
2075
|
-
|
2076
|
-
|
2077
|
-
|
1992
|
+
if config[:setup]
|
1993
|
+
# Because the setup commands are processed every time etch runs
|
1994
|
+
# (rather than just when the file has changed, as with pre/post) we
|
1995
|
+
# don't want to print a message for them unless we're in debug mode.
|
1996
|
+
puts "Processing setup commands" if (@debug)
|
1997
|
+
config[:setup].each do |setup|
|
1998
|
+
r = process_exec(:setup, setup, file)
|
1999
|
+
# process_exec currently raises an exception if a setup or pre command
|
2000
|
+
# fails. In case that ever changes make sure we propagate
|
2001
|
+
# the error.
|
2002
|
+
return r if (!r)
|
2003
|
+
end
|
2078
2004
|
end
|
2005
|
+
true
|
2079
2006
|
end
|
2080
2007
|
def process_pre(file, config)
|
2081
|
-
|
2082
|
-
|
2083
|
-
|
2084
|
-
|
2085
|
-
|
2086
|
-
|
2087
|
-
|
2088
|
-
|
2008
|
+
if config[:pre]
|
2009
|
+
puts "Processing pre commands"
|
2010
|
+
config[:pre].each do |pre|
|
2011
|
+
r = process_exec(:pre, pre, file)
|
2012
|
+
# process_exec currently raises an exception if a setup or pre command
|
2013
|
+
# fails. In case that ever changes make sure we propagate
|
2014
|
+
# the error.
|
2015
|
+
return r if (!r)
|
2016
|
+
end
|
2089
2017
|
end
|
2018
|
+
true
|
2090
2019
|
end
|
2091
2020
|
def process_post(file, config)
|
2092
|
-
exectype = 'post'
|
2093
2021
|
execs = []
|
2094
|
-
puts "Processing #{exectype} commands"
|
2095
2022
|
|
2096
|
-
|
2023
|
+
if [:post, :post_once, :post_once_per_run].any?{|p| config[p]}
|
2024
|
+
puts "Processing post commands"
|
2025
|
+
end
|
2026
|
+
|
2027
|
+
# Add the "post once" items into the list of commands to process
|
2097
2028
|
# if this is the first time etch has updated this file, and if
|
2098
2029
|
# we haven't already run the command.
|
2099
|
-
if @first_update[file]
|
2100
|
-
config.
|
2101
|
-
if !@exec_already_processed.has_key?(
|
2102
|
-
execs <<
|
2103
|
-
@exec_already_processed[
|
2030
|
+
if @first_update[file] && config[:post_once]
|
2031
|
+
config[:post_once].each do |once|
|
2032
|
+
if !@exec_already_processed.has_key?(once)
|
2033
|
+
execs << once
|
2034
|
+
@exec_already_processed[once] = true
|
2104
2035
|
else
|
2105
|
-
puts "Skipping '#{
|
2036
|
+
puts "Skipping '#{once}', it has already " +
|
2106
2037
|
"been executed once this run" if (@debug)
|
2107
2038
|
end
|
2108
2039
|
end
|
2109
2040
|
end
|
2110
2041
|
|
2111
|
-
# Add in the regular
|
2112
|
-
config
|
2113
|
-
execs
|
2042
|
+
# Add in the regular post items
|
2043
|
+
if config[:post]
|
2044
|
+
execs.concat config[:post]
|
2114
2045
|
end
|
2115
2046
|
|
2116
2047
|
# post failures are considered non-fatal, so we ignore the
|
2117
2048
|
# return value from process_exec (it takes care of warning
|
2118
2049
|
# the user).
|
2119
|
-
execs.each { |exec| process_exec(
|
2050
|
+
execs.each { |exec| process_exec(:post, exec, file) }
|
2120
2051
|
|
2121
|
-
config
|
2122
|
-
|
2123
|
-
|
2124
|
-
|
2125
|
-
|
2052
|
+
if config[:post_once_per_run]
|
2053
|
+
config[:post_once_per_run].each do |popr|
|
2054
|
+
# Stuff the "post once per run" nodes into the global hash to
|
2055
|
+
# be run after we've processed all files.
|
2056
|
+
puts "Adding '#{popr}' to 'post once per run' list" if (@debug)
|
2057
|
+
@exec_once_per_run[popr] = true
|
2058
|
+
end
|
2126
2059
|
end
|
2127
2060
|
end
|
2128
2061
|
def process_test_before_post(file, config)
|
2129
|
-
|
2130
|
-
|
2131
|
-
|
2132
|
-
|
2133
|
-
|
2134
|
-
|
2062
|
+
if config[:test_before_post]
|
2063
|
+
puts "Processing test_before_post commands"
|
2064
|
+
config[:test_before_post].each do |tbp|
|
2065
|
+
r = process_exec(:test_before_post, tbp, file)
|
2066
|
+
# If the test failed we need to propagate that error
|
2067
|
+
return r if (!r)
|
2068
|
+
end
|
2135
2069
|
end
|
2070
|
+
true
|
2136
2071
|
end
|
2137
2072
|
def process_test(file, config)
|
2138
|
-
|
2139
|
-
|
2140
|
-
|
2141
|
-
|
2142
|
-
|
2143
|
-
|
2073
|
+
if config[:test]
|
2074
|
+
puts "Processing test commands"
|
2075
|
+
config[:test].each do |test|
|
2076
|
+
r = process_exec(:test, test, file)
|
2077
|
+
# If the test failed we need to propagate that error
|
2078
|
+
return r if (!r)
|
2079
|
+
end
|
2144
2080
|
end
|
2145
2081
|
end
|
2146
2082
|
def process_guard(guard, commandname)
|
2147
|
-
exectype = 'guard'
|
2148
2083
|
# Because the guard commands are processed every time etch runs we don't
|
2149
2084
|
# want to print a message for them unless we're in debug mode.
|
2150
|
-
puts "Processing
|
2151
|
-
process_exec(
|
2085
|
+
puts "Processing guard" if (@debug)
|
2086
|
+
process_exec(:guard, guard, commandname)
|
2152
2087
|
end
|
2153
2088
|
def process_command(command, commandname)
|
2154
|
-
|
2155
|
-
|
2156
|
-
process_exec(exectype, command, commandname)
|
2089
|
+
puts "Processing command"
|
2090
|
+
process_exec(:command, command, commandname)
|
2157
2091
|
end
|
2158
2092
|
|
2159
2093
|
def process_exec(exectype, exec, file='')
|
@@ -2162,14 +2096,14 @@ class Etch::Client
|
|
2162
2096
|
# Because the setup and guard commands are processed every time (rather
|
2163
2097
|
# than just when the file has changed as with pre/post) we don't want to
|
2164
2098
|
# print a message for them.
|
2165
|
-
puts " Executing '#{exec}'" if (
|
2099
|
+
puts " Executing '#{exec}'" if (![:setup, :guard].include?(exectype) || @debug)
|
2166
2100
|
|
2167
2101
|
# Actually run the command unless we're in a dry run, or if we're in
|
2168
2102
|
# a damp run and the command is a setup command.
|
2169
|
-
if ! @dryrun || (@dryrun == 'damp' && exectype ==
|
2103
|
+
if ! @dryrun || exectype == :guard || (@dryrun == 'damp' && exectype == :setup)
|
2170
2104
|
etch_priority = nil
|
2171
2105
|
|
2172
|
-
if
|
2106
|
+
if [:post, :command].include?(exectype)
|
2173
2107
|
# Etch is likely running at a lower priority than normal.
|
2174
2108
|
# However, we don't want to run post commands at that
|
2175
2109
|
# priority. If they restart processes (for example,
|
@@ -2189,7 +2123,7 @@ class Etch::Client
|
|
2189
2123
|
# "FOO=bar myprogram" works.
|
2190
2124
|
r = system('/bin/sh', '-c', exec)
|
2191
2125
|
|
2192
|
-
if
|
2126
|
+
if [:post, :command].include?(exectype)
|
2193
2127
|
if etch_priority != 0
|
2194
2128
|
puts " Returning priority to #{etch_priority}" if (@debug)
|
2195
2129
|
Process.setpriority(Process::PRIO_USER, 0, etch_priority)
|
@@ -2204,7 +2138,7 @@ class Etch::Client
|
|
2204
2138
|
# what's going on if it fails. So include the command in the message if
|
2205
2139
|
# there was a failure.
|
2206
2140
|
execmsg = ''
|
2207
|
-
execmsg = "'#{exec}' " if (
|
2141
|
+
execmsg = "'#{exec}' " if ([:setup, :guard].include?(exectype))
|
2208
2142
|
|
2209
2143
|
# Normally we include the filename of the file that this command
|
2210
2144
|
# is associated with in the messages we print. But for "exec once
|
@@ -2218,21 +2152,21 @@ class Etch::Client
|
|
2218
2152
|
# software prerequisites, and bad things generally happen if
|
2219
2153
|
# those software installs fail. So consider it a fatal error if
|
2220
2154
|
# that occurs.
|
2221
|
-
if
|
2155
|
+
if [:setup, :pre].include?(exectype)
|
2222
2156
|
raise " Setup/Pre command " + execmsg + filemsg +
|
2223
2157
|
"exited with non-zero value"
|
2224
2158
|
# Post commands are generally used to restart services. While
|
2225
2159
|
# it is unfortunate if they fail, there is little to be gained
|
2226
2160
|
# by having etch exit if they do so. So simply warn if a post
|
2227
2161
|
# command fails.
|
2228
|
-
elsif exectype ==
|
2162
|
+
elsif exectype == :post
|
2229
2163
|
puts " Post command " + execmsg + filemsg +
|
2230
2164
|
"exited with non-zero value"
|
2231
2165
|
# process_commands takes the appropriate action when guards and commands
|
2232
2166
|
# fail, so we just warn of any failures here.
|
2233
|
-
elsif exectype ==
|
2167
|
+
elsif exectype == :guard
|
2234
2168
|
puts " Guard " + execmsg + filemsg + "exited with non-zero value"
|
2235
|
-
elsif exectype ==
|
2169
|
+
elsif exectype == :command
|
2236
2170
|
puts " Command " + execmsg + filemsg + "exited with non-zero value"
|
2237
2171
|
# For test commands we need to warn the user and then return a
|
2238
2172
|
# value indicating the failure so that a rollback can be
|
@@ -2247,10 +2181,9 @@ class Etch::Client
|
|
2247
2181
|
end
|
2248
2182
|
|
2249
2183
|
def lookup_uid(user)
|
2250
|
-
|
2251
|
-
if user =~ /^\d+$/
|
2184
|
+
if user.to_i.to_s == user.to_s
|
2252
2185
|
# If the user was specified as a numeric UID, use it directly.
|
2253
|
-
uid = user
|
2186
|
+
uid = user.to_i
|
2254
2187
|
else
|
2255
2188
|
# Otherwise attempt to look up the username to get a UID.
|
2256
2189
|
# Default to UID 0 if the username can't be found.
|
@@ -2258,19 +2191,17 @@ class Etch::Client
|
|
2258
2191
|
pw = Etc.getpwnam(user)
|
2259
2192
|
uid = pw.uid
|
2260
2193
|
rescue ArgumentError
|
2261
|
-
puts "config
|
2194
|
+
puts "config requests user #{user}, but that user can't be found. Using UID 0." if @debug
|
2262
2195
|
uid = 0
|
2263
2196
|
end
|
2264
2197
|
end
|
2265
|
-
|
2266
|
-
uid.to_i
|
2198
|
+
uid
|
2267
2199
|
end
|
2268
2200
|
|
2269
2201
|
def lookup_gid(group)
|
2270
|
-
|
2271
|
-
if group =~ /^\d+$/
|
2202
|
+
if group.to_i.to_s == group.to_s
|
2272
2203
|
# If the group was specified as a numeric GID, use it directly.
|
2273
|
-
gid = group
|
2204
|
+
gid = group.to_i
|
2274
2205
|
else
|
2275
2206
|
# Otherwise attempt to look up the group to get a GID. Default
|
2276
2207
|
# to GID 0 if the group can't be found.
|
@@ -2278,12 +2209,11 @@ class Etch::Client
|
|
2278
2209
|
gr = Etc.getgrnam(group)
|
2279
2210
|
gid = gr.gid
|
2280
2211
|
rescue ArgumentError
|
2281
|
-
puts "config
|
2212
|
+
puts "config requests group #{group}, but that group can't be found. Using GID 0." if @debug
|
2282
2213
|
gid = 0
|
2283
2214
|
end
|
2284
2215
|
end
|
2285
|
-
|
2286
|
-
gid.to_i
|
2216
|
+
gid
|
2287
2217
|
end
|
2288
2218
|
|
2289
2219
|
# Returns true if the permissions of the given file match the given
|