Add generateServiceConfig option for configure command (#2226)

For runners that are already configured but need to add systemd services after the fact, a new command option is added to generate the file only. Once generated, ./svc.sh install and other commands will be available.

This also adds support for falling back to the tenant name in the Actions URL in cases when the GitHub URL is not provided, such as for our hosted larger runners.
This commit is contained in:
Cory Miller
2022-10-26 08:48:23 -04:00
committed by GitHub
parent 3fc993da59
commit b18bda773f
5 changed files with 127 additions and 4 deletions

View File

@@ -77,14 +77,15 @@ namespace GitHub.Runner.Common
Uri accountUri = new(this.ServerUrl);
string repoOrOrgName = string.Empty;
if (accountUri.Host.EndsWith(".githubusercontent.com", StringComparison.OrdinalIgnoreCase))
if (accountUri.Host.EndsWith(".githubusercontent.com", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(this.GitHubUrl))
{
Uri gitHubUrl = new(this.GitHubUrl);
// Use the "NWO part" from the GitHub URL path
repoOrOrgName = gitHubUrl.AbsolutePath.Trim('/');
}
else
if (string.IsNullOrEmpty(repoOrOrgName))
{
repoOrOrgName = accountUri.AbsolutePath.Split('/', StringSplitOptions.RemoveEmptyEntries).FirstOrDefault();
}

View File

@@ -128,6 +128,7 @@ namespace GitHub.Runner.Common
public static readonly string Check = "check";
public static readonly string Commit = "commit";
public static readonly string Ephemeral = "ephemeral";
public static readonly string GenerateServiceConfig = "generateServiceConfig";
public static readonly string Help = "help";
public static readonly string Replace = "replace";
public static readonly string DisableUpdate = "disableupdate";

View File

@@ -34,6 +34,7 @@ namespace GitHub.Runner.Listener
{
Constants.Runner.CommandLine.Flags.DisableUpdate,
Constants.Runner.CommandLine.Flags.Ephemeral,
Constants.Runner.CommandLine.Flags.GenerateServiceConfig,
Constants.Runner.CommandLine.Flags.Replace,
Constants.Runner.CommandLine.Flags.RunAsService,
Constants.Runner.CommandLine.Flags.Unattended,
@@ -79,11 +80,12 @@ namespace GitHub.Runner.Listener
// Flags.
public bool Check => TestFlag(Constants.Runner.CommandLine.Flags.Check);
public bool Commit => TestFlag(Constants.Runner.CommandLine.Flags.Commit);
public bool DisableUpdate => TestFlag(Constants.Runner.CommandLine.Flags.DisableUpdate);
public bool Ephemeral => TestFlag(Constants.Runner.CommandLine.Flags.Ephemeral);
public bool GenerateServiceConfig => TestFlag(Constants.Runner.CommandLine.Flags.GenerateServiceConfig);
public bool Help => TestFlag(Constants.Runner.CommandLine.Flags.Help);
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);

View File

@@ -81,6 +81,27 @@ namespace GitHub.Runner.Listener.Configuration
_term.WriteLine("--------------------------------------------------------------------------------");
Trace.Info(nameof(ConfigureAsync));
if (command.GenerateServiceConfig)
{
#if OS_LINUX
if (!IsConfigured())
{
throw new InvalidOperationException("--generateServiceConfig requires that the runner is already configured. For configuring a new runner as a service, run './config.sh'.");
}
RunnerSettings settings = _store.GetSettings();
Trace.Info($"generate service config for runner: {settings.AgentId}");
var controlManager = HostContext.GetService<ILinuxServiceControlManager>();
controlManager.GenerateScripts(settings);
return;
#else
throw new NotSupportedException("--generateServiceConfig is only supported on Linux.");
#endif
}
if (IsConfigured())
{
throw new InvalidOperationException("Cannot configure the runner because it is already configured. To reconfigure the runner, run 'config.cmd remove' or './config.sh remove' first.");

View File

@@ -234,5 +234,103 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration
_runnerServer.Verify(x => x.GetAgentPoolsAsync(It.IsAny<string>(), It.Is<TaskAgentPoolType>(p => p == TaskAgentPoolType.Automation)), Times.Exactly(1));
}
}
#if OS_LINUX
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "ConfigurationManagement")]
public async Task ConfigureRunnerServiceFailsOnUnconfiguredRunners()
{
using (TestHostContext tc = CreateTestContext())
{
Tracing trace = tc.GetTrace();
trace.Info("Creating config manager");
IConfigurationManager configManager = new ConfigurationManager();
configManager.Initialize(tc);
trace.Info("Preparing command line arguments");
var command = new CommandSettings(
tc,
new[]
{
"configure",
"--generateServiceConfig",
});
trace.Info("Constructed");
_store.Setup(x => x.IsConfigured()).Returns(false);
trace.Info("Ensuring service generation mode fails when on un-configured runners");
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => configManager.ConfigureAsync(command));
Assert.Contains("requires that the runner is already configured", ex.Message);
}
}
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "ConfigurationManagement")]
public async Task ConfigureRunnerServiceCreatesService()
{
using (TestHostContext tc = CreateTestContext())
{
Tracing trace = tc.GetTrace();
trace.Info("Creating config manager");
IConfigurationManager configManager = new ConfigurationManager();
configManager.Initialize(tc);
trace.Info("Preparing command line arguments");
var command = new CommandSettings(
tc,
new[]
{
"configure",
"--generateServiceConfig",
});
trace.Info("Constructed");
_store.Setup(x => x.IsConfigured()).Returns(true);
trace.Info("Ensuring service generation mode fails when on un-configured runners");
await configManager.ConfigureAsync(command);
_serviceControlManager.Verify(x => x.GenerateScripts(It.IsAny<RunnerSettings>()), Times.Once);
}
}
#endif
#if !OS_LINUX
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "ConfigurationManagement")]
public async Task ConfigureRunnerServiceFailsOnUnsupportedPlatforms()
{
using (TestHostContext tc = CreateTestContext())
{
Tracing trace = tc.GetTrace();
trace.Info("Creating config manager");
IConfigurationManager configManager = new ConfigurationManager();
configManager.Initialize(tc);
trace.Info("Preparing command line arguments");
var command = new CommandSettings(
tc,
new[]
{
"configure",
"--generateServiceConfig",
});
trace.Info("Constructed");
_store.Setup(x => x.IsConfigured()).Returns(true);
trace.Info("Ensuring service generation mode fails on unsupported runner platforms");
var ex = await Assert.ThrowsAsync<NotSupportedException>(() => configManager.ConfigureAsync(command));
Assert.Contains("only supported on Linux", ex.Message);
}
}
#endif
}
}