mirror of
https://github.com/actions/runner.git
synced 2025-12-10 12:36:23 +00:00
Compare commits
7 Commits
robherley/
...
fhammerl/2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f2e6c296c7 | ||
|
|
b4e17c4fee | ||
|
|
b1ebc2aae4 | ||
|
|
444f054278 | ||
|
|
dc8b1b685f | ||
|
|
8eacbdc79f | ||
|
|
6b4a95cdb1 |
@@ -1,21 +1,19 @@
|
||||
## Features
|
||||
|
||||
- Bump runtime to dotnet 6 (#1471)
|
||||
- Show service container logs on teardown (#1563)
|
||||
- Add Runner Configuration option to disable auto update `--disableupdate` (#1558)
|
||||
- Introduce `GITHUB_ACTIONS_RUNNER_TLS_NO_VERIFY` env variable to skip SSL Cert Verification on the Runner (#1616)
|
||||
- Adds support for downloading trimmed versions of the runner when the entire package does not need to be upgraded (#1568)
|
||||
|
||||
## Bugs
|
||||
|
||||
- Add masks for multiline secrets from ::add-mask:: (#1521)
|
||||
- fix Log size and retention settings not work (#1507)
|
||||
- Refactor SelfUpdater adding L0 tests. (#1564)
|
||||
- Fix test failure: /bin/sleep on Macos 11 (Monterey) does not accept the suffix s. (#1472)
|
||||
|
||||
- Set Outcome/Conclusion for composite action steps (#1600)
|
||||
|
||||
## Misc
|
||||
|
||||
- Update dependency check for dotnet 6. (#1551)
|
||||
- Produce trimmed down runner packages. (#1556)
|
||||
- Deleted extra background in github-praph.png, which is displayed in README.md (#1432)
|
||||
- Update `run.sh` to more gracefully handle updates (#1494)
|
||||
- Use 8Mb default chunking for File Container Uploads (#1626)
|
||||
- Performance improvements in handling large amounts of live logs (#1592)
|
||||
- Allow `./svc.sh stop` to exit as soon as runner process exits (#1580)
|
||||
- Add additional tracing to help troubleshoot job message corruption (#1587)
|
||||
|
||||
|
||||
## Windows x64
|
||||
|
||||
@@ -1 +1 @@
|
||||
<Update to ./src/runnerversion when creating release>
|
||||
2.287.1
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
@echo off
|
||||
|
||||
"%~dp0\bin\Runner.Listener.exe" run %*
|
||||
|
||||
rem using `if %ERRORLEVEL% EQU N` insterad of `if ERRORLEVEL N`
|
||||
rem `if ERRORLEVEL N` means: error level is N or MORE
|
||||
|
||||
if %ERRORLEVEL% EQU 0 (
|
||||
echo "Runner listener exit with 0 return code, stop the service, no retry needed."
|
||||
exit /b 0
|
||||
)
|
||||
|
||||
if %ERRORLEVEL% EQU 1 (
|
||||
echo "Runner listener exit with terminated error, stop the service, no retry needed."
|
||||
exit /b 0
|
||||
)
|
||||
|
||||
if %ERRORLEVEL% EQU 2 (
|
||||
echo "Runner listener exit with retryable error, re-launch runner in 5 seconds."
|
||||
ping 127.0.0.1 -n 6 -w 1000 >NUL
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
if %ERRORLEVEL% EQU 3 (
|
||||
rem Sleep 5 seconds to wait for the runner update process finish
|
||||
echo "Runner listener exit because of updating, re-launch runner in 5 seconds"
|
||||
ping 127.0.0.1 -n 6 -w 1000 >NUL
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
if %ERRORLEVEL% EQU 4 (
|
||||
rem Sleep 5 seconds to wait for the ephemeral runner update process finish
|
||||
echo "Runner listener exit because of updating, re-launch ephemeral runner in 5 seconds"
|
||||
ping 127.0.0.1 -n 6 -w 1000 >NUL
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo "Exiting after unknown error code: %ERRORLEVEL%"
|
||||
exit /b 0
|
||||
@@ -1,54 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Validate not sudo
|
||||
user_id=`id -u`
|
||||
if [ $user_id -eq 0 -a -z "$RUNNER_ALLOW_RUNASROOT" ]; then
|
||||
echo "Must not run interactively with sudo"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Run
|
||||
shopt -s nocasematch
|
||||
|
||||
safe_sleep() {
|
||||
if [ ! -x "$(command -v sleep)" ]; then
|
||||
if [ ! -x "$(command -v ping)" ]; then
|
||||
COUNT="0"
|
||||
while [[ $COUNT != 5000 ]]; do
|
||||
echo "SLEEP" > /dev/null
|
||||
COUNT=$[$COUNT+1]
|
||||
done
|
||||
else
|
||||
ping -c 5 127.0.0.1 > /dev/null
|
||||
fi
|
||||
else
|
||||
sleep 5
|
||||
fi
|
||||
}
|
||||
|
||||
bin/Runner.Listener run $*
|
||||
returnCode=$?
|
||||
if [[ $returnCode == 0 ]]; then
|
||||
echo "Runner listener exit with 0 return code, stop the service, no retry needed."
|
||||
exit 0
|
||||
elif [[ $returnCode == 1 ]]; then
|
||||
echo "Runner listener exit with terminated error, stop the service, no retry needed."
|
||||
exit 0
|
||||
elif [[ $returnCode == 2 ]]; then
|
||||
echo "Runner listener exit with retryable error, re-launch runner in 5 seconds."
|
||||
safe_sleep
|
||||
exit 1
|
||||
elif [[ $returnCode == 3 ]]; then
|
||||
# Sleep 5 seconds to wait for the runner update process finish
|
||||
echo "Runner listener exit because of updating, re-launch runner in 5 seconds"
|
||||
safe_sleep
|
||||
exit 1
|
||||
elif [[ $returnCode == 4 ]]; then
|
||||
# Sleep 5 seconds to wait for the ephemeral runner update process finish
|
||||
echo "Runner listener exit because of updating, re-launch ephemeral runner in 5 seconds"
|
||||
safe_sleep
|
||||
exit 1
|
||||
else
|
||||
echo "Exiting with unknown error code: ${returnCode}"
|
||||
exit 0
|
||||
fi
|
||||
@@ -13,19 +13,21 @@ if defined VERBOSE_ARG (
|
||||
rem Unblock files in the root of the layout folder. E.g. .cmd files.
|
||||
powershell.exe -NoLogo -Sta -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command "$VerbosePreference = %VERBOSE_ARG% ; Get-ChildItem -LiteralPath '%~dp0' | ForEach-Object { Write-Verbose ('Unblock: {0}' -f $_.FullName) ; $_ } | Unblock-File | Out-Null"
|
||||
|
||||
if /i "%~1" equ "localRun" (
|
||||
rem ********************************************************************************
|
||||
rem Local run.
|
||||
rem ********************************************************************************
|
||||
"%~dp0bin\Runner.Listener.exe" %*
|
||||
) else (
|
||||
rem ********************************************************************************
|
||||
rem Run.
|
||||
rem ********************************************************************************
|
||||
"%~dp0bin\Runner.Listener.exe" run %*
|
||||
|
||||
rem ********************************************************************************
|
||||
rem Run.
|
||||
rem ********************************************************************************
|
||||
|
||||
:launch_helper
|
||||
copy run-helper.cmd.template run-helper.cmd /Y
|
||||
call "%~dp0run-helper.cmd" %*
|
||||
|
||||
if %ERRORLEVEL% EQU 1 (
|
||||
echo "Restarting runner..."
|
||||
goto :launch_helper
|
||||
) else (
|
||||
echo "Exiting runner..."
|
||||
exit 0
|
||||
rem Return code 4 means the run once runner received an update message.
|
||||
rem Sleep 5 seconds to wait for the update process finish and run the runner again.
|
||||
if ERRORLEVEL 4 (
|
||||
timeout /t 5 /nobreak > NUL
|
||||
"%~dp0bin\Runner.Listener.exe" run %*
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,24 +1,64 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Validate not sudo
|
||||
user_id=`id -u`
|
||||
if [ $user_id -eq 0 -a -z "$RUNNER_ALLOW_RUNASROOT" ]; then
|
||||
echo "Must not run interactively with sudo"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Change directory to the script root directory
|
||||
# https://stackoverflow.com/questions/59895/getting-the-source-directory-of-a-bash-script-from-within
|
||||
SOURCE="${BASH_SOURCE[0]}"
|
||||
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
SOURCE="$(readlink "$SOURCE")"
|
||||
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
SOURCE="$(readlink "$SOURCE")"
|
||||
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
|
||||
done
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
cp -f run-helper.sh.template run-helper.sh
|
||||
# run the helper process which keep the listener alive
|
||||
while :;
|
||||
do
|
||||
"$DIR"/run-helper.sh $*
|
||||
|
||||
# Do not "cd $DIR". For localRun, the current directory is expected to be the repo location on disk.
|
||||
|
||||
# Run
|
||||
shopt -s nocasematch
|
||||
if [[ "$1" == "localRun" ]]; then
|
||||
"$DIR"/bin/Runner.Listener $*
|
||||
else
|
||||
"$DIR"/bin/Runner.Listener run $*
|
||||
|
||||
# Return code 3 means the run once runner received an update message.
|
||||
# Sleep 5 seconds to wait for the update process finish
|
||||
returnCode=$?
|
||||
if [[ $returnCode == 1 ]]; then
|
||||
echo "Restarting runner..."
|
||||
if [[ $returnCode == 3 ]]; then
|
||||
if [ ! -x "$(command -v sleep)" ]; then
|
||||
if [ ! -x "$(command -v ping)" ]; then
|
||||
COUNT="0"
|
||||
while [[ $COUNT != 5000 ]]; do
|
||||
echo "SLEEP" > /dev/null
|
||||
COUNT=$[$COUNT+1]
|
||||
done
|
||||
else
|
||||
ping -c 5 127.0.0.1 > /dev/null
|
||||
fi
|
||||
else
|
||||
sleep 5
|
||||
fi
|
||||
elif [[ $returnCode == 4 ]]; then
|
||||
if [ ! -x "$(command -v sleep)" ]; then
|
||||
if [ ! -x "$(command -v ping)" ]; then
|
||||
COUNT="0"
|
||||
while [[ $COUNT != 5000 ]]; do
|
||||
echo "SLEEP" > /dev/null
|
||||
COUNT=$[$COUNT+1]
|
||||
done
|
||||
else
|
||||
ping -c 5 127.0.0.1 > /dev/null
|
||||
fi
|
||||
else
|
||||
sleep 5
|
||||
fi
|
||||
"$DIR"/bin/Runner.Listener run $*
|
||||
else
|
||||
echo "Exiting runner..."
|
||||
exit 0
|
||||
exit $returnCode
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
@@ -33,6 +33,9 @@ namespace GitHub.Runner.Common
|
||||
[DataMember(EmitDefaultValue = false)]
|
||||
public string PoolName { get; set; }
|
||||
|
||||
[DataMember(EmitDefaultValue = false)]
|
||||
public bool DisableUpdate { get; set; }
|
||||
|
||||
[DataMember(EmitDefaultValue = false)]
|
||||
public bool Ephemeral { get; set; }
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ namespace GitHub.Runner.Common
|
||||
Externals,
|
||||
Root,
|
||||
Actions,
|
||||
StepSummary,
|
||||
Temp,
|
||||
Tools,
|
||||
Update,
|
||||
@@ -130,6 +129,7 @@ namespace GitHub.Runner.Common
|
||||
public static readonly string Ephemeral = "ephemeral";
|
||||
public static readonly string Help = "help";
|
||||
public static readonly string Replace = "replace";
|
||||
public static readonly string DisableUpdate = "disableupdate";
|
||||
public static readonly string Once = "once"; // Keep this around since customers still relies on it
|
||||
public static readonly string RunAsService = "runasservice";
|
||||
public static readonly string Unattended = "unattended";
|
||||
@@ -197,7 +197,6 @@ namespace GitHub.Runner.Common
|
||||
public static readonly string DiagDirectory = "_diag";
|
||||
public static readonly string ExternalsDirectory = "externals";
|
||||
public static readonly string RunnerDiagnosticLogPrefix = "Runner_";
|
||||
public static readonly string StepSummaryDirectory = "_step_summary";
|
||||
public static readonly string TempDirectory = "_temp";
|
||||
public static readonly string ToolDirectory = "_tool";
|
||||
public static readonly string UpdateDirectory = "_update";
|
||||
|
||||
@@ -243,12 +243,6 @@ namespace GitHub.Runner.Common
|
||||
path = new DirectoryInfo(GetDirectory(WellKnownDirectory.Bin)).Parent.FullName;
|
||||
break;
|
||||
|
||||
case WellKnownDirectory.StepSummary:
|
||||
path = Path.Combine(
|
||||
GetDirectory(WellKnownDirectory.Temp),
|
||||
Constants.Path.StepSummaryDirectory);
|
||||
break;
|
||||
|
||||
case WellKnownDirectory.Temp:
|
||||
path = Path.Combine(
|
||||
GetDirectory(WellKnownDirectory.Work),
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace GitHub.Runner.Listener
|
||||
{
|
||||
Constants.Runner.CommandLine.Flags.Check,
|
||||
Constants.Runner.CommandLine.Flags.Commit,
|
||||
Constants.Runner.CommandLine.Flags.DisableUpdate,
|
||||
Constants.Runner.CommandLine.Flags.Ephemeral,
|
||||
Constants.Runner.CommandLine.Flags.Help,
|
||||
Constants.Runner.CommandLine.Flags.Once,
|
||||
@@ -68,6 +69,7 @@ namespace GitHub.Runner.Listener
|
||||
public bool Unattended => TestFlag(Constants.Runner.CommandLine.Flags.Unattended);
|
||||
public bool Version => TestFlag(Constants.Runner.CommandLine.Flags.Version);
|
||||
public bool Ephemeral => TestFlag(Constants.Runner.CommandLine.Flags.Ephemeral);
|
||||
public bool DisableUpdate => TestFlag(Constants.Runner.CommandLine.Flags.DisableUpdate);
|
||||
|
||||
// Keep this around since customers still relies on it
|
||||
public bool RunOnce => TestFlag(Constants.Runner.CommandLine.Flags.Once);
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace GitHub.Runner.Listener.Configuration
|
||||
Trace.Info(nameof(LoadSettings));
|
||||
if (!IsConfigured())
|
||||
{
|
||||
throw new NonRetryableException("Not configured. Run config.(sh/cmd) to configure the runner.");
|
||||
throw new InvalidOperationException("Not configured. Run config.(sh/cmd) to configure the runner.");
|
||||
}
|
||||
|
||||
RunnerSettings settings = _store.GetSettings();
|
||||
@@ -196,6 +196,7 @@ namespace GitHub.Runner.Listener.Configuration
|
||||
TaskAgent agent;
|
||||
while (true)
|
||||
{
|
||||
runnerSettings.DisableUpdate = command.DisableUpdate;
|
||||
runnerSettings.Ephemeral = command.Ephemeral;
|
||||
runnerSettings.AgentName = command.GetRunnerName();
|
||||
|
||||
@@ -213,11 +214,22 @@ namespace GitHub.Runner.Listener.Configuration
|
||||
if (command.GetReplace())
|
||||
{
|
||||
// Update existing agent with new PublicKey, agent version.
|
||||
agent = UpdateExistingAgent(agent, publicKey, userLabels, runnerSettings.Ephemeral);
|
||||
agent = UpdateExistingAgent(agent, publicKey, userLabels, runnerSettings.Ephemeral, command.DisableUpdate);
|
||||
|
||||
try
|
||||
{
|
||||
agent = await _runnerServer.ReplaceAgentAsync(runnerSettings.PoolId, agent);
|
||||
if (command.DisableUpdate &&
|
||||
command.DisableUpdate != agent.DisableUpdate)
|
||||
{
|
||||
throw new NotSupportedException("The GitHub server does not support configuring a self-hosted runner with 'DisableUpdate' flag.");
|
||||
}
|
||||
if (command.Ephemeral &&
|
||||
command.Ephemeral != agent.Ephemeral)
|
||||
{
|
||||
throw new NotSupportedException("The GitHub server does not support configuring a self-hosted runner with 'Ephemeral' flag.");
|
||||
}
|
||||
|
||||
_term.WriteSuccessMessage("Successfully replaced the runner");
|
||||
break;
|
||||
}
|
||||
@@ -236,11 +248,22 @@ namespace GitHub.Runner.Listener.Configuration
|
||||
else
|
||||
{
|
||||
// Create a new agent.
|
||||
agent = CreateNewAgent(runnerSettings.AgentName, publicKey, userLabels, runnerSettings.Ephemeral);
|
||||
agent = CreateNewAgent(runnerSettings.AgentName, publicKey, userLabels, runnerSettings.Ephemeral, command.DisableUpdate);
|
||||
|
||||
try
|
||||
{
|
||||
agent = await _runnerServer.AddAgentAsync(runnerSettings.PoolId, agent);
|
||||
if (command.DisableUpdate &&
|
||||
command.DisableUpdate != agent.DisableUpdate)
|
||||
{
|
||||
throw new NotSupportedException("The GitHub server does not support configuring a self-hosted runner with 'DisableUpdate' flag.");
|
||||
}
|
||||
if (command.Ephemeral &&
|
||||
command.Ephemeral != agent.Ephemeral)
|
||||
{
|
||||
throw new NotSupportedException("The GitHub server does not support configuring a self-hosted runner with 'Ephemeral' flag.");
|
||||
}
|
||||
|
||||
_term.WriteSuccessMessage("Runner successfully added");
|
||||
break;
|
||||
}
|
||||
@@ -466,7 +489,7 @@ namespace GitHub.Runner.Listener.Configuration
|
||||
}
|
||||
|
||||
|
||||
private TaskAgent UpdateExistingAgent(TaskAgent agent, RSAParameters publicKey, ISet<string> userLabels, bool ephemeral)
|
||||
private TaskAgent UpdateExistingAgent(TaskAgent agent, RSAParameters publicKey, ISet<string> userLabels, bool ephemeral, bool disableUpdate)
|
||||
{
|
||||
ArgUtil.NotNull(agent, nameof(agent));
|
||||
agent.Authorization = new TaskAgentAuthorization
|
||||
@@ -478,6 +501,7 @@ namespace GitHub.Runner.Listener.Configuration
|
||||
agent.Version = BuildConstants.RunnerPackage.Version;
|
||||
agent.OSDescription = RuntimeInformation.OSDescription;
|
||||
agent.Ephemeral = ephemeral;
|
||||
agent.DisableUpdate = disableUpdate;
|
||||
agent.MaxParallelism = 1;
|
||||
|
||||
agent.Labels.Clear();
|
||||
@@ -494,7 +518,7 @@ namespace GitHub.Runner.Listener.Configuration
|
||||
return agent;
|
||||
}
|
||||
|
||||
private TaskAgent CreateNewAgent(string agentName, RSAParameters publicKey, ISet<string> userLabels, bool ephemeral)
|
||||
private TaskAgent CreateNewAgent(string agentName, RSAParameters publicKey, ISet<string> userLabels, bool ephemeral, bool disableUpdate)
|
||||
{
|
||||
TaskAgent agent = new TaskAgent(agentName)
|
||||
{
|
||||
@@ -506,6 +530,7 @@ namespace GitHub.Runner.Listener.Configuration
|
||||
Version = BuildConstants.RunnerPackage.Version,
|
||||
OSDescription = RuntimeInformation.OSDescription,
|
||||
Ephemeral = ephemeral,
|
||||
DisableUpdate = disableUpdate
|
||||
};
|
||||
|
||||
agent.Labels.Add(new AgentLabel("self-hosted", LabelType.System));
|
||||
|
||||
@@ -408,7 +408,7 @@ namespace GitHub.Runner.Listener
|
||||
autoUpdateInProgress = true;
|
||||
var runnerUpdateMessage = JsonUtility.FromString<AgentRefreshMessage>(message.Body);
|
||||
var selfUpdater = HostContext.GetService<ISelfUpdater>();
|
||||
selfUpdateTask = selfUpdater.SelfUpdate(runnerUpdateMessage, jobDispatcher, false, HostContext.RunnerShutdownToken);
|
||||
selfUpdateTask = selfUpdater.SelfUpdate(runnerUpdateMessage, jobDispatcher, !runOnce && HostContext.StartupType != StartupType.Service, HostContext.RunnerShutdownToken);
|
||||
Trace.Info("Refresh message received, kick-off selfupdate background process.");
|
||||
}
|
||||
else
|
||||
@@ -540,6 +540,7 @@ Config Options:
|
||||
--work string Relative runner work directory (default {Constants.Path.WorkDirectory})
|
||||
--replace Replace any existing runner with the same name (default false)
|
||||
--pat GitHub personal access token used for checking network connectivity when executing `.{separator}run.{ext} --check`
|
||||
--disableupdate Disable self-hosted runner automatic update to the latest released version`
|
||||
--ephemeral Configure the runner to only take one job and then let the service un-configure the runner after the job finishes (default false)");
|
||||
|
||||
#if OS_WINDOWS
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace GitHub.Runner.Listener
|
||||
private IRunnerServer _runnerServer;
|
||||
private int _poolId;
|
||||
private int _agentId;
|
||||
private readonly ConcurrentQueue<string> _updateTrace = new ConcurrentQueue<string>();
|
||||
private readonly List<string> _updateTrace = new List<string>();
|
||||
private Task _cloneAndCalculateContentHashTask;
|
||||
private string _dotnetRuntimeCloneDirectory;
|
||||
private string _externalsCloneDirectory;
|
||||
@@ -80,7 +80,7 @@ namespace GitHub.Runner.Listener
|
||||
}
|
||||
|
||||
Trace.Info($"An update is available.");
|
||||
_updateTrace.Enqueue($"RunnerPlatform: {_targetPackage.Platform}");
|
||||
_updateTrace.Add($"RunnerPlatform: {_targetPackage.Platform}");
|
||||
|
||||
// Print console line that warn user not shutdown runner.
|
||||
await UpdateRunnerUpdateStateAsync("Runner update in progress, do not shutdown runner.");
|
||||
@@ -120,7 +120,7 @@ namespace GitHub.Runner.Listener
|
||||
Trace.Info($"Delete old version runner backup.");
|
||||
stopWatch.Stop();
|
||||
// generate update script from template
|
||||
_updateTrace.Enqueue($"DeleteRunnerBackupTime: {stopWatch.ElapsedMilliseconds}ms");
|
||||
_updateTrace.Add($"DeleteRunnerBackupTime: {stopWatch.ElapsedMilliseconds}ms");
|
||||
await UpdateRunnerUpdateStateAsync("Generate and execute update script.");
|
||||
|
||||
string updateScript = GenerateUpdateScript(restartInteractiveRunner);
|
||||
@@ -145,14 +145,14 @@ namespace GitHub.Runner.Listener
|
||||
|
||||
totalUpdateTime.Stop();
|
||||
|
||||
_updateTrace.Enqueue($"TotalUpdateTime: {totalUpdateTime.ElapsedMilliseconds}ms");
|
||||
_updateTrace.Add($"TotalUpdateTime: {totalUpdateTime.ElapsedMilliseconds}ms");
|
||||
await UpdateRunnerUpdateStateAsync("Runner will exit shortly for update, should be back online within 10 seconds.");
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_updateTrace.Enqueue(ex.ToString());
|
||||
_updateTrace.Add(ex.ToString());
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
@@ -260,9 +260,9 @@ namespace GitHub.Runner.Listener
|
||||
}
|
||||
}
|
||||
|
||||
_updateTrace.Enqueue($"DownloadUrl: {packageDownloadUrl}");
|
||||
_updateTrace.Enqueue($"RuntimeTrimmed: {runtimeTrimmed}");
|
||||
_updateTrace.Enqueue($"ExternalsTrimmed: {externalsTrimmed}");
|
||||
_updateTrace.Add($"DownloadUrl: {packageDownloadUrl}");
|
||||
_updateTrace.Add($"RuntimeTrimmed: {runtimeTrimmed}");
|
||||
_updateTrace.Add($"ExternalsTrimmed: {externalsTrimmed}");
|
||||
|
||||
try
|
||||
{
|
||||
@@ -328,14 +328,14 @@ namespace GitHub.Runner.Listener
|
||||
if (fallbackToFullPackage)
|
||||
{
|
||||
Trace.Error("Something wrong with the trimmed runner package, failback to use the full package for runner updates.");
|
||||
_updateTrace.Enqueue($"FallbackToFullPackage: {fallbackToFullPackage}");
|
||||
_updateTrace.Add($"FallbackToFullPackage: {fallbackToFullPackage}");
|
||||
|
||||
IOUtil.DeleteDirectory(latestRunnerDirectory, token);
|
||||
Directory.CreateDirectory(latestRunnerDirectory);
|
||||
|
||||
packageDownloadUrl = _targetPackage.DownloadUrl;
|
||||
packageHashValue = _targetPackage.HashValue;
|
||||
_updateTrace.Enqueue($"DownloadUrl: {packageDownloadUrl}");
|
||||
_updateTrace.Add($"DownloadUrl: {packageDownloadUrl}");
|
||||
|
||||
try
|
||||
{
|
||||
@@ -453,9 +453,9 @@ namespace GitHub.Runner.Listener
|
||||
Trace.Info($"Download runner: finished download");
|
||||
downloadSucceeded = true;
|
||||
stopWatch.Stop();
|
||||
_updateTrace.Enqueue($"PackageDownloadTime: {stopWatch.ElapsedMilliseconds}ms");
|
||||
_updateTrace.Enqueue($"Attempts: {attempt}");
|
||||
_updateTrace.Enqueue($"PackageSize: {downloadSize / 1024 / 1024}MB");
|
||||
_updateTrace.Add($"PackageDownloadTime: {stopWatch.ElapsedMilliseconds}ms");
|
||||
_updateTrace.Add($"Attempts: {attempt}");
|
||||
_updateTrace.Add($"PackageSize: {downloadSize / 1024 / 1024}MB");
|
||||
break;
|
||||
}
|
||||
catch (OperationCanceledException) when (token.IsCancellationRequested)
|
||||
@@ -505,7 +505,7 @@ namespace GitHub.Runner.Listener
|
||||
|
||||
stopWatch.Stop();
|
||||
Trace.Info($"Validated Runner Hash matches {archiveFile} : {packageHashValue}");
|
||||
_updateTrace.Enqueue($"ValidateHashTime: {stopWatch.ElapsedMilliseconds}ms");
|
||||
_updateTrace.Add($"ValidateHashTime: {stopWatch.ElapsedMilliseconds}ms");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -561,7 +561,7 @@ namespace GitHub.Runner.Listener
|
||||
|
||||
stopWatch.Stop();
|
||||
Trace.Info($"Finished getting latest runner package at: {extractDirectory}.");
|
||||
_updateTrace.Enqueue($"PackageExtractTime: {stopWatch.ElapsedMilliseconds}ms");
|
||||
_updateTrace.Add($"PackageExtractTime: {stopWatch.ElapsedMilliseconds}ms");
|
||||
}
|
||||
|
||||
private Task CopyLatestRunnerToRoot(string latestRunnerDirectory, CancellationToken token)
|
||||
@@ -594,7 +594,7 @@ namespace GitHub.Runner.Listener
|
||||
}
|
||||
|
||||
stopWatch.Stop();
|
||||
_updateTrace.Enqueue($"CopyRunnerToRootTime: {stopWatch.ElapsedMilliseconds}ms");
|
||||
_updateTrace.Add($"CopyRunnerToRootTime: {stopWatch.ElapsedMilliseconds}ms");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
@@ -720,14 +720,9 @@ namespace GitHub.Runner.Listener
|
||||
_terminal.WriteLine(currentState);
|
||||
|
||||
var traces = new List<string>();
|
||||
while (_updateTrace.TryDequeue(out var trace))
|
||||
if (_updateTrace.Count > 0)
|
||||
{
|
||||
traces.Add(trace);
|
||||
}
|
||||
|
||||
if (traces.Count > 0)
|
||||
{
|
||||
foreach (var trace in traces)
|
||||
foreach (var trace in _updateTrace)
|
||||
{
|
||||
Trace.Info(trace);
|
||||
}
|
||||
@@ -735,7 +730,7 @@ namespace GitHub.Runner.Listener
|
||||
|
||||
try
|
||||
{
|
||||
await _runnerServer.UpdateAgentUpdateStateAsync(_poolId, _agentId, currentState, string.Join(Environment.NewLine, traces));
|
||||
await _runnerServer.UpdateAgentUpdateStateAsync(_poolId, _agentId, currentState, string.Join(Environment.NewLine, _updateTrace));
|
||||
_updateTrace.Clear();
|
||||
}
|
||||
catch (VssResourceNotFoundException)
|
||||
@@ -811,7 +806,7 @@ namespace GitHub.Runner.Listener
|
||||
finally
|
||||
{
|
||||
stopWatch.Stop();
|
||||
_updateTrace.Enqueue($"{nameof(RestoreTrimmedExternals)}Time: {stopWatch.ElapsedMilliseconds}ms");
|
||||
_updateTrace.Add($"{nameof(RestoreTrimmedExternals)}Time: {stopWatch.ElapsedMilliseconds}ms");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -863,7 +858,7 @@ namespace GitHub.Runner.Listener
|
||||
finally
|
||||
{
|
||||
stopWatch.Stop();
|
||||
_updateTrace.Enqueue($"{nameof(RestoreTrimmedDotnetRuntime)}Time: {stopWatch.ElapsedMilliseconds}ms");
|
||||
_updateTrace.Add($"{nameof(RestoreTrimmedDotnetRuntime)}Time: {stopWatch.ElapsedMilliseconds}ms");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -894,7 +889,7 @@ namespace GitHub.Runner.Listener
|
||||
var externalsHash = await HashFiles(externalsCloneDirectory, token);
|
||||
Trace.Info($"Externals content hash: {externalsHash}");
|
||||
_contentHashes[_externals] = externalsHash;
|
||||
_updateTrace.Enqueue($"ExternalsHash: {_contentHashes[_externals]}");
|
||||
_updateTrace.Add($"ExternalsHash: {_contentHashes[_externals]}");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -918,7 +913,7 @@ namespace GitHub.Runner.Listener
|
||||
var runtimeHash = await HashFiles(dotnetRuntimeCloneDirectory, token);
|
||||
Trace.Info($"Runtime content hash: {runtimeHash}");
|
||||
_contentHashes[_dotnetRuntime] = runtimeHash;
|
||||
_updateTrace.Enqueue($"DotnetRuntimeHash: {_contentHashes[_dotnetRuntime]}");
|
||||
_updateTrace.Add($"DotnetRuntimeHash: {_contentHashes[_dotnetRuntime]}");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -988,7 +983,7 @@ namespace GitHub.Runner.Listener
|
||||
finally
|
||||
{
|
||||
stopWatch.Stop();
|
||||
_updateTrace.Enqueue($"{nameof(CloneDotnetRuntime)}Time: {stopWatch.ElapsedMilliseconds}ms");
|
||||
_updateTrace.Add($"{nameof(CloneDotnetRuntime)}Time: {stopWatch.ElapsedMilliseconds}ms");
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -1014,7 +1009,7 @@ namespace GitHub.Runner.Listener
|
||||
finally
|
||||
{
|
||||
stopWatch.Stop();
|
||||
_updateTrace.Enqueue($"{nameof(CloneExternals)}Time: {stopWatch.ElapsedMilliseconds}ms");
|
||||
_updateTrace.Add($"{nameof(CloneExternals)}Time: {stopWatch.ElapsedMilliseconds}ms");
|
||||
}
|
||||
|
||||
return Task.FromResult(false);
|
||||
@@ -1068,7 +1063,7 @@ namespace GitHub.Runner.Listener
|
||||
}
|
||||
|
||||
stopWatch.Stop();
|
||||
_updateTrace.Enqueue($"{nameof(HashFiles)}{Path.GetFileName(fileFolder)}Time: {stopWatch.ElapsedMilliseconds}ms");
|
||||
_updateTrace.Add($"{nameof(HashFiles)}{Path.GetFileName(fileFolder)}Time: {stopWatch.ElapsedMilliseconds}ms");
|
||||
return hashResult;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -469,7 +469,7 @@ namespace GitHub.Runner.Plugins.Artifact
|
||||
try
|
||||
{
|
||||
uploadTimer.Restart();
|
||||
using (HttpResponseMessage response = await _fileContainerHttpClient.UploadFileAsync(_containerId, itemPath, fs, _projectId, cancellationToken: token, chunkSize: 4 * 1024 * 1024))
|
||||
using (HttpResponseMessage response = await _fileContainerHttpClient.UploadFileAsync(_containerId, itemPath, fs, _projectId, cancellationToken: token))
|
||||
{
|
||||
if (response == null || response.StatusCode != HttpStatusCode.Created)
|
||||
{
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
using GitHub.DistributedTask.WebApi;
|
||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||
using GitHub.Runner.Common.Util;
|
||||
using GitHub.Services.Common;
|
||||
using GitHub.Services.WebApi;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net.Http;
|
||||
using GitHub.DistributedTask.WebApi;
|
||||
using GitHub.Runner.Common;
|
||||
using GitHub.Runner.Common.Util;
|
||||
using GitHub.Runner.Sdk;
|
||||
using GitHub.Services.Common;
|
||||
using GitHub.Services.WebApi;
|
||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||
|
||||
namespace GitHub.Runner.Worker
|
||||
{
|
||||
@@ -25,6 +25,7 @@ namespace GitHub.Runner.Worker
|
||||
public sealed class JobRunner : RunnerService, IJobRunner
|
||||
{
|
||||
private IJobServerQueue _jobServerQueue;
|
||||
private RunnerSettings _runnerSettings;
|
||||
private ITempDirectoryManager _tempDirectoryManager;
|
||||
|
||||
public async Task<TaskResult> RunAsync(Pipelines.AgentJobRequestMessage message, CancellationToken jobRequestCancellationToken)
|
||||
@@ -108,8 +109,8 @@ namespace GitHub.Runner.Worker
|
||||
jobContext.SetRunnerContext("os", VarUtil.OS);
|
||||
jobContext.SetRunnerContext("arch", VarUtil.OSArchitecture);
|
||||
|
||||
var runnerSettings = HostContext.GetService<IConfigurationStore>().GetSettings();
|
||||
jobContext.SetRunnerContext("name", runnerSettings.AgentName);
|
||||
_runnerSettings = HostContext.GetService<IConfigurationStore>().GetSettings();
|
||||
jobContext.SetRunnerContext("name", _runnerSettings.AgentName);
|
||||
|
||||
string toolsDirectory = HostContext.GetDirectory(WellKnownDirectory.Tools);
|
||||
Directory.CreateDirectory(toolsDirectory);
|
||||
@@ -209,6 +210,53 @@ namespace GitHub.Runner.Worker
|
||||
jobContext.Debug($"Finishing: {message.JobDisplayName}");
|
||||
TaskResult result = jobContext.Complete(taskResult);
|
||||
|
||||
if (_runnerSettings.DisableUpdate == true)
|
||||
{
|
||||
try
|
||||
{
|
||||
var currentVersion = new PackageVersion(BuildConstants.RunnerPackage.Version);
|
||||
ServiceEndpoint systemConnection = message.Resources.Endpoints.Single(x => string.Equals(x.Name, WellKnownServiceEndpointNames.SystemVssConnection, StringComparison.OrdinalIgnoreCase));
|
||||
VssCredentials serverCredential = VssUtil.GetVssCredential(systemConnection);
|
||||
|
||||
var runnerServer = HostContext.GetService<IRunnerServer>();
|
||||
await runnerServer.ConnectAsync(systemConnection.Url, serverCredential);
|
||||
var serverPackages = await runnerServer.GetPackagesAsync("agent", BuildConstants.RunnerPackage.PackageName, 5, includeToken: false, cancellationToken: CancellationToken.None);
|
||||
if (serverPackages.Count > 0)
|
||||
{
|
||||
serverPackages = serverPackages.OrderByDescending(x => x.Version).ToList();
|
||||
Trace.Info($"Newer packages {StringUtil.ConvertToJson(serverPackages.Select(x => x.Version.ToString()))}");
|
||||
|
||||
var warnOnFailedJob = false; // any minor/patch version behind.
|
||||
var warnOnOldRunnerVersion = false; // >= 2 minor version behind
|
||||
if (serverPackages.Any(x => x.Version.CompareTo(currentVersion) > 0))
|
||||
{
|
||||
Trace.Info($"Current runner version {currentVersion} is behind the latest runner version {serverPackages[0].Version}.");
|
||||
warnOnFailedJob = true;
|
||||
}
|
||||
|
||||
if (serverPackages.Where(x => x.Version.Major == currentVersion.Major && x.Version.Minor > currentVersion.Minor).Count() > 1)
|
||||
{
|
||||
Trace.Info($"Current runner version {currentVersion} is way behind the latest runner version {serverPackages[0].Version}.");
|
||||
warnOnOldRunnerVersion = true;
|
||||
}
|
||||
|
||||
if (result == TaskResult.Failed && warnOnFailedJob)
|
||||
{
|
||||
jobContext.Warning($"This job failure may be caused by using an out of date self-hosted runner. You are currently using runner version {currentVersion}. Please update to the latest version {serverPackages[0].Version}");
|
||||
}
|
||||
else if (warnOnOldRunnerVersion)
|
||||
{
|
||||
jobContext.Warning($"This self-hosted runner is currently using runner version {currentVersion}. This version is out of date. Please update to the latest version {serverPackages[0].Version}");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Ignore any error since suggest runner update is best effort.
|
||||
Trace.Error($"Caught exception during runner version check: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await ShutdownQueue(throwOnFailure: true);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -104,10 +103,6 @@ namespace GitHub.Runner.Worker
|
||||
// Set GITHUB_ACTION
|
||||
step.ExecutionContext.SetGitHubContext("action", actionStep.Action.Name);
|
||||
|
||||
var stepSummaryFilePath = CreateStepSummaryFile(step);
|
||||
step.ExecutionContext.SetGitHubContext("step_summary", stepSummaryFilePath);
|
||||
envContext["GITHUB_STEP_SUMMARY"] = new StringContextData(stepSummaryFilePath);
|
||||
|
||||
try
|
||||
{
|
||||
// Evaluate and merge step env
|
||||
@@ -357,52 +352,7 @@ namespace GitHub.Runner.Worker
|
||||
{
|
||||
var executionContext = step.ExecutionContext;
|
||||
|
||||
CreateSummaryAttachment(step);
|
||||
|
||||
executionContext.Complete(result, resultCode: resultCode);
|
||||
}
|
||||
|
||||
private string CreateStepSummaryFile(IStep step)
|
||||
{
|
||||
var stepSummaryDirectory = HostContext.GetDirectory(WellKnownDirectory.StepSummary);
|
||||
if (!Directory.Exists(stepSummaryDirectory))
|
||||
{
|
||||
Trace.Info($"Creating step summary directory: {stepSummaryDirectory}");
|
||||
Directory.CreateDirectory(stepSummaryDirectory);
|
||||
}
|
||||
|
||||
var stepID = step.ExecutionContext.Id;
|
||||
var stepSummaryFilePath = Path.Combine(stepSummaryDirectory, $"{stepID}.md");
|
||||
|
||||
Trace.Info($"Creating step summary file: {stepSummaryFilePath}");
|
||||
File.Create(stepSummaryFilePath).Close();
|
||||
return stepSummaryFilePath;
|
||||
}
|
||||
|
||||
private void CreateSummaryAttachment(IStep step) {
|
||||
var executionContext = step.ExecutionContext;
|
||||
var parentContext = executionContext.Root;
|
||||
var stepSummaryFilePath = executionContext.GetGitHubContext("step_summary");
|
||||
var stepID = executionContext.Id;
|
||||
|
||||
Trace.Info($"Reading step summary data from {stepSummaryFilePath}");
|
||||
|
||||
var summaryExists = File.Exists(stepSummaryFilePath);
|
||||
if (summaryExists)
|
||||
{
|
||||
Trace.Info($"File exists: {stepSummaryFilePath}");
|
||||
|
||||
var summaryFileIsEmpty = new FileInfo(stepSummaryFilePath).Length == 0;
|
||||
if (summaryFileIsEmpty)
|
||||
{
|
||||
Trace.Info($"Summary file ({summaryFileIsEmpty}) is empty, skipping attachment upload");
|
||||
}
|
||||
else
|
||||
{
|
||||
Trace.Info($"Queueing file ({stepSummaryFilePath}) for attachment upload ({stepID})");
|
||||
parentContext.QueueAttachFile(ChecksAttachmentType.StepSummary, stepID.ToString(), stepSummaryFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace GitHub.DistributedTask.WebApi
|
||||
this.ProvisioningState = referenceToBeCloned.ProvisioningState;
|
||||
this.AccessPoint = referenceToBeCloned.AccessPoint;
|
||||
this.Ephemeral = referenceToBeCloned.Ephemeral;
|
||||
this.DisableUpdate = referenceToBeCloned.DisableUpdate;
|
||||
|
||||
if (referenceToBeCloned.m_links != null)
|
||||
{
|
||||
@@ -92,6 +93,16 @@ namespace GitHub.DistributedTask.WebApi
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not this agent should auto-update to latest version.
|
||||
/// </summary>
|
||||
[DataMember(EmitDefaultValue = false)]
|
||||
public bool? DisableUpdate
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not the agent is online.
|
||||
/// </summary>
|
||||
|
||||
@@ -102,10 +102,4 @@ namespace GitHub.DistributedTask.WebApi
|
||||
public static readonly String FileAttachment = "DistributedTask.Core.FileAttachment";
|
||||
public static readonly String DiagnosticLog = "DistributedTask.Core.DiagnosticLog";
|
||||
}
|
||||
|
||||
[GenerateAllConstants]
|
||||
public class ChecksAttachmentType
|
||||
{
|
||||
public static readonly String StepSummary = "Checks.Step.Summary";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration
|
||||
_serviceControlManager = new Mock<ILinuxServiceControlManager>();
|
||||
#endif
|
||||
|
||||
var expectedAgent = new TaskAgent(_expectedAgentName) { Id = 1 };
|
||||
var expectedAgent = new TaskAgent(_expectedAgentName) { Id = 1, Ephemeral = true, DisableUpdate = true };
|
||||
expectedAgent.Authorization = new TaskAgentAuthorization
|
||||
{
|
||||
ClientId = Guid.NewGuid(),
|
||||
@@ -154,7 +154,7 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration
|
||||
tc,
|
||||
new[]
|
||||
{
|
||||
"configure",
|
||||
"configure",
|
||||
"--url", _expectedServerUrl,
|
||||
"--name", _expectedAgentName,
|
||||
"--runnergroup", _secondRunnerGroupName,
|
||||
@@ -163,6 +163,8 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration
|
||||
"--token", _expectedToken,
|
||||
"--labels", userLabels,
|
||||
"--ephemeral",
|
||||
"--disableupdate",
|
||||
"--unattended",
|
||||
});
|
||||
trace.Info("Constructed.");
|
||||
_store.Setup(x => x.IsConfigured()).Returns(false);
|
||||
@@ -185,7 +187,7 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration
|
||||
// validate GetAgentPoolsAsync gets called twice with automation pool type
|
||||
_runnerServer.Verify(x => x.GetAgentPoolsAsync(It.IsAny<string>(), It.Is<TaskAgentPoolType>(p => p == TaskAgentPoolType.Automation)), Times.Exactly(2));
|
||||
|
||||
var expectedLabels = new List<string>() { "self-hosted", VarUtil.OS, VarUtil.OSArchitecture};
|
||||
var expectedLabels = new List<string>() { "self-hosted", VarUtil.OS, VarUtil.OSArchitecture };
|
||||
expectedLabels.AddRange(userLabels.Split(",").ToList());
|
||||
|
||||
_runnerServer.Verify(x => x.AddAgentAsync(It.IsAny<int>(), It.Is<TaskAgent>(a => a.Labels.Select(x => x.Name).ToHashSet().SetEquals(expectedLabels))), Times.Once);
|
||||
|
||||
@@ -1 +1 @@
|
||||
2.286.2
|
||||
2.287.1
|
||||
|
||||
Reference in New Issue
Block a user