Tentacle can detect Powershell scripts that don't start, and can abandon them.#1200
Tentacle can detect Powershell scripts that don't start, and can abandon them.#1200LukeButters merged 31 commits intomainfrom
Conversation
…ssue so no need to have it for *nix
…ent comment exist
This reverts commit 4300b37.
…nt in the script body
5a599f2 to
5bb0dd6
Compare
| /// but silently stall before executing any script content. This was seen happening because | ||
| /// CrowdStrike prevented the script body from running. | ||
| /// | ||
| /// When this happens, we get no output from the script AND the script is un-killable. |
There was a problem hiding this comment.
Is this because it deviates from what we expect or can we literally not kill the powershell process?
There was a problem hiding this comment.
Tentacle is unable to kill the script, with whatever the standard kill command dotnet uses.
We have taken dumps and seen crowdstrike is in the dump, I never saw the dump myself though.
I suspect the issue is something like powershell calls something that enters the kernel which hangs. Since it is in the kernel it can never be killed.
rhysparry
left a comment
There was a problem hiding this comment.
I'm a little unclear on the cancellation behaviour.
| readonly IOctopusFileSystem fileSystem; | ||
| readonly IHomeDirectoryProvider home; | ||
| readonly SensitiveValueMasker sensitiveValueMasker; | ||
| readonly bool useBashWorkspace; |
There was a problem hiding this comment.
Should this be an enum to select a specific workspace type?
| [IntegrationTestTimeout] | ||
| public class PowerShellStartupDetectionTests : IntegrationTest | ||
| { | ||
| static (ScriptServiceV2 service, ScriptWorkspaceFactory workspaceFactory, ScriptStateStoreFactory stateStoreFactory, TemporaryDirectory tempDir) CreateScriptService( |
There was a problem hiding this comment.
Can we replace this with a nested class? It should implement IDisposable for the TemporaryDirectory.
rhysparry
left a comment
There was a problem hiding this comment.
💚 Just a few minor nits. Otherwise, LGTM.
| Bash, | ||
| PowerShell | ||
| } | ||
| } No newline at end of file |
There was a problem hiding this comment.
nit: missing newline at end of file
|
|
||
| await DeletePotentiallyInUseFile(stillRunning); | ||
| await Task.Delay(TimeSpan.FromSeconds(5)); | ||
| File.Exists(stillRunning).Should().BeFalse("Otherwise the script is still running and we made not effort to cancel it."); |
There was a problem hiding this comment.
nit:
| File.Exists(stillRunning).Should().BeFalse("Otherwise the script is still running and we made not effort to cancel it."); | |
| File.Exists(stillRunning).Should().BeFalse("Otherwise the script is still running and we made no effort to cancel it."); |
| $"{shellPath} process did not start within {powerShellStartupTimeout.TotalMinutes} minutes. Script execution aborted."); | ||
|
|
||
| // The script has not started, and the files on disk have been arranged, so it will never meaningfully progress. | ||
| // We will now abandon the script, as we do we will cancell its cancellation token. Which will result in |
There was a problem hiding this comment.
nit:
| // We will now abandon the script, as we do we will cancell its cancellation token. Which will result in | |
| // We will now abandon the script, as we do we will cancel its cancellation token. Which will result in |
|
|
||
| // The script has not started, and the files on disk have been arranged, so it will never meaningfully progress. | ||
| // We will now abandon the script, as we do we will cancell its cancellation token. Which will result in | ||
| // the script possibly dieing, although from what we have seen, the script will never die. |
There was a problem hiding this comment.
nit:
| // the script possibly dieing, although from what we have seen, the script will never die. | |
| // the script possibly dying, although from what we have seen, the script will never die. |
…time we expect a powershell to start in
Background
When
powershell.exeis invoked to run a script, it can sometimes start the process but never actually begin executing the script body. Additionally the script could never be terminated. This results in hung deployments where we may wait forever for a script that will never complete.Refs: EFT-365
Refs: EFT-3145
Refs: HPY-1295, HPY-1296
Fixes: #1208
#investigation-stuck-tasks-blocking-deployments
Results
This PR introduces a startup detection mechanism that lets Tentacle detect and report when PowerShell never executes the script content.
Scripts that opt in include a special marker comment:
# TENTACLE-POWERSHELL-STARTUP-DETECTION-AND-GUARD-MUST-BE-AT-THE-START-OF-THE-SCRIPTWhen Tentacle bootstraps the script, it replaces this marker with generated detection code that:
.octopus_powershell_startedsentinel file.octopus_powershell_should_runfile (written by Tentacle before execution)Concurrently,
RunningScriptruns a monitoring task alongside the script execution task. If the started file isn't created within the timeout window (default: 5 minutes), the monitor concludes PowerShell never executed the script and returns exit code-47(PowerShellNeverStartedExitCode). Additionally tentacle will ensure the power shell body is never executed.Notes
RunningScriptconstructor (tests use a shorter value)powershell.exe);pwshsupport on Linux/Mac is possible as a follow-upFixes https://github.com/OctopusDeploy/OctopusTentacle/issues/... (optional public issue)
When Octopus feature toggle is enabled
Message written to server task log when PowerShell startup detection is enabled
Warning written to Tentacle logs when it takes longer than the configured timeout to start powershell:
How to review this PR
PowerShellStartupDetection.cs(new) — Generates and injects the detection code; manages sentinel file pathsPowerShellStartupStatus.cs(new) — Enum for monitoring outcomes:NotMonitored,Started,NeverStartedRunningScript.cs— MadeExecuteasync; added concurrent startup monitoring taskScriptWorkspace.cs— Injects detection code during bootstrap when the marker comment is present; creates theshould_runfileScriptExitCodes.cs— AddedPowerShellNeverStartedExitCode=-47StartScriptCommandV2.cs/ExecuteShellScriptCommand.cs— AddedDurationToWaitForPowerShellToStartupparameter to allow configurable timeoutPowerShellStartupDetectionTests.cs(new) — Integration tests covering successful detection, failure detection, monitoring timeout, and scripts without the markerQuality ✔️
Pre-requisites