This commit is contained in:
TingluoHuang
2021-10-14 16:29:59 -04:00
parent f37e9f80a6
commit 7128998d77
4 changed files with 201 additions and 52 deletions

View File

@@ -107,9 +107,37 @@ async function run(): Promise<void> {
await exec.exec('podman', ['rm', '-f', jobContainerId]) await exec.exec('podman', ['rm', '-f', jobContainerId])
await exec.exec('podman', ['network', 'rm', '-f', network]) await exec.exec('podman', ['network', 'rm', '-f', network])
} else if (command === 'Exec') {
const execInput = inputJson.execInput
core.debug(JSON.stringify(execInput))
// podman exec -i --workdir /__w/canary/canary
// -e GITHUB_JOB -e GITHUB_REF -e GITHUB_SHA -e GITHUB_REPOSITORY
// -e GITHUB_REPOSITORY_OWNER -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER
// -e GITHUB_RETENTION_DAYS -e GITHUB_RUN_ATTEMPT -e GITHUB_ACTOR
// -e GITHUB_WORKFLOW -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GITHUB_EVENT_NAME
// -e GITHUB_SERVER_URL -e GITHUB_API_URL -e GITHUB_GRAPHQL_URL
// -e GITHUB_WORKSPACE -e GITHUB_ACTION -e GITHUB_EVENT_PATH -e GITHUB_ACTION_REPOSITORY
// -e GITHUB_ACTION_REF -e GITHUB_PATH -e GITHUB_ENV -e RUNNER_DEBUG
// -e RUNNER_OS -e RUNNER_NAME -e RUNNER_TOOL_CACHE
// -e RUNNER_TEMP -e RUNNER_WORKSPACE
// eccdf520697a035599d6e8c8dc801f004fdd3797cdce88f590aba3669a88d9bc sh -e /__w/_temp/d3b30383-719c-4e76-a16f-8f85443352be.sh
const execArgs = ['exec']
execArgs.push('-i')
execArgs.push(`--wordir=${execInput.workingDirectory}`)
for (const envKey of execInput.environmentKeys) {
execArgs.push(`-e=${envKey}`)
}
execArgs.push(execInput.jobContainer.containerId)
execArgs.push(execInput.fileName)
execArgs.push(execInput.arguments)
core.debug(JSON.stringify(execArgs))
await exec.exec('podman', execArgs)
} }
// else if (command === 'Exec') {
// }
await exec.exec('podman', ['network', 'ls']) await exec.exec('podman', ['network', 'ls'])
await exec.exec('podman', ['ps', '-a']) await exec.exec('podman', ['ps', '-a'])
} }

View File

@@ -1130,8 +1130,32 @@ function run() {
yield exec.exec('podman', ['rm', '-f', jobContainerId]); yield exec.exec('podman', ['rm', '-f', jobContainerId]);
yield exec.exec('podman', ['network', 'rm', '-f', network]); yield exec.exec('podman', ['network', 'rm', '-f', network]);
} }
// else if (command === 'Exec') { else if (command === 'Exec') {
// } const execInput = inputJson.execInput;
core.debug(JSON.stringify(execInput));
// podman exec -i --workdir /__w/canary/canary
// -e GITHUB_JOB -e GITHUB_REF -e GITHUB_SHA -e GITHUB_REPOSITORY
// -e GITHUB_REPOSITORY_OWNER -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER
// -e GITHUB_RETENTION_DAYS -e GITHUB_RUN_ATTEMPT -e GITHUB_ACTOR
// -e GITHUB_WORKFLOW -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GITHUB_EVENT_NAME
// -e GITHUB_SERVER_URL -e GITHUB_API_URL -e GITHUB_GRAPHQL_URL
// -e GITHUB_WORKSPACE -e GITHUB_ACTION -e GITHUB_EVENT_PATH -e GITHUB_ACTION_REPOSITORY
// -e GITHUB_ACTION_REF -e GITHUB_PATH -e GITHUB_ENV -e RUNNER_DEBUG
// -e RUNNER_OS -e RUNNER_NAME -e RUNNER_TOOL_CACHE
// -e RUNNER_TEMP -e RUNNER_WORKSPACE
// eccdf520697a035599d6e8c8dc801f004fdd3797cdce88f590aba3669a88d9bc sh -e /__w/_temp/d3b30383-719c-4e76-a16f-8f85443352be.sh
const execArgs = ['exec'];
execArgs.push("-i");
execArgs.push(`--wordir=${execInput.workingDirectory}`);
for (const envKey of execInput.environmentKeys) {
execArgs.push(`-e=${envKey}`);
}
execArgs.push(execInput.jobContainer.containerId);
execArgs.push(execInput.fileName);
execArgs.push(execInput.arguments);
core.debug(JSON.stringify(execArgs));
yield exec.exec('podman', execArgs);
}
yield exec.exec('podman', ['network', 'ls']); yield exec.exec('podman', ['network', 'ls']);
yield exec.exec('podman', ['ps', '-a']); yield exec.exec('podman', ['ps', '-a']);
}); });

