2024-02-15 02:34:52 +00:00
#nullable enable
2025-10-16 21:16:14 +01:00
using System ;
2024-02-15 02:34:52 +00:00
using System.IO ;
using System.Threading.Tasks ;
using GitHub.DistributedTask.Pipelines ;
2025-10-16 21:16:14 +01:00
using GitHub.DistributedTask.WebApi ;
2024-02-15 02:34:52 +00:00
using GitHub.Runner.Common ;
using GitHub.Runner.Sdk ;
2025-10-16 21:16:14 +01:00
using GitHub.Runner.Worker.Handlers ;
2024-02-15 02:34:52 +00:00
namespace GitHub.Runner.Worker ;
[ServiceLocator(Default = typeof(SnapshotOperationProvider))]
public interface ISnapshotOperationProvider : IRunnerService
{
Task CreateSnapshotRequestAsync ( IExecutionContext executionContext , Snapshot snapshotRequest ) ;
2025-10-16 21:16:14 +01:00
void RunSnapshotPreflightChecks ( IExecutionContext jobContext ) ;
2024-02-15 02:34:52 +00:00
}
public class SnapshotOperationProvider : RunnerService , ISnapshotOperationProvider
{
public Task CreateSnapshotRequestAsync ( IExecutionContext executionContext , Snapshot snapshotRequest )
{
var snapshotRequestFilePath = Path . Combine ( HostContext . GetDirectory ( WellKnownDirectory . Root ) , ".snapshot" , "request.json" ) ;
var snapshotRequestDirectoryPath = Path . GetDirectoryName ( snapshotRequestFilePath ) ;
if ( snapshotRequestDirectoryPath ! = null )
{
Directory . CreateDirectory ( snapshotRequestDirectoryPath ) ;
}
IOUtil . SaveObject ( snapshotRequest , snapshotRequestFilePath ) ;
2025-10-16 21:16:14 +01:00
executionContext . Output ( $"Image Name: {snapshotRequest.ImageName} Version: {snapshotRequest.Version}" ) ;
2024-02-15 02:34:52 +00:00
executionContext . Output ( $"Request written to: {snapshotRequestFilePath}" ) ;
executionContext . Output ( "This request will be processed after the job completes. You will not receive any feedback on the snapshot process within the workflow logs of this job." ) ;
executionContext . Output ( "If the snapshot process is successful, you should see a new image with the requested name in the list of available custom images when creating a new GitHub-hosted Runner." ) ;
return Task . CompletedTask ;
}
2025-10-16 21:16:14 +01:00
public void RunSnapshotPreflightChecks ( IExecutionContext context )
{
var shouldCheckRunnerEnvironment = context . Global . Variables . GetBoolean ( Constants . Runner . Features . SnapshotPreflightHostedRunnerCheck ) ? ? false ;
if ( shouldCheckRunnerEnvironment & &
context . Global . Variables . TryGetValue ( WellKnownDistributedTaskVariables . RunnerEnvironment , out var runnerEnvironment ) & &
! string . IsNullOrEmpty ( runnerEnvironment ) )
{
context . Debug ( $"Snapshot: RUNNER_ENVIRONMENT={runnerEnvironment}" ) ;
if ( ! string . Equals ( runnerEnvironment , "github-hosted" , StringComparison . OrdinalIgnoreCase ) )
{
throw new ArgumentException ( "Snapshot workflows must be run on a GitHub Hosted Runner" ) ;
}
}
var imageGenEnabled = StringUtil . ConvertToBoolean ( Environment . GetEnvironmentVariable ( "GITHUB_ACTIONS_IMAGE_GEN_ENABLED" ) ) ;
context . Debug ( $"Snapshot: GITHUB_ACTIONS_IMAGE_GEN_ENABLED={imageGenEnabled}" ) ;
var shouldCheckImageGenPool = context . Global . Variables . GetBoolean ( Constants . Runner . Features . SnapshotPreflightImageGenPoolCheck ) ? ? false ;
if ( shouldCheckImageGenPool & & ! imageGenEnabled )
{
throw new ArgumentException ( "Snapshot workflows must be run a hosted runner with Image Generation enabled" ) ;
}
}
2024-02-15 02:34:52 +00:00
}