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
}