-
Notifications
You must be signed in to change notification settings - Fork 193
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
(MODULES-8431) Update windows installation to use powershell #362
Conversation
778a293
to
75c9fbb
Compare
I think you forgot to |
whoops |
75c9fbb
to
f7a82db
Compare
fdba31a
to
e9c94c5
Compare
CLA signed by all contributors. |
templates/install_puppet.ps1.erb
Outdated
[String] $InstallDir='<%= @install_dir %>', | ||
[String] $PuppetMaster='<%= @_puppet_master %>', | ||
[String] $PuppetStartType='<%= @_agent_startup_mode %>', | ||
[String] $InstallArgs='<%= @_install_options.map do |option| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally I'd prefer this "logic" be in the manifest and the $InstallArgs be a dumb string, but I'm not too fussed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with Glenn
templates/install_puppet.ps1.erb
Outdated
Fetch the location of the puppet installation from the registry | ||
#> | ||
function Script:fetch_install_dir { | ||
param() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without cmdlet binding, this is not needed.
templates/install_puppet.ps1.erb
Outdated
Move/rename puppetres.dll to a temporary location | ||
#> | ||
function Script:move_puppetres_dll { | ||
param() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without cmdlet binding, this is not needed.
templates/install_puppet.ps1.erb
Outdated
# for the already installed package | ||
$InstallDir = fetch_install_dir | ||
if (Test-Path "$InstallDir\puppet\bin\puppetres.dll") { | ||
Out-File -InputObject "Moving puppetres.dll to $temp_puppetres" -FilePath $Logfile -Append |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The canonical way of doing this is normally;
"Moving puppetres.dll to $temp_puppetres" | Out-File -FilePath $Logfile -Append"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May be easier to abstract this into a method? Log <error_message>
is more readable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to refactor to it's own function
$InstallDir = fetch_install_dir | ||
if (Test-Path $temp_puppetres) { | ||
Out-File -InputObject "Restoring puppetres.dll" -FilePath $Logfile -Append | ||
Move-Item -Path $temp_puppetres -Destination "$InstallDir\puppet\bin\puppetres.dll" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should fail gracefully. Moving the locked DLL will fail on rollback
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can also test for the existence of the normal puppetres.dll too.
templates/install_puppet.ps1.erb
Outdated
# but using WaitForExit works fine. | ||
$msiexec_proc.WaitForExit() | ||
Out-File -InputObject "****************************** End msiexec.exe output ******************************" -FilePath $Logfile -Append | ||
if ($msiexec_proc.ExitCode -ne 0){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not quite true.
Exit code could be 0, 3010 or 1641 (? I think it's 1604 - Soft reboot required)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we force /norestart in the MSI wouldn't the restart exit codes technically be failures as far as we're concerned?
It's my understanding that the agent should absolutely never cause a restart on upgrade.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those are both successful installation methods. 1641 simply means "The requested operation completed successfully. The system will be restarted so the changes can take effect" and 3010 means "The requested operation is successful. Changes will not be effective until the system is rebooted."
Thus one is initiating the reboot automatically, and the other is waiting for the user to reboot. The difference is in the switches or properties you've set when calling the MSI.
3010 is a succesfull install but it's pending a reboot. i.e. the agent package WANTED to reboot but it couldn't due to /norestart
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As per comments.
- Also strictly speaking the function names in the PS script aren't Verb-Noun
- Are we looking at running Pester tests over this?
- This script will need manual verification (i.e. functional review) for it's ability to upgrade, and will need to prove the puppetres.dll workaround works.
@glennsarti I was looking into https://tickets.puppetlabs.com/browse/PA-663 to understand the |
templates/install_puppet.ps1.erb
Outdated
# Wait for the puppet run to finish | ||
Out-File -InputObject "Waiting for puppet to stop, PID:$PuppetPID" -FilePath $Logfile -Append | ||
try { | ||
Wait-Process -Id $PuppetPID -Timeout 120 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could also do
$proc = Get-Process -Id $PuppetPID -ErrorAction SilentlyContinue
if ($proc) {
if (-Not $proc.WaitForExit(120000)) { // milliseconds
Log "Timeout"
}
} else {
Log "Puppet was already finished"
}
when waiting for the Puppet run to end.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or more simply;
try {
Get-Process -ID $PuppetPID -ErrorAction SilentlyContinue | Wait-Process -Timeout 120`
}
catch [System.TimeoutException] {
# TIMEOUT OCCURED
}
catch {
# unhandled error
}
throw $_ | ||
} | ||
} | ||
foreach($service in $service_names) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The previous install_puppet.bat
file had a long comment about why stopping the services was important. Maybe that comment should be here too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The long comment was about waiting for the puppet PID, rather than waiting for the services:
but I will add that back. And I'll add a comment as to why we need to shut down the services
9e3164f
to
6aba3a6
Compare
Pending manual Functional Review of the DLL locking repro case and description of manual testing performed by @mcdonaldseanp |
7acc4ba
to
122896c
Compare
templates/install_puppet.ps1.erb
Outdated
Lock-Installation $install_pid_lock | ||
# Wait for the puppet run to finish | ||
# | ||
# We *must* wait for Puppet Agent to finished applying its prior catalog |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Typo here -- "to finished applying".
Also, this comment should be expanded on a bit more. Probably something like
We must wait for the puppet agent to finish applying its catalog before we stop all of our services. Otherwise if the catalog has additional resources that start our services (e.g. such as those from the PE module), then the install will fail to proceed.
i.e. it isn't something specific to pxp-agent, it applies to all services.
templates/install_puppet.ps1.erb
Outdated
[String] $message | ||
) | ||
begin { | ||
$message | Out-File -FilePath $Logfile -Append |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May be worth including a timestamp.
122896c
to
abd4c6a
Compare
This commit updates the installation method on windows to use a powershell script rather than a batch file
abd4c6a
to
dd14ad0
Compare
$InstallDir = Find-InstallDir | ||
if (Test-Path "$InstallDir\puppet\bin\puppetres.dll") { | ||
Write-Log "Moving puppetres.dll to $temp_puppetres" | ||
Move-Item -Path "$InstallDir\puppet\bin\puppetres.dll" -Destination $temp_puppetres |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 I wasn't sure if this would work the same in PowerShell. Guess it does :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ship it!
# correctly from the module. | ||
[parameter(Position=0)] | ||
[String] $PuppetPID, | ||
[String] $Source='<%= @_msi_location %>', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering if we should be passing params via the invocation, rather than injecting values into a template. I think the only reason we used a template on the batch side was because arg passing with batch can be a real pain.
# PuppetPID _must_ come first!, this script needs PuppetPID to be a positional parameter to execute | ||
# correctly from the module. | ||
[parameter(Position=0)] | ||
[String] $PuppetPID, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be a numeric value, shouldn't it?
) | ||
# Find-InstallDir, Move-PuppetresDLL and Reset-PuppetresDLL serve as a workaround for older | ||
# installations of puppet: we used to need to move puppetres.dll out of the way during puppet | ||
# upgrades because the file would lock and cause network stack restarts. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's one possibility, but the problem was a little more subtle.
Any application connected to the event log - like a local event log collector application or the PowerShell cmdlets, loads / locks all the resource DLLs registered to the event log. This means the event log service holds a lock on puppetres.dll
.
Because Windows will share svchost.exe
instances amongst multiple services, any services co-located to the same process as the event log will get bounced, even when just the event log service needs to be restarted. Furthermore, in the event that one of the other hosted services was a dependency of yet other services, it would cause a domino effect. So in the worst case situation, I believe we saw DHCP being shared with Event Log. Higher level services like Exchange Server depended on DHCP, which caused cascading service restarts.
It may be sufficient to mention network stack restarts, but that's just one of the ways this manifested depending on version of OS, which services Windows decided to share with event log, etc, etc.
Fetch the location of the puppet installation from the registry | ||
#> | ||
function Script:Find-InstallDir { | ||
begin { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this function doesn't accept pipeline input, begin
, process
, end
are superfluous.
@@ -0,0 +1,262 @@ | |||
# install_puppet.ps1 | |||
<# |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On a similar note about this being a template... these inline docs won't inform the PowerShell runtime during test / debugging since it's not a PS1 until rendered.
Reset-PuppetresDLL $temp_puppetres | ||
} | ||
} finally { | ||
Unlock-Installation $install_pid_lock |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you also want to call Unregister-Event
to perform cleanup... though exiting PowerShell altogether may do this for you
This commit updates the installation method on windows to use a powershell
script rather than a batch file