View File

@@ -29,12 +29,34 @@ namespace GitHub.Runner.Worker
public ContainersCreationInput CreationInput { get; set; } public ContainersCreationInput CreationInput { get; set; }
[DataMember] [DataMember]
public object JobContainerExecInput { get; set; } public JobContainerExecInput ExecInput { get; set; }
[DataMember] [DataMember]
public ContainersRemoveInput RemoveInput { get; set; } public ContainersRemoveInput RemoveInput { get; set; }
} }
[DataContract]
public class JobContainerExecInput
{
[DataMember]
public ContainerInfo JobContainer { get; set; }
[DataMember]
public string WorkingDirectory { get; set; }
[DataMember]
public string FileName { get; set; }
[DataMember]
public string Arguments { get; set; }
[DataMember]
public List<string> EnvironmentKeys { get; set; }
}
[DataContract] [DataContract]
public class ContainersCreationInput public class ContainersCreationInput
{ {
@@ -192,6 +214,7 @@ namespace GitHub.Runner.Worker
{ {
executionContext.JobContext.Container["network"] = new StringContextData(podmanOutput.CreationOutput.Network); executionContext.JobContext.Container["network"] = new StringContextData(podmanOutput.CreationOutput.Network);
executionContext.JobContext.Container["id"] = new StringContextData(podmanOutput.CreationOutput.JobContainerId); executionContext.JobContext.Container["id"] = new StringContextData(podmanOutput.CreationOutput.JobContainerId);
executionContext.Global.Container.ContainerId = podmanOutput.CreationOutput.JobContainerId;
} }
} }
else else

View File

