diff --git a/cli/app/cp.go b/cli/app/cp.go index b073781a..ab167167 100644 --- a/cli/app/cp.go +++ b/cli/app/cp.go @@ -18,7 +18,7 @@ import ( "coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/upstream/container" "github.com/docker/cli/cli/command" - containertypes "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types" dockerClient "github.com/docker/docker/client" "github.com/docker/docker/errdefs" "github.com/docker/docker/pkg/archive" @@ -33,7 +33,7 @@ var AppCpCommand = &cobra.Command{ abra app cp 1312.net myfile.txt app:/ # copy that file back to your current working directory locally - abra app cp 1312.net app:/myfile.txt ./`, + abra app cp 1312.net app:/myfile.txt`, Args: cobra.ExactArgs(3), ValidArgsFunction: func( cmd *cobra.Command, @@ -134,14 +134,14 @@ func CopyToContainer(cl *dockerClient.Client, containerID, srcPath, dstPath stri if err != nil { return err } - if _, err := container.RunExec(dcli, cl, containerID, &containertypes.ExecOptions{ + if _, err := container.RunExec(dcli, cl, containerID, &types.ExecConfig{ AttachStderr: true, AttachStdin: true, AttachStdout: true, Cmd: []string{"mkdir", "-p", dstPath}, Detach: false, Tty: true, - }, true); err != nil { + }); err != nil { return fmt.Errorf("create remote directory: %s", err) } case CopyModeFileToFile: @@ -162,7 +162,7 @@ func CopyToContainer(cl *dockerClient.Client, containerID, srcPath, dstPath stri } log.Debugf("copy %s from local to %s on container", srcPath, dstPath) - copyOpts := containertypes.CopyToContainerOptions{AllowOverwriteDirWithFile: false, CopyUIDGID: false} + copyOpts := types.CopyToContainerOptions{AllowOverwriteDirWithFile: false, CopyUIDGID: false} if err := cl.CopyToContainer(context.Background(), containerID, dstPath, content, copyOpts); err != nil { return err } @@ -173,14 +173,14 @@ func CopyToContainer(cl *dockerClient.Client, containerID, srcPath, dstPath stri if err != nil { return err } - if _, err := container.RunExec(dcli, cl, containerID, &containertypes.ExecOptions{ + if _, err := container.RunExec(dcli, cl, containerID, &types.ExecConfig{ AttachStderr: true, AttachStdin: true, AttachStdout: true, Cmd: []string{"mv", path.Join("/tmp", srcFile), movePath}, Detach: false, Tty: true, - }, true); err != nil { + }); err != nil { return fmt.Errorf("create remote directory: %s", err) } } diff --git a/cli/app/run.go b/cli/app/run.go index 3c6a3205..637531ed 100644 --- a/cli/app/run.go +++ b/cli/app/run.go @@ -11,7 +11,7 @@ import ( "coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/upstream/container" "github.com/docker/cli/cli/command" - containertypes "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" "github.com/spf13/cobra" ) @@ -64,7 +64,7 @@ var AppRunCommand = &cobra.Command{ } userCmd := args[2:] - execCreateOpts := containertypes.ExecOptions{ + execCreateOpts := types.ExecConfig{ AttachStderr: true, AttachStdin: true, AttachStdout: true, @@ -85,7 +85,7 @@ var AppRunCommand = &cobra.Command{ log.Fatal(err) } - if _, err := container.RunExec(dcli, cl, targetContainer.ID, &execCreateOpts, true); err != nil { + if _, err := container.RunExec(dcli, cl, targetContainer.ID, &execCreateOpts); err != nil { log.Fatal(err) } }, diff --git a/cli/internal/backup.go b/cli/internal/backup.go index 67b8c971..1080d7ce 100644 --- a/cli/internal/backup.go +++ b/cli/internal/backup.go @@ -12,7 +12,6 @@ import ( "coopcloud.tech/abra/pkg/upstream/container" "github.com/docker/cli/cli/command" "github.com/docker/docker/api/types" - containertypes "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" dockerClient "github.com/docker/docker/client" ) @@ -48,7 +47,7 @@ func RunBackupCmdRemote( backupCmd string, containerID string, execEnv []string) (io.Writer, error) { - execBackupListOpts := containertypes.ExecOptions{ + execBackupListOpts := types.ExecConfig{ AttachStderr: true, AttachStdin: true, AttachStdout: true, @@ -66,10 +65,10 @@ func RunBackupCmdRemote( return nil, err } - _, err = container.RunExec(dcli, cl, containerID, &execBackupListOpts, true) + out, err := container.RunExec(dcli, cl, containerID, &execBackupListOpts) if err != nil { return nil, err } - return nil, nil + return out, nil } diff --git a/cli/internal/command.go b/cli/internal/command.go index 9f6ab712..e14893ac 100644 --- a/cli/internal/command.go +++ b/cli/internal/command.go @@ -14,7 +14,7 @@ import ( "coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/upstream/container" "github.com/docker/cli/cli/command" - containertypes "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" dockerClient "github.com/docker/docker/client" "github.com/docker/docker/pkg/archive" @@ -24,7 +24,7 @@ import ( func RunCmdRemote( cl *dockerClient.Client, app appPkg.App, - disableTTY bool, + requestTTY bool, abraSh, serviceName, cmdName, cmdArgs, remoteUser string) error { filters := filters.NewArgs() filters.Add("name", fmt.Sprintf("^%s_%s", app.StackName(), serviceName)) @@ -42,7 +42,7 @@ func RunCmdRemote( return err } - copyOpts := containertypes.CopyToContainerOptions{AllowOverwriteDirWithFile: false, CopyUIDGID: false} + copyOpts := types.CopyToContainerOptions{AllowOverwriteDirWithFile: false, CopyUIDGID: false} if err := cl.CopyToContainer(context.Background(), targetContainer.ID, "/tmp", content, copyOpts); err != nil { return err } @@ -55,7 +55,7 @@ func RunCmdRemote( shell := "/bin/bash" findShell := []string{"test", "-e", shell} - execCreateOpts := containertypes.ExecOptions{ + execCreateOpts := types.ExecConfig{ AttachStderr: true, AttachStdin: true, AttachStdout: true, @@ -64,7 +64,7 @@ func RunCmdRemote( Tty: false, } - if _, err := container.RunExec(dcli, cl, targetContainer.ID, &execCreateOpts, true); err != nil { + if _, err := container.RunExec(dcli, cl, targetContainer.ID, &execCreateOpts); err != nil { log.Infof("%s does not exist for %s, use /bin/sh as fallback", shell, app.Name) shell = "/bin/sh" } @@ -84,14 +84,12 @@ func RunCmdRemote( } execCreateOpts.Cmd = cmd - - execCreateOpts.Tty = true - if disableTTY { - execCreateOpts.Tty = false + execCreateOpts.Tty = requestTTY + if !requestTTY { log.Debugf("not requesting a remote TTY") } - if _, err := container.RunExec(dcli, cl, targetContainer.ID, &execCreateOpts, true); err != nil { + if _, err := container.RunExec(dcli, cl, targetContainer.ID, &execCreateOpts); err != nil { return err } diff --git a/pkg/upstream/container/exec.go b/pkg/upstream/container/exec.go index 6ecbbe38..584b9206 100644 --- a/pkg/upstream/container/exec.go +++ b/pkg/upstream/container/exec.go @@ -1,7 +1,6 @@ package container // https://github.com/docker/cli/blob/master/cli/command/container/exec.go import ( - "bytes" "context" "errors" "fmt" @@ -10,14 +9,14 @@ import ( "coopcloud.tech/abra/pkg/log" "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" - "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types" apiclient "github.com/docker/docker/client" ) // RunExec runs a command on a remote container. io.Writer corresponds to the // command output. func RunExec(dockerCli command.Cli, client *apiclient.Client, containerID string, - execOptions *container.ExecOptions, stdout bool) (string, error) { + execConfig *types.ExecConfig) (io.Writer, error) { ctx := context.Background() // We need to check the tty _before_ we do the ContainerExecCreate, because @@ -25,68 +24,62 @@ func RunExec(dockerCli command.Cli, client *apiclient.Client, containerID string // there's no easy way to clean those up). But also in order to make "not // exist" errors take precedence we do a dummy inspect first. if _, err := client.ContainerInspect(ctx, containerID); err != nil { - return "", err + return nil, err } - if !execOptions.Detach { - if err := dockerCli.In().CheckTty(execOptions.AttachStdin, execOptions.Tty); err != nil { - return "", err + if !execConfig.Detach { + if err := dockerCli.In().CheckTty(execConfig.AttachStdin, execConfig.Tty); err != nil { + return nil, err } } - response, err := client.ContainerExecCreate(ctx, containerID, *execOptions) + response, err := client.ContainerExecCreate(ctx, containerID, *execConfig) if err != nil { - return "", err + return nil, err } execID := response.ID if execID == "" { - return "", errors.New("exec ID empty") + return nil, errors.New("exec ID empty") } - if execOptions.Detach { - execStartCheck := container.ExecStartOptions{ - Detach: execOptions.Detach, - Tty: execOptions.Tty, + if execConfig.Detach { + execStartCheck := types.ExecStartCheck{ + Detach: execConfig.Detach, + Tty: execConfig.Tty, } - return "", client.ContainerExecStart(ctx, execID, execStartCheck) + return nil, client.ContainerExecStart(ctx, execID, execStartCheck) } - return interactiveExec(ctx, dockerCli, client, execOptions, execID, stdout) + return interactiveExec(ctx, dockerCli, client, execConfig, execID) } func interactiveExec(ctx context.Context, dockerCli command.Cli, client *apiclient.Client, - execOpts *container.ExecOptions, execID string, stdout bool) (string, error) { + execConfig *types.ExecConfig, execID string) (io.Writer, error) { // Interactive exec requested. var ( out, stderr io.Writer - outBuffer *bytes.Buffer in io.ReadCloser ) - if execOpts.AttachStdin { + if execConfig.AttachStdin { in = dockerCli.In() } - if execOpts.AttachStdout { - if stdout { - out = dockerCli.Out() - } else { - outBuffer = new(bytes.Buffer) - out = outBuffer - } + if execConfig.AttachStdout { + out = dockerCli.Out() } - if execOpts.AttachStderr { - if execOpts.Tty { + if execConfig.AttachStderr { + if execConfig.Tty { stderr = dockerCli.Out() } else { stderr = dockerCli.Err() } } - execStartCheck := container.ExecStartOptions{ - Tty: execOpts.Tty, + execStartCheck := types.ExecStartCheck{ + Tty: execConfig.Tty, } resp, err := client.ContainerExecAttach(ctx, execID, execStartCheck) if err != nil { - return "", err + return out, err } defer resp.Close() @@ -101,15 +94,15 @@ func interactiveExec(ctx context.Context, dockerCli command.Cli, client *apiclie outputStream: out, errorStream: stderr, resp: resp, - tty: execOpts.Tty, - detachKeys: execOpts.DetachKeys, + tty: execConfig.Tty, + detachKeys: execConfig.DetachKeys, } return streamer.stream(ctx) }() }() - if execOpts.Tty && dockerCli.In().IsTerminal() { + if execConfig.Tty && dockerCli.In().IsTerminal() { if err := MonitorTtySize(ctx, client, dockerCli, execID, true); err != nil { fmt.Fprintln(dockerCli.Err(), "Error monitoring TTY size:", err) } @@ -117,14 +110,10 @@ func interactiveExec(ctx context.Context, dockerCli command.Cli, client *apiclie if err := <-errCh; err != nil { log.Debugf("Error hijack: %s", err) - return "", err + return out, err } - if execOpts.AttachStdout { - return outBuffer.String(), getExecExitStatus(ctx, client, execID) - } - - return "", getExecExitStatus(ctx, client, execID) + return out, getExecExitStatus(ctx, client, execID) } func getExecExitStatus(ctx context.Context, client apiclient.ContainerAPIClient, execID string) error {