Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 42 additions & 42 deletions plans/patch_batch.pp
Original file line number Diff line number Diff line change
Expand Up @@ -55,58 +55,58 @@
}

# get nodes that are 'clean' from health check results
$nodes_to_patch = ($health_checks.filter_set |$item| { $item.value['state'] == 'clean' }).map |$n| { $n.target }
$skipped_nodes = ($health_checks.filter_set |$item| { $item.status == 'failure' }).map |$n| { $n.target }
$nodes_to_patch = ($health_checks.filter_set |$item| { $item.value['state'] == 'clean' }).map |$n| { $n.target }
$health_check_failed = ($health_checks.filter_set |$item| { $item.status == 'failure' }).map |$n| { $n.target }

if $debug {
out::message('patch_batch.pp: Nodes to patch after health check:')
out::message($nodes_to_patch)
out::message('patch_batch.pp: Skipped nodes after health check:')
out::message($skipped_nodes)
out::message($health_check_failed)
}
} else {
$nodes_to_patch = $batch
$health_check_failed = []
}

$patching_result = run_task('os_patching::patch_server', $nodes_to_patch,
_catch_errors => $catch_errors,
clean_cache => $clean_cache,
dpkg_params => $dpkg_params,
reboot => $reboot,
security_only => $security_only,
timeout => $timeout,
yum_params => $yum_params,
zypper_params => $zypper_params,
)
$patching_result = run_task('os_patching::patch_server', $nodes_to_patch,
_catch_errors => $catch_errors,
clean_cache => $clean_cache,
dpkg_params => $dpkg_params,
reboot => $reboot,
security_only => $security_only,
timeout => $timeout,
yum_params => $yum_params,
zypper_params => $zypper_params,
)

if $debug {
out::message('patch_batch.pp: Patching results:')
out::message($patching_result)
}
} else {
$patching_result = run_task('os_patching::patch_server', $batch,
_catch_errors => $catch_errors,
clean_cache => $clean_cache,
dpkg_params => $dpkg_params,
reboot => $reboot,
security_only => $security_only,
timeout => $timeout,
yum_params => $yum_params,
zypper_params => $zypper_params,
)
if $debug {
out::message('patch_batch.pp: Patching results:')
out::message($patching_result)
}

if $debug {
out::message('patch_batch.pp: Patching results:')
out::message($patching_result)
}
$no_patches = $patching_result.ok_set.filter |$item| {
$item.value['packages_updated'].empty
}.map |$n| { $n.target }

$with_patches = $patching_result.ok_set.filter |$item| {
! $item.value['packages_updated'].empty
}.map |$n| { $n.target }

$skipped_nodes = [] # No skipped nodes if health check is not run
$reboot_required = $patching_result.ok_set.filter |$item| {
$item.value['reboot_required'] == true
}.map |$n| { $n.target }

$output = {
failed => $patching_result.error_set.names,
health_check => $run_health_check,
health_check_failed => $health_check_failed,
no_patches => $no_patches,
reboot_pattern => $reboot,
reboot_required => $reboot_required,
targets => $batch,
with_patches => $with_patches,
}

return(
{
targets => $batch,
patched => $patching_result.ok_set.names,
failed => $patching_result.error_set.names,
skipped => $skipped_nodes,
health_check => $run_health_check,
}
)
return($output)
}
13 changes: 8 additions & 5 deletions plans/patch_group.pp
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,14 @@

