Skip to content

Support refresh runner configs with pipelines service. #3706

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

Merged
merged 4 commits into from
Mar 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 66 additions & 3 deletions src/Runner.Common/ConfigurationStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,11 @@ public interface IConfigurationStore : IRunnerService
CredentialData GetCredentials();
CredentialData GetMigratedCredentials();
RunnerSettings GetSettings();
RunnerSettings GetMigratedSettings();
void SaveCredential(CredentialData credential);
void SaveMigratedCredential(CredentialData credential);
void SaveSettings(RunnerSettings settings);
void SaveMigratedSettings(RunnerSettings settings);
void DeleteCredential();
void DeleteMigratedCredential();
void DeleteSettings();
Expand All @@ -130,13 +133,15 @@ public sealed class ConfigurationStore : RunnerService, IConfigurationStore
{
private string _binPath;
private string _configFilePath;
private string _migratedConfigFilePath;
private string _credFilePath;
private string _migratedCredFilePath;
private string _serviceConfigFilePath;

private CredentialData _creds;
private CredentialData _migratedCreds;
private RunnerSettings _settings;
private RunnerSettings _migratedSettings;

public override void Initialize(IHostContext hostContext)
{
Expand All @@ -154,6 +159,9 @@ public override void Initialize(IHostContext hostContext)
_configFilePath = hostContext.GetConfigFile(WellKnownConfigFile.Runner);
Trace.Info("ConfigFilePath: {0}", _configFilePath);

_migratedConfigFilePath = hostContext.GetConfigFile(WellKnownConfigFile.MigratedRunner);
Trace.Info("MigratedConfigFilePath: {0}", _migratedConfigFilePath);

_credFilePath = hostContext.GetConfigFile(WellKnownConfigFile.Credentials);
Trace.Info("CredFilePath: {0}", _credFilePath);

Expand All @@ -169,23 +177,23 @@ public override void Initialize(IHostContext hostContext)
public bool HasCredentials()
{
Trace.Info("HasCredentials()");
bool credsStored = (new FileInfo(_credFilePath)).Exists || (new FileInfo(_migratedCredFilePath)).Exists;
bool credsStored = new FileInfo(_credFilePath).Exists || new FileInfo(_migratedCredFilePath).Exists;
Trace.Info("stored {0}", credsStored);
return credsStored;
}

public bool IsConfigured()
{
Trace.Info("IsConfigured()");
bool configured = new FileInfo(_configFilePath).Exists;
bool configured = new FileInfo(_configFilePath).Exists || new FileInfo(_migratedConfigFilePath).Exists;
Trace.Info("IsConfigured: {0}", configured);
return configured;
}

public bool IsServiceConfigured()
{
Trace.Info("IsServiceConfigured()");
bool serviceConfigured = (new FileInfo(_serviceConfigFilePath)).Exists;
bool serviceConfigured = new FileInfo(_serviceConfigFilePath).Exists;
Trace.Info($"IsServiceConfigured: {serviceConfigured}");
return serviceConfigured;
}
Expand Down Expand Up @@ -229,6 +237,25 @@ public RunnerSettings GetSettings()
return _settings;
}

public RunnerSettings GetMigratedSettings()
{
if (_migratedSettings == null)
{
RunnerSettings configuredSettings = null;
if (File.Exists(_migratedConfigFilePath))
{
string json = File.ReadAllText(_migratedConfigFilePath, Encoding.UTF8);
Trace.Info($"Read migrated setting file: {json.Length} chars");
configuredSettings = StringUtil.ConvertFromJson<RunnerSettings>(json);
}

ArgUtil.NotNull(configuredSettings, nameof(configuredSettings));
_migratedSettings = configuredSettings;
}

return _migratedSettings;
}

public void SaveCredential(CredentialData credential)
{
Trace.Info("Saving {0} credential @ {1}", credential.Scheme, _credFilePath);
Expand All @@ -244,6 +271,21 @@ public void SaveCredential(CredentialData credential)
File.SetAttributes(_credFilePath, File.GetAttributes(_credFilePath) | FileAttributes.Hidden);
}

public void SaveMigratedCredential(CredentialData credential)
{
Trace.Info("Saving {0} migrated credential @ {1}", credential.Scheme, _migratedCredFilePath);
if (File.Exists(_migratedCredFilePath))
{
// Delete existing credential file first, since the file is hidden and not able to overwrite.
Trace.Info("Delete exist runner migrated credential file.");
IOUtil.DeleteFile(_migratedCredFilePath);
}

IOUtil.SaveObject(credential, _migratedCredFilePath);
Trace.Info("Migrated Credentials Saved.");
File.SetAttributes(_migratedCredFilePath, File.GetAttributes(_migratedCredFilePath) | FileAttributes.Hidden);
}

public void SaveSettings(RunnerSettings settings)
{
Trace.Info("Saving runner settings.");
Expand All @@ -259,6 +301,21 @@ public void SaveSettings(RunnerSettings settings)
File.SetAttributes(_configFilePath, File.GetAttributes(_configFilePath) | FileAttributes.Hidden);
}

public void SaveMigratedSettings(RunnerSettings settings)
{
Trace.Info("Saving runner migrated settings");
if (File.Exists(_migratedConfigFilePath))
{
// Delete existing settings file first, since the file is hidden and not able to overwrite.
Trace.Info("Delete exist runner migrated settings file.");
IOUtil.DeleteFile(_migratedConfigFilePath);
}

IOUtil.SaveObject(settings, _migratedConfigFilePath);
Trace.Info("Migrated Settings Saved.");
File.SetAttributes(_migratedConfigFilePath, File.GetAttributes(_migratedConfigFilePath) | FileAttributes.Hidden);
}

public void DeleteCredential()
{
IOUtil.Delete(_credFilePath, default(CancellationToken));
Expand All @@ -273,6 +330,12 @@ public void DeleteMigratedCredential()
public void DeleteSettings()
{
IOUtil.Delete(_configFilePath, default(CancellationToken));
IOUtil.Delete(_migratedConfigFilePath, default(CancellationToken));
}

public void DeleteMigratedSettings()
{
IOUtil.Delete(_migratedConfigFilePath, default(CancellationToken));
}
}
}
1 change: 1 addition & 0 deletions src/Runner.Common/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public enum WellKnownDirectory
public enum WellKnownConfigFile
{
Runner,
MigratedRunner,
Credentials,
MigratedCredentials,
RSACredentials,
Expand Down
6 changes: 6 additions & 0 deletions src/Runner.Common/HostContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,12 @@ public string GetConfigFile(WellKnownConfigFile configFile)
".runner");
break;

