diff --git a/pkg/container/container_types.go b/pkg/container/container_types.go index 627e5d8eb1b..efcc406fcfe 100644 --- a/pkg/container/container_types.go +++ b/pkg/container/container_types.go @@ -30,6 +30,7 @@ type NewContainerInput struct { NetworkAliases []string ExposedPorts nat.PortSet PortBindings nat.PortMap + LogOutput bool } // FileEntry is a file to copy to a container diff --git a/pkg/container/docker_run.go b/pkg/container/docker_run.go index af39c991e54..fb1f6030fdf 100644 --- a/pkg/container/docker_run.go +++ b/pkg/container/docker_run.go @@ -43,6 +43,7 @@ import ( func NewContainer(input *NewContainerInput) ExecutionsEnvironment { cr := new(containerReference) cr.input = input + cr.logOutput = input.LogOutput return cr } @@ -65,8 +66,19 @@ func supportsContainerImagePlatform(ctx context.Context, cli client.APIClient) b } func (cr *containerReference) Create(capAdd []string, capDrop []string) common.Executor { + if cr.logOutput { + return common. + NewInfoExecutor("%sdocker create image=%s platform=%s entrypoint=%+q cmd=%+q network=%+q", logPrefix, cr.input.Image, cr.input.Platform, cr.input.Entrypoint, cr.input.Cmd, cr.input.NetworkMode). + Then( + common.NewPipelineExecutor( + cr.connect(), + cr.find(), + cr.create(capAdd, capDrop), + ).IfNot(common.Dryrun), + ) + } return common. - NewInfoExecutor("%sdocker create image=%s platform=%s entrypoint=%+q cmd=%+q network=%+q", logPrefix, cr.input.Image, cr.input.Platform, cr.input.Entrypoint, cr.input.Cmd, cr.input.NetworkMode). + NewDebugExecutor("%sdocker create image=%s platform=%s entrypoint=%+q cmd=%+q network=%+q", logPrefix, cr.input.Image, cr.input.Platform, cr.input.Entrypoint, cr.input.Cmd, cr.input.NetworkMode). Then( common.NewPipelineExecutor( cr.connect(), @@ -77,8 +89,30 @@ func (cr *containerReference) Create(capAdd []string, capDrop []string) common.E } func (cr *containerReference) Start(attach bool) common.Executor { + if cr.logOutput { + return common. + NewInfoExecutor("%sdocker run image=%s platform=%s entrypoint=%+q cmd=%+q network=%+q", logPrefix, cr.input.Image, cr.input.Platform, cr.input.Entrypoint, cr.input.Cmd, cr.input.NetworkMode). + Then( + common.NewPipelineExecutor( + cr.connect(), + cr.find(), + cr.attach().IfBool(attach), + cr.start(), + cr.wait().IfBool(attach), + cr.tryReadUID(), + cr.tryReadGID(), + func(ctx context.Context) error { + // If this fails, then folders have wrong permissions on non root container + if cr.UID != 0 || cr.GID != 0 { + _ = cr.Exec([]string{"chown", "-R", fmt.Sprintf("%d:%d", cr.UID, cr.GID), cr.input.WorkingDir}, nil, "0", "")(ctx) + } + return nil + }, + ).IfNot(common.Dryrun), + ) + } return common. - NewInfoExecutor("%sdocker run image=%s platform=%s entrypoint=%+q cmd=%+q network=%+q", logPrefix, cr.input.Image, cr.input.Platform, cr.input.Entrypoint, cr.input.Cmd, cr.input.NetworkMode). + NewDebugExecutor("%sdocker run image=%s platform=%s entrypoint=%+q cmd=%+q network=%+q", logPrefix, cr.input.Image, cr.input.Platform, cr.input.Entrypoint, cr.input.Cmd, cr.input.NetworkMode). Then( common.NewPipelineExecutor( cr.connect(), @@ -100,8 +134,21 @@ func (cr *containerReference) Start(attach bool) common.Executor { } func (cr *containerReference) Pull(forcePull bool) common.Executor { + if cr.logOutput { + return common. + NewInfoExecutor("%sdocker pull image=%s platform=%s username=%s forcePull=%t", logPrefix, cr.input.Image, cr.input.Platform, cr.input.Username, forcePull). + Then( + NewDockerPullExecutor(NewDockerPullExecutorInput{ + Image: cr.input.Image, + ForcePull: forcePull, + Platform: cr.input.Platform, + Username: cr.input.Username, + Password: cr.input.Password, + }), + ) + } return common. - NewInfoExecutor("%sdocker pull image=%s platform=%s username=%s forcePull=%t", logPrefix, cr.input.Image, cr.input.Platform, cr.input.Username, forcePull). + NewDebugExecutor("%sdocker pull image=%s platform=%s username=%s forcePull=%t", logPrefix, cr.input.Image, cr.input.Platform, cr.input.Username, forcePull). Then( NewDockerPullExecutor(NewDockerPullExecutorInput{ Image: cr.input.Image, @@ -122,8 +169,21 @@ func (cr *containerReference) Copy(destPath string, files ...*FileEntry) common. } func (cr *containerReference) CopyDir(destPath string, srcPath string, useGitIgnore bool) common.Executor { + if cr.logOutput { + return common.NewPipelineExecutor( + common.NewInfoExecutor("%sdocker cp src=%s dst=%s", logPrefix, srcPath, destPath), + cr.copyDir(destPath, srcPath, useGitIgnore), + func(ctx context.Context) error { + // If this fails, then folders have wrong permissions on non root container + if cr.UID != 0 || cr.GID != 0 { + _ = cr.Exec([]string{"chown", "-R", fmt.Sprintf("%d:%d", cr.UID, cr.GID), destPath}, nil, "0", "")(ctx) + } + return nil + }, + ).IfNot(common.Dryrun) + } return common.NewPipelineExecutor( - common.NewInfoExecutor("%sdocker cp src=%s dst=%s", logPrefix, srcPath, destPath), + common.NewDebugExecutor("%sdocker cp src=%s dst=%s", logPrefix, srcPath, destPath), cr.copyDir(destPath, srcPath, useGitIgnore), func(ctx context.Context) error { // If this fails, then folders have wrong permissions on non root container @@ -152,8 +212,16 @@ func (cr *containerReference) UpdateFromImageEnv(env *map[string]string) common. } func (cr *containerReference) Exec(command []string, env map[string]string, user, workdir string) common.Executor { + if cr.logOutput { + return common.NewPipelineExecutor( + common.NewInfoExecutor("%sdocker exec cmd=[%s] user=%s workdir=%s", logPrefix, strings.Join(command, " "), user, workdir), + cr.connect(), + cr.find(), + cr.exec(command, env, user, workdir), + ).IfNot(common.Dryrun) + } return common.NewPipelineExecutor( - common.NewInfoExecutor("%sdocker exec cmd=[%s] user=%s workdir=%s", logPrefix, strings.Join(command, " "), user, workdir), + common.NewDebugExecutor("%sdocker exec cmd=[%s] user=%s workdir=%s", logPrefix, strings.Join(command, " "), user, workdir), cr.connect(), cr.find(), cr.exec(command, env, user, workdir), @@ -204,11 +272,12 @@ func (cr *containerReference) ReplaceLogWriter(stdout io.Writer, stderr io.Write } type containerReference struct { - cli client.APIClient - id string - input *NewContainerInput - UID int - GID int + cli client.APIClient + id string + input *NewContainerInput + logOutput bool + UID int + GID int LinuxContainerEnvironmentExtensions } diff --git a/pkg/runner/action.go b/pkg/runner/action.go index b46a4d03a75..fe45fbee2b8 100644 --- a/pkg/runner/action.go +++ b/pkg/runner/action.go @@ -434,6 +434,7 @@ func newStepContainer(ctx context.Context, step step, image string, cmd []string UsernsMode: rc.Config.UsernsMode, Platform: rc.Config.ContainerArchitecture, Options: rc.Config.ContainerOptions, + LogOutput: rc.Config.LogOutput, }) return stepContainer } diff --git a/pkg/runner/run_context.go b/pkg/runner/run_context.go index 5d4277123ed..41db802e0fa 100644 --- a/pkg/runner/run_context.go +++ b/pkg/runner/run_context.go @@ -347,6 +347,7 @@ func (rc *RunContext) startJobContainer() common.Executor { NetworkAliases: []string{serviceID}, ExposedPorts: exposedPorts, PortBindings: portBindings, + LogOutput: rc.Config.LogOutput, }) rc.ServiceContainers = append(rc.ServiceContainers, c) } @@ -409,6 +410,7 @@ func (rc *RunContext) startJobContainer() common.Executor { UsernsMode: rc.Config.UsernsMode, Platform: rc.Config.ContainerArchitecture, Options: rc.options(ctx), + LogOutput: rc.Config.LogOutput, }) if rc.JobContainer == nil { return errors.New("Failed to create job container") diff --git a/pkg/runner/step_docker.go b/pkg/runner/step_docker.go index cc28a3b53c5..1e9c37e8979 100644 --- a/pkg/runner/step_docker.go +++ b/pkg/runner/step_docker.go @@ -130,6 +130,7 @@ func (sd *stepDocker) newStepContainer(ctx context.Context, image string, cmd [] Privileged: rc.Config.Privileged, UsernsMode: rc.Config.UsernsMode, Platform: rc.Config.ContainerArchitecture, + LogOutput: rc.Config.LogOutput, }) return stepContainer }