# Merge all batch results into a single hash by combining arrays
$result = {
'targets' => $batch_results.map |$r| { $r['targets'] }.flatten,
'patched' => $batch_results.map |$r| { $r['patched'] }.flatten,
'failed' => $batch_results.map |$r| { $r['failed'] }.flatten,
'skipped' => $batch_results.map |$r| { $r['skipped'] }.flatten,
'health_check' => $batch_results[0]['health_check'],
failed => $batch_results.map |$r| { $r['failed'] }.flatten,
health_check => $batch_results[0]['health_check'],
health_check_failed => $batch_results.map |$r| { $r['health_check_failed'] }.flatten,
no_patches => $batch_results.map |$r| { $r['no_patches'] }.flatten,
reboot_pattern => $batch_results[0]['reboot_pattern'],
reboot_required => $batch_results.map |$r| { $r['reboot_required'] }.flatten,
targets => $batch_results.map |$r| { $r['targets'] }.flatten,
with_patches => $batch_results.map |$r| { $r['with_patches'] }.flatten,
}
} else {
out::message("patch_group.pp: Patching all targets at once: ${targets}")
Expand Down
13 changes: 8 additions & 5 deletions plans/patch_pql.pp
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,14 @@

# Merge all batch results into a single hash by combining arrays
$result = {
'targets' => $batch_results.map |$r| { $r['targets'] }.flatten,
'patched' => $batch_results.map |$r| { $r['patched'] }.flatten,
'failed' => $batch_results.map |$r| { $r['failed'] }.flatten,
'skipped' => $batch_results.map |$r| { $r['skipped'] }.flatten,
'health_check' => $batch_results[0]['health_check'],
failed => $batch_results.map |$r| { $r['failed'] }.flatten,
health_check => $batch_results[0]['health_check'],
health_check_failed => $batch_results.map |$r| { $r['health_check_failed'] }.flatten,
no_patches => $batch_results.map |$r| { $r['no_patches'] }.flatten,
reboot_pattern => $batch_results[0]['reboot_pattern'],
reboot_required => $batch_results.map |$r| { $r['reboot_required'] }.flatten,
targets => $batch_results.map |$r| { $r['targets'] }.flatten,
with_patches => $batch_results.map |$r| { $r['with_patches'] }.flatten,
}
} else {
out::message('patch_pql.pp: Patching in batches is disabled')
Expand Down
64 changes: 51 additions & 13 deletions tasks/patch_server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
# set paths/commands for windows
fact_generation_script = 'C:/ProgramData/os_patching/os_patching_fact_generation.ps1'
fact_generation_cmd = "#{ENV['systemroot']}/system32/WindowsPowerShell/v1.0/powershell.exe -ExecutionPolicy RemoteSigned -file #{fact_generation_script}"
puppet_cmd = "#{ENV['programfiles']}/Puppet Labs/Puppet/bin/puppet"
@puppet_cmd = "#{ENV['programfiles']}/Puppet Labs/Puppet/bin/puppet"
shutdown_cmd = 'shutdown /r /t 60 /c "Rebooting due to the installation of updates by os_patching" /d p:2:17'
else
# not windows
Expand All @@ -29,7 +29,7 @@
# set paths/commands for linux
fact_generation_script = '/usr/local/bin/os_patching_fact_generation.sh'
fact_generation_cmd = fact_generation_script
puppet_cmd = '/opt/puppetlabs/puppet/bin/puppet'
@puppet_cmd = '/opt/puppetlabs/puppet/bin/puppet'
shutdown_cmd = 'nohup /sbin/shutdown -r +1 2>/dev/null 1>/dev/null &'

ENV['LC_ALL'] = 'C'
Expand Down Expand Up @@ -134,8 +134,35 @@
end
end

def pending_reboot_linux(log, starttime)
facts = gather_facts(log, starttime)

# check for existence of /var/run/reboot-required file
if facts['os']['family'] == 'RedHat'
if File.file?('/usr/bin/needs-restarting')
_output, _stderr, status = Open3.capture3('/usr/bin/needs-restarting -r')
if status != 0

Check failure on line 144 in tasks/patch_server.rb

View workflow job for this annotation

GitHub Actions / Puppet / Static validations

Style/GuardClause: Use a guard clause (`return true if status != 0`) instead of wrapping the code inside a conditional expression. (https://rubystyle.guide#no-nested-conditionals)
return true
else
return false
end
else
log.warn 'needs-restarting command not found, cannot determine if reboot is required'
log.warn 'please install the yum-util/dnf-utils package to enable this functionality'
# needs-restart doesn't exist so assume it is not needed
return false
end
end

if File.file?('/var/run/reboot-required')
true
else
false
end
end

# Default output function
def output(returncode, reboot, security, message, packages_updated, debug, job_id, pinned_packages, starttime)
def output(returncode, reboot, security, message, packages_updated, debug, job_id, pinned_packages, starttime, log)
endtime = Time.now.iso8601
json = {
:return => returncode,
Expand All @@ -148,7 +175,12 @@
:pinned_packages => pinned_packages,
:start_time => starttime,
:end_time => endtime,
:duration => Time.parse(endtime) - Time.parse(starttime)
}

json[:reboot_required] = pending_reboot_win if IS_WINDOWS
json[:reboot_required] = pending_reboot_linux(log, starttime) unless IS_WINDOWS

puts JSON.pretty_generate(json)
history(starttime, message, returncode, reboot, security, job_id)
end
Expand Down Expand Up @@ -235,6 +267,15 @@
end
end

def gather_facts(log, starttime)
# Cache the facts
log.debug 'Gathering facts'
full_facts, stderr, status = Open3.capture3(@puppet_cmd, 'facts')
err(status, 'os_patching/facter', stderr, starttime) if status != 0

JSON.parse(full_facts)
end

# Parse input, get params in scope
params = nil
begin
Expand All @@ -259,10 +300,7 @@
end

# Cache the facts
log.debug 'Gathering facts'
full_facts, stderr, status = Open3.capture3(puppet_cmd, 'facts')
err(status, 'os_patching/facter', stderr, starttime) if status != 0
facts = JSON.parse(full_facts)
facts = gather_facts(log, starttime)

if facts['os']
os = facts['os']
Expand Down Expand Up @@ -450,7 +488,7 @@
if updatecount.zero?
if reboot == 'always'
log.error 'Rebooting'
output('Success', reboot, security_only, 'No patches to apply, reboot triggered', '', '', '', pinned_pkgs, starttime)
output('Success', reboot, security_only, 'No patches to apply, reboot triggered', '', '', '', pinned_pkgs, starttime, log)
$stdout.flush
log.info 'No patches to apply, rebooting as requested'
p1 = if IS_WINDOWS
Expand All @@ -460,7 +498,7 @@
end
Process.detach(p1)
else
output('Success', reboot, security_only, 'No patches to apply', '', '', '', pinned_pkgs, starttime)
output('Success', reboot, security_only, 'No patches to apply', '', '', '', pinned_pkgs, starttime, log)
log.info 'No patches to apply, exiting'
end
exit(0)
Expand Down Expand Up @@ -535,7 +573,7 @@
pkg_hash = {}
end

output(yum_return, reboot, security_only, 'Patching complete', pkg_hash, output, job, pinned_pkgs, starttime)
output(yum_return, reboot, security_only, 'Patching complete', pkg_hash, output, job, pinned_pkgs, starttime, log)
log.info 'Patching complete'
elsif os['family'] == 'Debian'
# Are we doing security only patching?
Expand All @@ -556,7 +594,7 @@
apt_std_out, stderr, status = Open3.capture3("#{deb_front} apt-get #{dpkg_params} -y #{deb_opts} #{apt_mode}")
err(status, 'os_patching/apt', stderr, starttime) if status != 0

output('Success', reboot, security_only, 'Patching complete', pkg_list, apt_std_out, '', pinned_pkgs, starttime)
output('Success', reboot, security_only, 'Patching complete', pkg_list, apt_std_out, '', pinned_pkgs, starttime, log)
log.info 'Patching complete'
elsif os['family'] == 'windows'
# we're on windows
Expand Down Expand Up @@ -615,7 +653,7 @@

# output results
# def output(returncode, reboot, security, message, packages_updated, debug, job_id, pinned_packages, starttime)
output('Success', reboot, security_only, 'Patching complete', update_titles, win_std_out.split("\n"), '', '', starttime)
output('Success', reboot, security_only, 'Patching complete', update_titles, win_std_out.split("\n"), '', '', starttime, log)

elsif os['family'] == 'Suse'
zypper_required_params = '--non-interactive --no-abbrev --quiet'
Expand All @@ -635,7 +673,7 @@
status, output = run_with_timeout("zypper #{zypper_required_params} #{zypper_params} update -t package #{zypper_cmd_params}", timeout, 2)
err(status, 'os_patching/zypper', "zypper update returned non-zero (#{status}) : #{output}", starttime) if status != 0
end
output('Success', reboot, security_only, 'Patching complete', pkg_list, output, '', pinned_pkgs, starttime)
output('Success', reboot, security_only, 'Patching complete', pkg_list, output, '', pinned_pkgs, starttime, log)
log.info 'Patching complete'
log.debug "Timeout value set to : #{timeout}"
else
Expand Down
Loading