If you have had the opportunity to work with Windows slaves for Jenkins, then you probably faced some problems like high memory consumption or directories blocked due to Java Slave service unresponsiveness.

These kind of problems in Windows environmentes get harder and more complicated if you need to execute GUIs from Jenkins using the slave, and for certain kind of testing it's mandatory to execute GUIs.

The problem

The most visible problems I face with, are:

  • Some workspaces blocked, so workspace cleanup is not posible until Slave restart
  • High memory consumption, -> host unresponsive & slow app execution
  • Queued jobs take so much time to get taken from the node

I'm faced with these problems so many times and tries different approaches trying to solve them, but anything works as expected in the end, unti a few days ago, I found the way to solve these problems without restart the host. (In our environment it's not posible to do this automatically because our machines are under a AD Group which has a logon disclaimer policy wich avoids logon into the machine automatically due to company security policies) And now I'm going to share the solution with you.

The solution

Windows doesn't allow to execute graphical applications from a remote connection, so we've to work around this limitation.

I was trying to find a simmilar way of connecting to Windows machines like Unix ones (SSH), but Windows doesn't provide this kind of connectios, the good part is that provides PSRemote sessions, which are similar to SSH. but Microsoft proprieteary.

We can stablish a connection with a remote Windows host with the following sentence:

Enter-PSSession $env:hostname -Credential $cred

This will start an interactive session with the specified host.

So now we have the control, we need to stop the jp2 launcher process, easy:

taskkill /IM jp2launcher.exe /F

And now comes the difficult part, restart the slave with the remote JP2 launcher in GUI mode. We will use Scheduled Tasks, as Windows doesn't know we are going to start one from a remote session, so we will be able to start GUIs from here.

The trick is to register the scheduled task without any trigger, and later will be called from a cmdlet. It will be as simple as launching a simple program.

First, let's create the Scheduled Task:

$existingPSTask = Get-ScheduledTask -TaskName "jenkins-slave-ui"

if (!$existingPSTask) {
    $STName = "jenkins-slave-ui"
    $STAction = New-ScheduledTaskAction -Execute "javaws.exe" -Arguments "http://belvedere.domain.com:6080/computer/$minionname/slave-agent.jnlp"
    $STSettings = New-ScheduledTaskSettingsSet -DontStopOnIdleEnd -ExecutionTimeLimit ([TimeSpan]::Zero) -WakeToRun
    $STPrincipal = New-ScheduledTaskPrincipal -UserID $logonuser -RunLevel "Highest" -LogonType S4U

    Register-ScheduledTask $STName -Action $STAction -Trigger $STTrigger -Principal $STPrincipal -Settings $STSettings
}

We had created a task with the following properties

  • name jenkins-slave-ui
  • action javaws <jnlp path>
  • settings Must be waked up to launch & Don't stop on idle
  • prinicipal login specified user with S4U logon

Voilá, we are able now to launch out jenkins slave with GUI remotely!

Start-ScheduledTask -TaskName jenkins-slave-ui

Now in order to make this solution available to other memebers we should put this code in a shared place like Jenkins shared libraries or a public Job.

This script has to be executed on the target machine, `Start-PSSession` is intended for interactive connection.

For automation usage, use `Invoke-Command`:

Invoke-Command -ComputerName $env:hostname -FilePath ".\scripts\restartMinionsPSRemote.ps1" -Credential $cred -ArgumentList "-minionname", "$env:minion_name", "-logonuser", "$env:logon_user"

That's all folks!