Support --ephemeral flag (#660)

This optional flag will configure the runner to only take one job, and let the service un-configure the runner after that job finishes.
This commit is contained in:
Tingluo Huang
2021-09-13 11:28:09 -04:00
committed by GitHub
parent 1b69c279f5
commit 7ffd9af644
7 changed files with 50 additions and 16 deletions

View File

@@ -33,6 +33,9 @@ namespace GitHub.Runner.Common
[DataMember(EmitDefaultValue = false)] [DataMember(EmitDefaultValue = false)]
public string PoolName { get; set; } public string PoolName { get; set; }
[DataMember(EmitDefaultValue = false)]
public bool Ephemeral { get; set; }
[DataMember(EmitDefaultValue = false)] [DataMember(EmitDefaultValue = false)]
public string ServerUrl { get; set; } public string ServerUrl { get; set; }

View File

@@ -125,9 +125,10 @@ namespace GitHub.Runner.Common
{ {
public static readonly string Check = "check"; public static readonly string Check = "check";
public static readonly string Commit = "commit"; public static readonly string Commit = "commit";
public static readonly string Ephemeral = "ephemeral";
public static readonly string Help = "help"; public static readonly string Help = "help";
public static readonly string Replace = "replace"; public static readonly string Replace = "replace";
public static readonly string Once = "once"; public static readonly string Once = "once"; // TODO: Remove in 10/2021
public static readonly string RunAsService = "runasservice"; public static readonly string RunAsService = "runasservice";
public static readonly string Unattended = "unattended"; public static readonly string Unattended = "unattended";
public static readonly string Version = "version"; public static readonly string Version = "version";

View File

@@ -29,10 +29,10 @@ namespace GitHub.Runner.Listener
{ {
Constants.Runner.CommandLine.Flags.Check, Constants.Runner.CommandLine.Flags.Check,
Constants.Runner.CommandLine.Flags.Commit, Constants.Runner.CommandLine.Flags.Commit,
Constants.Runner.CommandLine.Flags.Ephemeral,
Constants.Runner.CommandLine.Flags.Help, Constants.Runner.CommandLine.Flags.Help,
Constants.Runner.CommandLine.Flags.Replace, Constants.Runner.CommandLine.Flags.Replace,
Constants.Runner.CommandLine.Flags.RunAsService, Constants.Runner.CommandLine.Flags.RunAsService,
Constants.Runner.CommandLine.Flags.Once,
Constants.Runner.CommandLine.Flags.Unattended, Constants.Runner.CommandLine.Flags.Unattended,
Constants.Runner.CommandLine.Flags.Version Constants.Runner.CommandLine.Flags.Version
}; };
@@ -66,7 +66,9 @@ namespace GitHub.Runner.Listener
public bool Help => TestFlag(Constants.Runner.CommandLine.Flags.Help); public bool Help => TestFlag(Constants.Runner.CommandLine.Flags.Help);
public bool Unattended => TestFlag(Constants.Runner.CommandLine.Flags.Unattended); public bool Unattended => TestFlag(Constants.Runner.CommandLine.Flags.Unattended);
public bool Version => TestFlag(Constants.Runner.CommandLine.Flags.Version); public bool Version => TestFlag(Constants.Runner.CommandLine.Flags.Version);
public bool Ephemeral => TestFlag(Constants.Runner.CommandLine.Flags.Ephemeral);
// TODO: Remove in 10/2021
public bool RunOnce => TestFlag(Constants.Runner.CommandLine.Flags.Once); public bool RunOnce => TestFlag(Constants.Runner.CommandLine.Flags.Once);
// Constructor. // Constructor.

View File

@@ -195,6 +195,7 @@ namespace GitHub.Runner.Listener.Configuration
TaskAgent agent; TaskAgent agent;
while (true) while (true)
{ {
runnerSettings.Ephemeral = command.Ephemeral;
runnerSettings.AgentName = command.GetRunnerName(); runnerSettings.AgentName = command.GetRunnerName();
_term.WriteLine(); _term.WriteLine();
@@ -211,7 +212,7 @@ namespace GitHub.Runner.Listener.Configuration
if (command.GetReplace()) if (command.GetReplace())
{ {
// Update existing agent with new PublicKey, agent version. // Update existing agent with new PublicKey, agent version.
agent = UpdateExistingAgent(agent, publicKey, userLabels); agent = UpdateExistingAgent(agent, publicKey, userLabels, runnerSettings.Ephemeral);
try try
{ {
@@ -234,7 +235,7 @@ namespace GitHub.Runner.Listener.Configuration
else else
{ {
// Create a new agent. // Create a new agent.
agent = CreateNewAgent(runnerSettings.AgentName, publicKey, userLabels); agent = CreateNewAgent(runnerSettings.AgentName, publicKey, userLabels, runnerSettings.Ephemeral);
try try
{ {
@@ -456,7 +457,7 @@ namespace GitHub.Runner.Listener.Configuration
} }
private TaskAgent UpdateExistingAgent(TaskAgent agent, RSAParameters publicKey, ISet<string> userLabels) private TaskAgent UpdateExistingAgent(TaskAgent agent, RSAParameters publicKey, ISet<string> userLabels, bool ephemeral)
{ {
ArgUtil.NotNull(agent, nameof(agent)); ArgUtil.NotNull(agent, nameof(agent));
agent.Authorization = new TaskAgentAuthorization agent.Authorization = new TaskAgentAuthorization
@@ -467,6 +468,8 @@ namespace GitHub.Runner.Listener.Configuration
// update should replace the existing labels // update should replace the existing labels
agent.Version = BuildConstants.RunnerPackage.Version; agent.Version = BuildConstants.RunnerPackage.Version;
agent.OSDescription = RuntimeInformation.OSDescription; agent.OSDescription = RuntimeInformation.OSDescription;
agent.Ephemeral = ephemeral;
agent.MaxParallelism = 1;
agent.Labels.Clear(); agent.Labels.Clear();
@@ -482,7 +485,7 @@ namespace GitHub.Runner.Listener.Configuration
return agent; return agent;
} }
private TaskAgent CreateNewAgent(string agentName, RSAParameters publicKey, ISet<string> userLabels) private TaskAgent CreateNewAgent(string agentName, RSAParameters publicKey, ISet<string> userLabels, bool ephemeral)
{ {
TaskAgent agent = new TaskAgent(agentName) TaskAgent agent = new TaskAgent(agentName)
{ {
@@ -493,6 +496,7 @@ namespace GitHub.Runner.Listener.Configuration
MaxParallelism = 1, MaxParallelism = 1,
Version = BuildConstants.RunnerPackage.Version, Version = BuildConstants.RunnerPackage.Version,
OSDescription = RuntimeInformation.OSDescription, OSDescription = RuntimeInformation.OSDescription,
Ephemeral = ephemeral,
}; };
agent.Labels.Add(new AgentLabel("self-hosted", LabelType.System)); agent.Labels.Add(new AgentLabel("self-hosted", LabelType.System));

View File

@@ -234,7 +234,7 @@ namespace GitHub.Runner.Listener
HostContext.StartupType = startType; HostContext.StartupType = startType;
// Run the runner interactively or as service // Run the runner interactively or as service
return await RunAsync(settings, command.RunOnce); return await RunAsync(settings, command.RunOnce || settings.Ephemeral); // TODO: Remove RunOnce later.
} }
else else
{ {
@@ -466,8 +466,16 @@ namespace GitHub.Runner.Listener
await jobDispatcher.ShutdownAsync(); await jobDispatcher.ShutdownAsync();
} }
//TODO: make sure we don't mask more important exception try
{
await _listener.DeleteSessionAsync(); await _listener.DeleteSessionAsync();
}
catch (Exception ex) when (runOnce)
{
// ignore exception during delete session for ephemeral runner since the runner might already be deleted from the server side
// and the delete session call will ends up with 401.
Trace.Info($"Ignore any exception during DeleteSession for an ephemeral runner. {ex}");
}
messageQueueLoopTokenSource.Dispose(); messageQueueLoopTokenSource.Dispose();
} }
@@ -512,7 +520,9 @@ Config Options:
--labels string Extra labels in addition to the default: 'self-hosted,{Constants.Runner.Platform},{Constants.Runner.PlatformArchitecture}' --labels string Extra labels in addition to the default: 'self-hosted,{Constants.Runner.Platform},{Constants.Runner.PlatformArchitecture}'
--work string Relative runner work directory (default {Constants.Path.WorkDirectory}) --work string Relative runner work directory (default {Constants.Path.WorkDirectory})
--replace Replace any existing runner with the same name (default false) --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`"); --pat GitHub personal access token used for checking network connectivity when executing `.{separator}run.{ext} --check`
--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 #if OS_WINDOWS
_term.WriteLine($@" --runasservice Run the runner as a service"); _term.WriteLine($@" --runasservice Run the runner as a service");
_term.WriteLine($@" --windowslogonaccount string Account to run the service as. Requires runasservice"); _term.WriteLine($@" --windowslogonaccount string Account to run the service as. Requires runasservice");

View File

@@ -24,6 +24,7 @@ namespace GitHub.DistributedTask.WebApi
this.OSDescription = referenceToBeCloned.OSDescription; this.OSDescription = referenceToBeCloned.OSDescription;
this.ProvisioningState = referenceToBeCloned.ProvisioningState; this.ProvisioningState = referenceToBeCloned.ProvisioningState;
this.AccessPoint = referenceToBeCloned.AccessPoint; this.AccessPoint = referenceToBeCloned.AccessPoint;
this.Ephemeral = referenceToBeCloned.Ephemeral;
if (referenceToBeCloned.m_links != null) if (referenceToBeCloned.m_links != null)
{ {
@@ -81,6 +82,16 @@ namespace GitHub.DistributedTask.WebApi
set; set;
} }
/// <summary>
/// Signifies that this Agent can only run one job and will be removed by the server after that one job finish.
/// </summary>
[DataMember]
public bool? Ephemeral
{
get;
set;
}
/// <summary> /// <summary>
/// Whether or not the agent is online. /// Whether or not the agent is online.
/// </summary> /// </summary>

View File

@@ -243,7 +243,8 @@ namespace GitHub.Runner.Common.Tests.Listener
runner.Initialize(hc); runner.Initialize(hc);
var settings = new RunnerSettings var settings = new RunnerSettings
{ {
PoolId = 43242 PoolId = 43242,
Ephemeral = true
}; };
var message = new TaskAgentMessage() var message = new TaskAgentMessage()
@@ -294,7 +295,7 @@ namespace GitHub.Runner.Common.Tests.Listener
_configStore.Setup(x => x.IsServiceConfigured()).Returns(false); _configStore.Setup(x => x.IsServiceConfigured()).Returns(false);
//Act //Act
var command = new CommandSettings(hc, new string[] { "run", "--once" }); var command = new CommandSettings(hc, new string[] { "run" });
Task<int> runnerTask = runner.ExecuteCommand(command); Task<int> runnerTask = runner.ExecuteCommand(command);
//Assert //Assert
@@ -332,7 +333,8 @@ namespace GitHub.Runner.Common.Tests.Listener
runner.Initialize(hc); runner.Initialize(hc);
var settings = new RunnerSettings var settings = new RunnerSettings
{ {
PoolId = 43242 PoolId = 43242,
Ephemeral = true
}; };
var message1 = new TaskAgentMessage() var message1 = new TaskAgentMessage()
@@ -390,7 +392,7 @@ namespace GitHub.Runner.Common.Tests.Listener
_configStore.Setup(x => x.IsServiceConfigured()).Returns(false); _configStore.Setup(x => x.IsServiceConfigured()).Returns(false);
//Act //Act
var command = new CommandSettings(hc, new string[] { "run", "--once" }); var command = new CommandSettings(hc, new string[] { "run" });
Task<int> runnerTask = runner.ExecuteCommand(command); Task<int> runnerTask = runner.ExecuteCommand(command);
//Assert //Assert
@@ -431,7 +433,8 @@ namespace GitHub.Runner.Common.Tests.Listener
var settings = new RunnerSettings var settings = new RunnerSettings
{ {
PoolId = 43242, PoolId = 43242,
AgentId = 5678 AgentId = 5678,
Ephemeral = true
}; };
var message1 = new TaskAgentMessage() var message1 = new TaskAgentMessage()
@@ -475,7 +478,7 @@ namespace GitHub.Runner.Common.Tests.Listener
_configStore.Setup(x => x.IsServiceConfigured()).Returns(false); _configStore.Setup(x => x.IsServiceConfigured()).Returns(false);
//Act //Act
var command = new CommandSettings(hc, new string[] { "run", "--once" }); var command = new CommandSettings(hc, new string[] { "run" });
Task<int> runnerTask = runner.ExecuteCommand(command); Task<int> runnerTask = runner.ExecuteCommand(command);
//Assert //Assert