case WellKnownConfigFile.MigratedRunner:
path = Path.Combine(
GetDirectory(WellKnownDirectory.Root),
".runner_migrated");
break;

case WellKnownConfigFile.Credentials:
path = Path.Combine(
GetDirectory(WellKnownDirectory.Root),
Expand Down
24 changes: 17 additions & 7 deletions src/Runner.Common/RunnerServer.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using GitHub.DistributedTask.WebApi;
using System;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using GitHub.Services.WebApi;
using GitHub.Services.Common;
using GitHub.DistributedTask.WebApi;
using GitHub.Runner.Sdk;
using GitHub.Services.Common;
using GitHub.Services.WebApi;

namespace GitHub.Runner.Common
{
Expand Down Expand Up @@ -50,7 +50,10 @@ public interface IRunnerServer : IRunnerService
Task<PackageMetadata> GetPackageAsync(string packageType, string platform, string version, bool includeToken, CancellationToken cancellationToken);

// agent update
Task<TaskAgent> UpdateAgentUpdateStateAsync(int agentPoolId, ulong agentId, string currentState, string trace);
Task<TaskAgent> UpdateAgentUpdateStateAsync(int agentPoolId, ulong agentId, string currentState, string trace, CancellationToken cancellationToken = default);

// runner config refresh
Task<string> RefreshRunnerConfigAsync(int agentId, string configType, string encodedRunnerConfig, CancellationToken cancellationToken);
}

public sealed class RunnerServer : RunnerService, IRunnerServer
Expand Down Expand Up @@ -315,10 +318,17 @@ public Task<PackageMetadata> GetPackageAsync(string packageType, string platform
return _genericTaskAgentClient.GetPackageAsync(packageType, platform, version, includeToken, cancellationToken: cancellationToken);
}

public Task<TaskAgent> UpdateAgentUpdateStateAsync(int agentPoolId, ulong agentId, string currentState, string trace)
public Task<TaskAgent> UpdateAgentUpdateStateAsync(int agentPoolId, ulong agentId, string currentState, string trace, CancellationToken cancellationToken = default)
{
CheckConnection(RunnerConnectionType.Generic);
return _genericTaskAgentClient.UpdateAgentUpdateStateAsync(agentPoolId, agentId, currentState, trace, cancellationToken: cancellationToken);
}

// runner config refresh
public Task<string> RefreshRunnerConfigAsync(int agentId, string configType, string encodedRunnerConfig, CancellationToken cancellationToken)
{
CheckConnection(RunnerConnectionType.Generic);
return _genericTaskAgentClient.UpdateAgentUpdateStateAsync(agentPoolId, agentId, currentState, trace);
return _genericTaskAgentClient.RefreshRunnerConfigAsync(agentId, configType, encodedRunnerConfig, cancellationToken: cancellationToken);
}
}
}
3 changes: 2 additions & 1 deletion src/Runner.Listener/MessageListener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,8 @@ private bool IsSessionCreationExceptionRetriable(Exception ex)
}
else if (ex is TaskAgentPoolNotFoundException ||
ex is AccessDeniedException ||
ex is VssUnauthorizedException)
ex is VssUnauthorizedException ||
(ex is VssOAuthTokenRequestException oauthEx && oauthEx.Error != "server_error"))
{
Trace.Info($"Non-retriable exception: {ex.Message}");
return false;
Expand Down
11 changes: 11 additions & 0 deletions src/Runner.Listener/Runner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,17 @@ ex is TaskOrchestrationJobAlreadyAcquiredException || // HTTP status 409
Trace.Info("Received ForceTokenRefreshMessage");
await _listener.RefreshListenerTokenAsync(messageQueueLoopTokenSource.Token);
}
else if (string.Equals(message.MessageType, RunnerRefreshConfigMessage.MessageType))
{
var runnerRefreshConfigMessage = JsonUtility.FromString<RunnerRefreshConfigMessage>(message.Body);
Trace.Info($"Received RunnerRefreshConfigMessage for '{runnerRefreshConfigMessage.ConfigType}' config file");
var configUpdater = HostContext.GetService<IRunnerConfigUpdater>();
await configUpdater.UpdateRunnerConfigAsync(
runnerQualifiedId: runnerRefreshConfigMessage.RunnerQualifiedId,
configType: runnerRefreshConfigMessage.ConfigType,
serviceType: runnerRefreshConfigMessage.ServiceType,
configRefreshUrl: runnerRefreshConfigMessage.ConfigRefreshUrl);
}
else
{
Trace.Error($"Received message {message.MessageId} with unsupported message type {message.MessageType}.");
Expand Down
Loading