@@ -21,6 +21,8 @@ namespace GitHub.Runner.Worker.Handlers
event EventHandler<ProcessDataReceivedEventArgs> OutputDataReceived; event EventHandler<ProcessDataReceivedEventArgs> OutputDataReceived;
event EventHandler<ProcessDataReceivedEventArgs> ErrorDataReceived; event EventHandler<ProcessDataReceivedEventArgs> ErrorDataReceived;
IExecutionContext ExecutionContext { get; set; }
string ResolvePathForStepHost(string path); string ResolvePathForStepHost(string path);
Task<string> DetermineNodeRuntimeVersion(IExecutionContext executionContext); Task<string> DetermineNodeRuntimeVersion(IExecutionContext executionContext);
@@ -53,6 +55,8 @@ namespace GitHub.Runner.Worker.Handlers
public event EventHandler<ProcessDataReceivedEventArgs> OutputDataReceived; public event EventHandler<ProcessDataReceivedEventArgs> OutputDataReceived;
public event EventHandler<ProcessDataReceivedEventArgs> ErrorDataReceived; public event EventHandler<ProcessDataReceivedEventArgs> ErrorDataReceived;
public IExecutionContext ExecutionContext { get; set; }
public string ResolvePathForStepHost(string path) public string ResolvePathForStepHost(string path)
{ {
return path; return path;
@@ -99,6 +103,8 @@ namespace GitHub.Runner.Worker.Handlers
public event EventHandler<ProcessDataReceivedEventArgs> OutputDataReceived; public event EventHandler<ProcessDataReceivedEventArgs> OutputDataReceived;
public event EventHandler<ProcessDataReceivedEventArgs> ErrorDataReceived; public event EventHandler<ProcessDataReceivedEventArgs> ErrorDataReceived;
public IExecutionContext ExecutionContext { get; set; }
public string ResolvePathForStepHost(string path) public string ResolvePathForStepHost(string path)
{ {
// make sure container exist. // make sure container exist.
@@ -174,69 +180,137 @@ namespace GitHub.Runner.Worker.Handlers
ArgUtil.NotNull(Container, nameof(Container)); ArgUtil.NotNull(Container, nameof(Container));
ArgUtil.NotNullOrEmpty(Container.ContainerId, nameof(Container.ContainerId)); ArgUtil.NotNullOrEmpty(Container.ContainerId, nameof(Container.ContainerId));
var dockerManager = HostContext.GetService<IDockerCommandManager>(); var podManHandler = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Bin), "podmanHandler", "index.js");
string dockerClientPath = dockerManager.DockerPath; if (File.Exists(podManHandler))
// Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
IList<string> dockerCommandArgs = new List<string>();
dockerCommandArgs.Add($"exec");
// [OPTIONS]
dockerCommandArgs.Add($"-i");
dockerCommandArgs.Add($"--workdir {workingDirectory}");
foreach (var env in environment)
{ {
// e.g. -e MY_SECRET maps the value into the exec'ed process without exposing var podmanInput = new ContainerEngineHandlerInput()
// the value directly in the command {
dockerCommandArgs.Add($"-e {env.Key}"); Command = "Exec",
ExecInput = new JobContainerExecInput()
{
JobContainer = this.Container,
WorkingDirectory = workingDirectory,
FileName = fileName,
Arguments = arguments,
EnvironmentKeys = environment.Keys.ToList()
}
};
// make sure all env are using container path
foreach (var envKey in environment.Keys.ToList())
{
environment[envKey] = this.Container.TranslateToContainerPath(environment[envKey]);
}
// ContainerEngineHandlerOutput podmanOutput = null;
using (var processInvoker = HostContext.CreateService<IProcessInvoker>())
{
var redirectStandardIn = Channel.CreateUnbounded<string>(new UnboundedChannelOptions() { SingleReader = true, SingleWriter = true });
redirectStandardIn.Writer.TryWrite(JsonUtility.ToString(podmanInput));
// processInvoker.OutputDataReceived += delegate (object sender, ProcessDataReceivedEventArgs message)
// {
// ExecutionContext.Output(message.Data);
// };
// processInvoker.ErrorDataReceived += delegate (object sender, ProcessDataReceivedEventArgs message)
// {
// executionContext.Output(message.Data);
// if (podmanOutput == null && message.Data.IndexOf("___CONTAINER_ENGINE_HANDLER_OUTPUT___") >= 0)
// {
// try
// {
// podmanOutput = JsonUtility.FromString<ContainerEngineHandlerOutput>(message.Data.Replace("___CONTAINER_ENGINE_HANDLER_OUTPUT___", ""));
// }
// catch (Exception ex)
// {
// executionContext.Error(ex);
// }
// }
// };
processInvoker.OutputDataReceived += OutputDataReceived;
processInvoker.ErrorDataReceived += ErrorDataReceived;
// Execute the process. Exit code 0 should always be returned.
// A non-zero exit code indicates infrastructural failure.
// Task failure should be communicated over STDOUT using ## commands.
return await processInvoker.ExecuteAsync(workingDirectory: HostContext.GetDirectory(WellKnownDirectory.Work),
fileName: Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Externals), "node12", "bin", $"node{IOUtil.ExeExtension}"),
arguments: podManHandler,
environment: environment,
requireExitCodeZero: requireExitCodeZero,
outputEncoding: Encoding.UTF8,
killProcessOnCancel: killProcessOnCancel,
redirectStandardIn: redirectStandardIn,
cancellationToken: cancellationToken);
}
} }
if (!string.IsNullOrEmpty(PrependPath)) else
{ {
// Prepend tool paths to container's PATH var dockerManager = HostContext.GetService<IDockerCommandManager>();
var fullPath = !string.IsNullOrEmpty(Container.ContainerRuntimePath) ? $"{PrependPath}:{Container.ContainerRuntimePath}" : PrependPath; string dockerClientPath = dockerManager.DockerPath;
dockerCommandArgs.Add($"-e PATH=\"{fullPath}\"");
}
// CONTAINER // Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
dockerCommandArgs.Add($"{Container.ContainerId}"); IList<string> dockerCommandArgs = new List<string>();
dockerCommandArgs.Add($"exec");
// COMMAND // [OPTIONS]
dockerCommandArgs.Add(fileName); dockerCommandArgs.Add($"-i");
dockerCommandArgs.Add($"--workdir {workingDirectory}");
foreach (var env in environment)
{
// e.g. -e MY_SECRET maps the value into the exec'ed process without exposing
// the value directly in the command
dockerCommandArgs.Add($"-e {env.Key}");
}
if (!string.IsNullOrEmpty(PrependPath))
{
// Prepend tool paths to container's PATH
var fullPath = !string.IsNullOrEmpty(Container.ContainerRuntimePath) ? $"{PrependPath}:{Container.ContainerRuntimePath}" : PrependPath;
dockerCommandArgs.Add($"-e PATH=\"{fullPath}\"");
}
// [ARG...] // CONTAINER
dockerCommandArgs.Add(arguments); dockerCommandArgs.Add($"{Container.ContainerId}");
string dockerCommandArgstring = string.Join(" ", dockerCommandArgs); // COMMAND
dockerCommandArgs.Add(fileName);
// make sure all env are using container path // [ARG...]
foreach (var envKey in environment.Keys.ToList()) dockerCommandArgs.Add(arguments);
{
environment[envKey] = this.Container.TranslateToContainerPath(environment[envKey]);
}
using (var processInvoker = HostContext.CreateService<IProcessInvoker>()) string dockerCommandArgstring = string.Join(" ", dockerCommandArgs);
{
processInvoker.OutputDataReceived += OutputDataReceived; // make sure all env are using container path
processInvoker.ErrorDataReceived += ErrorDataReceived; foreach (var envKey in environment.Keys.ToList())
{
environment[envKey] = this.Container.TranslateToContainerPath(environment[envKey]);
}
using (var processInvoker = HostContext.CreateService<IProcessInvoker>())
{
processInvoker.OutputDataReceived += OutputDataReceived;
processInvoker.ErrorDataReceived += ErrorDataReceived;
#if OS_WINDOWS #if OS_WINDOWS
// It appears that node.exe outputs UTF8 when not in TTY mode. // It appears that node.exe outputs UTF8 when not in TTY mode.
outputEncoding = Encoding.UTF8; outputEncoding = Encoding.UTF8;
#else #else
// Let .NET choose the default. // Let .NET choose the default.
outputEncoding = null; outputEncoding = null;
#endif #endif
return await processInvoker.ExecuteAsync(workingDirectory: HostContext.GetDirectory(WellKnownDirectory.Work), return await processInvoker.ExecuteAsync(workingDirectory: HostContext.GetDirectory(WellKnownDirectory.Work),
fileName: dockerClientPath, fileName: dockerClientPath,
arguments: dockerCommandArgstring, arguments: dockerCommandArgstring,
environment: environment, environment: environment,
requireExitCodeZero: requireExitCodeZero, requireExitCodeZero: requireExitCodeZero,
outputEncoding: outputEncoding, outputEncoding: outputEncoding,
killProcessOnCancel: killProcessOnCancel, killProcessOnCancel: killProcessOnCancel,
redirectStandardIn: null, redirectStandardIn: null,
inheritConsoleHandler: inheritConsoleHandler, inheritConsoleHandler: inheritConsoleHandler,
cancellationToken: cancellationToken); cancellationToken: cancellationToken);
}
} }
} }
} }