Skip to content
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

[Issue #125] Runaway process termination on startup #133

Merged

Conversation

oleg-nenashev
Copy link
Member

@oleg-nenashev oleg-nenashev commented Nov 26, 2016

Edited by @NextTurn: Resolves #125. Changes summary:

  • IWinSWExtension now offers hooks for the wrapped process startup/termination
  • Some generic process management logic has been moved from Main to ProcessHelper in WinSW Base
  • New extension point - Runaway Process Killer with some basic tests

This change introduces an extension, which performs automatic termination of runaway processes on startup. Sample configuration:

<?xml version="1.0" encoding="utf-8" ?>
<service>
  <id>SERVICE_NAME</id>
  <name>Jenkins Slave</name>
  <description>This service runs a slave for Jenkins continuous integration system.</description>
  <executable>%BASE%\sleep.bat</executable>
  <arguments></arguments>
  <logmode>rotate</logmode>

  <extensions>
	<!-- This is a sample configuration for the RunawayProcessKiller extension. -->
    <extension enabled="true" className="winsw.Plugins.RunawayProcessKiller.RunawayProcessKillerExtension" id="killOnStartup">
      <!-- Absolute path to the PID file, which stores ID of the previously launched process. -->
      <pidfile>%BASE%\pid.txt</pidfile>
      <!-- Defines the process termination timeout in milliseconds. This timeout will be applied multiple times for each child process. -->
      <stopTimeout>5000</stopTimeout>
      <!-- If true, the parent process will be terminated first if the runaway process gets terminated. -->
      <stopParentFirst>false</stopParentFirst>
    </extension>
  </extensions>
</service>

https://issues.jenkins-ci.org/browse/JENKINS-39231

@oleg-nenashev
Copy link
Member Author

Also created https://github.com/kohsuke/winsw/releases/tag/PR-133 with winsw.exe for evaluation

@oleg-nenashev
Copy link
Member Author

@reviewbybees

@ghost
Copy link

ghost commented Nov 26, 2016

This pull request originates from a CloudBees employee. At CloudBees, we require that all pull requests be reviewed by other CloudBees employees before we seek to have the change accepted. If you want to learn more about our process please see this explanation.

@oleg-nenashev oleg-nenashev changed the title [Issue #125] Process termination on startup [Issue #125] Runaway process termination on startup Nov 28, 2016
@oleg-nenashev
Copy link
Member Author

Plugin documentation will be delivered later once I get #129 integrated

/// <returns>List of child process PIDs</returns>
public static List<int> GetChildPids(int pid)
{
var searcher = new ManagementObjectSearcher("Select * From Win32_Process Where ParentProcessID=" + pid);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this still work with a limited access user? (ie not running as SYSTEM but a locked down (non-admin) service account)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It used to work at least. The code has been just migrated to another place without change, so I do not expect differences

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, missed that :o

@@ -13,7 +13,7 @@ public class XmlHelper
/// </summary>
/// <param name="node">Parent node</param>
/// <param name="tagName">Element name</param>
/// <param name="optional">If otional, don't throw an exception if the elemen is missing</param>
/// <param name="optional">If optional, don't throw an exception if the elemen is missing</param>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you missed the second typo on the line :) (element)

[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("RunawayProcessKiller")]
[assembly: AssemblyCopyright("Copyright © 2015")]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2015?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix it

</PropertyGroup>
<ItemGroup>
<Reference Include="log4net">
<HintPath>..\..\packages\log4net.2.0.5\lib\net20-full\log4net.dll</HintPath>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: does a user need to do more setup now to get log4net so they can compile this project? (where can they obtain it from - is the README updated?)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to do additional steps. log4net is being merged into the executable using ILMerge. A user still gets a single binary

}
else
{
Logger.Warn("The requested PID file '" + Pidfile + "' does not exist. The runaway process won't be checked");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: is this really a warning? - seems like INFO as this is expected (at least for the first time you startup the service)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And for the first time we have no idea if there is a runaway process. So I think it's a valid Warning

}

// Kill the runaway process
ProcessHelper.StopProcessAndChildren(pid, this.StopTimeout, this.StopParentProcessFirst);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is very scary.... on windows PIDs can be reused... and if this is due to a reboot after say patching the PID could depend on the order of startup of services - so you could (attempt) kill a very important system service.

There should be some form of check that the parent process was the one started (perhaps by setting a magic environment cookie - or at least looking like it is a java process aka Jenkins)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed

+ " <id>SERVICE_NAME</id> "
+ " <name>Jenkins Slave</name> "
+ " <description>This service runs a slave for Jenkins continuous integration system.</description> "
+ " <executable>C:\\Program Files\\Java\\jre7\\bin\\java.exe</executable> "
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this test is likely to fail on a CI system like Jenkins if this is needed - if its not - then should really be something like x:\ignored\not\used to avoid confusion.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test does not actually start the executable. Hence should be fine

@jtnord
Copy link

jtnord commented Nov 28, 2016

@oleg-nenashev generally the code looks good - but killing process trees because a PID was left in a file looks very very scary to me - and I fear you could end up killing very important services on a restart of the OS (due to the old PID being used by a different service after restart) at which point you could crash windows (if its a system critical process) and which point you get boot loops....

@oleg-nenashev
Copy link
Member Author

Yes, I agree the process validation needs to be extended

@oleg-nenashev
Copy link
Member Author

@jtnord I have added the check of the Service Id environment of the process, which needs to be terminated

Copy link

@jtnord jtnord left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me

@oleg-nenashev
Copy link
Member Author

@reviewbybees done
Here we go

@oleg-nenashev oleg-nenashev merged commit 62b495f into winsw:master Dec 1, 2016
@oleg-nenashev oleg-nenashev deleted the processTerminationOnStartup branch December 1, 2016 07:03
@oleg-nenashev oleg-nenashev restored the processTerminationOnStartup branch December 3, 2016 14:18
@nxtn nxtn modified the milestones: 2.0.1, 2.0.0 Mar 25, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

New plugin: Terminate runaway processes on startup [JENKINS-39231]
3 participants