@@ -50,44 +50,38 @@ def history(dts, message, code, reboot, security, job)
5050 end
5151end
5252
53- def run_with_timeout ( command , timeout , tick )
54- output = ''
53+ def run_with_timeout ( command , timeout )
54+ stdout = ''
55+ stderr = ''
56+ exit_code = nil
57+ wait_thr = nil
58+
5559 begin
56- # Start task in another thread, which spawns a process
57- stdin , stderrout , thread = Open3 . popen2e ( command )
58- # Get the pid of the spawned process
59- pid = thread [ :pid ]
60- start = Time . now
61-
62- while ( Time . now - start ) < timeout && thread . alive?
63- # Wait up to `tick` seconds for output/error data
64- Kernel . select ( [ stderrout ] , nil , nil , tick )
65- # Try to read the data
66- begin
67- output << stderrout . read_nonblock ( BUFFER_SIZE )
68- rescue IO ::WaitReadable
69- # A read would block, so loop around for another select
70- sleep 1
71- rescue EOFError
72- # Command has completed, not really an error...
73- break
60+ Timeout . timeout ( timeout ) do
61+ Open3 . popen3 ( *command ) do |stdin , out , err , thread |
62+ wait_thr = thread
63+ stdin . close
64+
65+ stdout = out . read
66+ stderr = err . read
67+ exit_code = wait_thr . value . exitstatus
7468 end
7569 end
76- # Give Ruby time to clean up the other thread
77- sleep 1
78-
79- if thread . alive?
80- # We need to kill the process, because killing the thread leaves
81- # the process alive but detached, annoyingly enough.
82- Process . kill ( 'TERM' , pid )
83- err ( '403' , 'os_patching/patching' , "TIMEOUT AFTER #{ timeout } seconds\n #{ output } " , start )
70+ rescue Timeout ::Error
71+ if wait_thr
72+ begin
73+ Process . kill ( 'TERM' , wait_thr . pid )
74+ sleep 2
75+ Process . kill ( 'KILL' , wait_thr . pid )
76+ rescue Errno ::ESRCH
77+ nil
78+ end
8479 end
85- ensure
86- stdin . close if stdin
87- stderrout . close if stderrout
88- status = thread . value . exitstatus
80+
81+ err ( '403' , 'os_patching/patching' , "TIMEOUT AFTER #{ timeout } seconds" , Time . now . iso8601 )
8982 end
90- [ status , output ]
83+
84+ [ exit_code , stdout , stderr ]
9185end
9286
9387# pending reboot detection function for windows
@@ -502,8 +496,8 @@ def gather_facts(log, starttime)
502496 log . info 'Running yum upgrade'
503497 log . debug "Timeout value set to : #{ timeout } "
504498 yum_end = ''
505- status , output = run_with_timeout ( "yum #{ yum_params } #{ securityflag } upgrade -y" , timeout , 2 )
506- err ( status , 'os_patching/yum' , "yum upgrade returned non-zero (#{ status } ) : #{ output } " , starttime ) if status != 0
499+ yum_exitcode , yum_output , yum_error = run_with_timeout ( "yum #{ yum_params } #{ securityflag } upgrade -y" , timeout )
500+ err ( yum_exitcode , 'os_patching/yum' , "yum upgrade returned non-zero (#{ yum_exitcode } ) : #{ yum_output } \n #{ yum_error } " , starttime ) if yum_exitcode != 0
507501
508502 if os [ 'release' ] [ 'major' ] . to_i > 5
509503 # Capture the yum job ID
@@ -569,6 +563,9 @@ def gather_facts(log, starttime)
569563 output ( yum_return , reboot , security_only , 'Patching complete' , pkg_hash , output , job , pinned_pkgs , starttime , log )
570564 log . info 'Patching complete'
571565elsif os [ 'family' ] == 'Debian'
566+ log . info 'Running apt'
567+ log . debug "Timeout value set to : #{ timeout } "
568+
572569 # Are we doing security only patching?
573570 if security_only == true
574571 pkg_list = os_patching [ 'security_package_updates' ]
@@ -582,10 +579,16 @@ def gather_facts(log, starttime)
582579 log . debug "Running apt #{ apt_mode } "
583580 deb_front = 'DEBIAN_FRONTEND=noninteractive'
584581 deb_opts = '-o Apt::Get::Purge=false -o Dpkg::Options::=--force-confold -o Dpkg::Options::=--force-confdef --no-install-recommends'
585- apt_std_out , status = run_with_timeout ( "#{ deb_front } apt-get #{ dpkg_params } -y #{ deb_opts } #{ apt_mode } " , timeout , 2 )
586- err ( status , 'os_patching/apt' , apt_std_out , starttime ) if status != 0
582+ # apt_std_out, stderr, status = Open3.capture3("#{deb_front} apt-get #{dpkg_params} -y #{deb_opts} #{apt_mode}")
583+ apt_exitcode , apt_out , apt_err = run_with_timeout ( "#{ deb_front } apt-get #{ dpkg_params } -y #{ deb_opts } #{ apt_mode } " , timeout )
584+
585+ log . debug "apt output : #{ apt_out } "
586+ log . debug "apt error output : #{ apt_err } "
587+ log . debug "apt exit status : #{ apt_exitcode } "
587588
588- output ( 'Success' , reboot , security_only , 'Patching complete' , pkg_list , apt_std_out , '' , pinned_pkgs , starttime , log )
589+ err ( apt_exitcode , 'os_patching/apt' , "Error: #{ apt_err } " , starttime ) if apt_exitcode != 0
590+
591+ output ( 'Success' , reboot , security_only , 'Patching complete' , pkg_list , apt_out . split ( "\n " ) , '' , pinned_pkgs , starttime , log )
589592 log . info 'Patching complete'
590593elsif os [ 'family' ] == 'windows'
591594 # we're on windows
@@ -645,7 +648,6 @@ def gather_facts(log, starttime)
645648 # output results
646649 # def output(returncode, reboot, security, message, packages_updated, debug, job_id, pinned_packages, starttime)
647650 output ( 'Success' , reboot , security_only , 'Patching complete' , update_titles , win_std_out . split ( "\n " ) , '' , '' , starttime , log )
648-
649651elsif os [ 'family' ] == 'Suse'
650652 zypper_required_params = '--non-interactive --no-abbrev --quiet'
651653 zypper_cmd_params = '--auto-agree-with-licenses'
@@ -656,15 +658,15 @@ def gather_facts(log, starttime)
656658 if security_only == true
657659 pkg_list = os_patching [ 'security_package_updates' ]
658660 log . info 'Running zypper patch'
659- status , output = run_with_timeout ( "zypper #{ zypper_required_params } #{ zypper_params } patch -g security #{ zypper_cmd_params } " , timeout , 2 )
660- err ( status , 'os_patching/zypper' , "zypper patch returned non-zero (#{ status } ) : #{ output } " , starttime ) if status != 0
661+ zypper_exitcode , zypper_output , zypper_error = run_with_timeout ( "zypper #{ zypper_required_params } #{ zypper_params } patch -g security #{ zypper_cmd_params } " , timeout )
662+ err ( zypper_exitcode , 'os_patching/zypper' , "zypper patch returned non-zero (#{ zypper_exitcode } ) : #{ zypper_output } \n #{ zypper_error } " , starttime ) if zypper_exitcode != 0
661663 else
662664 pkg_list = os_patching [ 'package_updates' ]
663665 log . info 'Running zypper update'
664- status , output = run_with_timeout ( "zypper #{ zypper_required_params } #{ zypper_params } update -t package #{ zypper_cmd_params } " , timeout , 2 )
665- err ( status , 'os_patching/zypper' , "zypper update returned non-zero (#{ status } ) : #{ output } " , starttime ) if status != 0
666+ zypper_exitcode , zypper_output , zypper_error = run_with_timeout ( "zypper #{ zypper_required_params } #{ zypper_params } update -t package #{ zypper_cmd_params } " , timeout )
667+ err ( zypper_exitcode , 'os_patching/zypper' , "zypper update returned non-zero (#{ zypper_exitcode } ) : #{ zypper_output } \n #{ zypper_error } " , starttime ) if zypper_exitcode != 0
666668 end
667- output ( 'Success' , reboot , security_only , 'Patching complete' , pkg_list , output , '' , pinned_pkgs , starttime , log )
669+ output ( 'Success' , reboot , security_only , 'Patching complete' , pkg_list , zypper_output . split ( " \n " ) , '' , pinned_pkgs , starttime , log )
668670 log . info 'Patching complete'
669671 log . debug "Timeout value set to : #{ timeout } "
670672else
0 commit comments