public static async Task PipeContainerOutput(IOutputObserver outputObserver, MultiplexedStream stream, CancellationToken cancellationToken) { byte[] buffer = new byte[1024]; while (!cancellationToken.IsCancellationRequested) { var result = await stream.ReadOutputAsync(buffer, 0, buffer.Length, cancellationToken); if (result.EOF) { break; } switch (result.Target) { case MultiplexedStream.TargetStream.StandardOut: await outputObserver.StandardOutput(buffer, result.Count); break; case MultiplexedStream.TargetStream.StandardError: await outputObserver.StandardError(buffer, result.Count); break; } } }
internal void AddOutputObserver(IOutputObserver obs) { m_OutputMessage += new ModelHandler<GlobalStateModel>(obs.NewOutputMessage); }
public void usunObserwator(IOutputObserver o) { _listaObserwatorow.Remove(o); }
public void dodajObserwatora(IOutputObserver o) { _listaObserwatorow.Add(o); }
public async Task <int> RunBuild(Protocol.RunDockerBuild build, IOutputObserver outputObserver, CancellationToken cancellationToken) { await CleanupNetworks(cancellationToken); CreateContainerResponse?proxyContainer = null; try { proxyContainer = await docker.Containers.CreateContainerAsync(new CreateContainerParameters { Image = build.ProxyImage, Env = build.EnableNetwork ? null : new List <string> { "HELIUM_PROXY_REPLAY=true" }, HostConfig = new HostConfig { AutoRemove = true, NetworkMode = build.EnableNetwork ? null : "none", Isolation = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "process" : null, }, }, cancellationToken); NetworksCreateResponse?network = null; try { var networkName = networkTag + "-" + proxyContainer.ID; network = await docker.Networks.CreateNetworkAsync( new NetworksCreateParameters { Name = networkName, Internal = true, }, cancellationToken ); await docker.Networks.ConnectNetworkAsync( network.ID, new NetworkConnectParameters { Container = proxyContainer.ID, EndpointConfig = new EndpointSettings { Aliases = new List <string> { buildProxyHostname, }, }, }, cancellationToken ); var buildMapping = new Dictionary <string, string>(); string?imageId = null; foreach (var imageBuild in build.Dockerfile.Builds) { var id = await RunSingleImageBuild(imageBuild, network.ID, buildMapping, outputObserver, cancellationToken); if (imageBuild.FromCommand.AsName != null) { buildMapping.Add(imageBuild.FromCommand.AsName, id); } imageId = id; } if (imageId == null) { throw new Exception("No images were built"); } await using (var imageFile = File.Create(build.OutputFile)) { await docker.Images.SaveImageAsync(imageId, cancellationToken); } return(0); } finally { if (network != null) { await docker.Networks.DeleteNetworkAsync(network.ID, cancellationToken); } } } catch (RunCommandFailedException ex) { await outputObserver.StandardOutput(ex.Message); return(ex.ExitCode); } catch (Exception ex) { await outputObserver.StandardOutput(ex.Message); return(1); } finally { if (proxyContainer != null) { await docker.Containers.RemoveContainerAsync( proxyContainer.ID, new ContainerRemoveParameters { Force = true }, cancellationToken ); } } }
private async Task <string> HandleRunCommandCommon(BuildState state, string proxyNetworkId, ReadOnlyDictionary <string, string> buildArgs, IReadOnlyList <string> command, IOutputObserver outputObserver, CancellationToken cancellationToken) { var nonEnvArgs = buildArgs.Where(arg => !state.Environment.ContainsKey(arg.Key)).ToList(); var response = await docker.Containers.CreateContainerAsync( new Docker.DotNet.Models.CreateContainerParameters { Image = state.Id, Env = nonEnvArgs.Select(env => $"{env.Key}={env.Value}").Concat(proxyEnv).ToList(), AttachStderr = true, AttachStdout = true, Cmd = command.ToList(), HostConfig = new Docker.DotNet.Models.HostConfig { NetworkMode = proxyNetworkId, Isolation = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "process" : null, }, }, cancellationToken ); try { using var stream = await docker.Containers.AttachContainerAsync( response.ID, tty : false, new Docker.DotNet.Models.ContainerAttachParameters { Stream = true, Stderr = true, Stdout = true, }, cancellationToken ); await docker.Containers.StartContainerAsync( response.ID, new Docker.DotNet.Models.ContainerStartParameters { }, cancellationToken ); await DockerHelpers.PipeContainerOutput(outputObserver, stream, cancellationToken); var waitResponse = await docker.Containers.WaitContainerAsync(response.ID, cancellationToken); int exitCode = (int)waitResponse.StatusCode; if (exitCode != 0) { throw new RunCommandFailedException($"Command failed with exit code {exitCode}.", exitCode); } var image = await docker.Images.CommitContainerChangesAsync(new CommitContainerChangesParameters { ContainerID = response.ID, Config = new Config { Env = nonEnvArgs.Select(env => env.Key).ToList(), }, }, cancellationToken); return(image.ID); } finally { await docker.Containers.RemoveContainerAsync(response.ID, new Docker.DotNet.Models.ContainerRemoveParameters(), cancellationToken); } }
private Task <string> HandleRunShellCommand(BuildState state, string proxyNetworkId, RunShellCommand runShell, IOutputObserver outputObserver, CancellationToken cancellationToken) { var cmd = state.Shell.ToList(); cmd.Add(runShell.ShellCommand); return(HandleRunCommandCommon(state, proxyNetworkId, runShell.BuildArgs, cmd, outputObserver, cancellationToken)); }
private Task <string> HandleRunExecCommand(BuildState state, string proxyNetworkId, RunExecCommand runExec, IOutputObserver outputObserver, CancellationToken cancellationToken) => HandleRunCommandCommon(state, proxyNetworkId, runExec.BuildArgs, runExec.ExecCommand, outputObserver, cancellationToken);
private async Task <string> RunSingleImageBuild(DockerfileBuild imageBuild, string proxyNetworkId, IReadOnlyDictionary <string, string> buildMapping, IOutputObserver outputObserver, CancellationToken cancellationToken) { string id = imageBuild.FromCommand.Image; if (id == "scratch") { throw new Exception("FROM scratch is not supported"); } var state = await InitialBuildState(id); foreach (var command in imageBuild.Commands) { var prevId = id; id = command switch { RunExecCommand runExec => await HandleRunExecCommand(state, proxyNetworkId, runExec, outputObserver, cancellationToken), RunShellCommand runShell => await HandleRunShellCommand(state, proxyNetworkId, runShell, outputObserver, cancellationToken), _ => throw new Exception("Unexpected command"), }; if (prevId != imageBuild.FromCommand.Image) { await docker.Images.DeleteImageAsync(prevId, new ImageDeleteParameters(), cancellationToken); } state.Id = id; } return(id); }
private static async Task <int> RunDocker(IDockerClient client, RunDockerCommand command, string callingContainerId, IOutputObserver outputObserver, CancellationToken cancellationToken) { var allowedMounts = await GetMounts(client, callingContainerId, cancellationToken); if (!(ValidateDockerCommand(command) && ValidateMounts(command.BindMounts, allowedMounts) is {} mounts)) { await Console.Error.WriteLineAsync("Could not validate docker command."); return(1); } var response = await client.Containers.CreateContainerAsync( new Docker.DotNet.Models.CreateContainerParameters { Image = command.ImageName, Env = command.Environment.Select(env => $"{env.Key}={env.Value}").ToList(), AttachStderr = true, AttachStdout = true, ArgsEscaped = false, Cmd = command.Command.ToList(), WorkingDir = command.CurrentDirectory, HostConfig = new Docker.DotNet.Models.HostConfig { AutoRemove = true, NetworkMode = "none", Isolation = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "process" : null, Mounts = mounts, }, }, cancellationToken ); using var stream = await client.Containers.AttachContainerAsync( response.ID, tty : false, new Docker.DotNet.Models.ContainerAttachParameters { Stream = true, Stderr = true, Stdout = true, }, cancellationToken ); await client.Containers.StartContainerAsync( response.ID, new Docker.DotNet.Models.ContainerStartParameters { }, cancellationToken ); await DockerHelpers.PipeContainerOutput(outputObserver, stream, cancellationToken); var waitResponse = await client.Containers.WaitContainerAsync(response.ID, cancellationToken); return((int)waitResponse.StatusCode); }