From 7993fb62a11d575dc4154ac650d2c3d68b4f29dd Mon Sep 17 00:00:00 2001 From: David Choi Date: Fri, 19 May 2023 15:56:08 -0700 Subject: [PATCH] Initial attached implementation - should consider if a container is started with TTY, currently only assuming all no-TTY containers only --- system/docker/contract.go | 11 ++++++-- system/docker/service.go | 58 ++++++++++++++++++++++++++++++++++----- 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/system/docker/contract.go b/system/docker/contract.go index 903a365a..eb3a5224 100644 --- a/system/docker/contract.go +++ b/system/docker/contract.go @@ -2,6 +2,8 @@ package docker import ( "fmt" + "strings" + "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/mount" @@ -10,7 +12,6 @@ import ( "github.com/viant/toolbox" "github.com/viant/toolbox/secret" "github.com/viant/toolbox/url" - "strings" ) //RunRequest represents a docker runAdapter request @@ -24,6 +25,7 @@ type RunRequest struct { Ports map[string]string `description:"publish a container’s port(s) to the host, docker -p option"` Workdir string `description:"working directory inside the container, docker -w option"` Reuse bool `description:"reuse existing container if exists, otherwise always removes"` + Foreground bool `description:"wait for container to stop"` Cmd []string Entrypoint []string types.ContainerCreateConfig `json:",inline" yaml:",inline"` @@ -118,7 +120,10 @@ type StatusResponse struct { } //StartRequest start request -type StartRequest StatusRequest +type StartRequest struct { + StatusRequest + Foreground bool +} //StartResponse represents docker start response type StartResponse StopResponse @@ -310,7 +315,7 @@ func (r *RemoveRequest) AsStatusRequest() *StatusRequest { //StatusRequest returns status request func (r *StartRequest) AsStatusRequest() *StatusRequest { - result := StatusRequest(*r) + result := StatusRequest((*r).StatusRequest) return &result } diff --git a/system/docker/service.go b/system/docker/service.go index b60527d1..e8fbb316 100644 --- a/system/docker/service.go +++ b/system/docker/service.go @@ -4,18 +4,21 @@ import ( "archive/tar" "bytes" "fmt" + "io" + "io/ioutil" + "log" + "path" + "strings" + "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/client" + "github.com/docker/docker/pkg/stdcopy" "github.com/go-errors/errors" "github.com/viant/endly" + "github.com/viant/endly/model/msg" "github.com/viant/toolbox" "github.com/viant/toolbox/url" - "io" - "io/ioutil" - "log" - "path" - "strings" ) const ( @@ -111,7 +114,10 @@ func (s *service) run(context *endly.Context, request *RunRequest) (*RunResponse return response, nil } _, err := s.start(context, &StartRequest{ - IDs: []string{containerInfo.ID}, + StatusRequest: StatusRequest{ + IDs: []string{containerInfo.ID}, + }, + Foreground: request.Foreground, }) return response, err } @@ -146,7 +152,10 @@ func (s *service) run(context *endly.Context, request *RunRequest) (*RunResponse return nil, err } response.ContainerID = createResponse.ID - startRequest := &StartRequest{IDs: []string{createResponse.ID}} + startRequest := &StartRequest{ + StatusRequest: StatusRequest{IDs: []string{createResponse.ID}}, + Foreground: request.Foreground, + } if _, err := s.start(context, startRequest); err != nil { return nil, err @@ -414,7 +423,42 @@ func (s *service) start(context *endly.Context, request *StartRequest) (*StartRe if err = runAdapter(context, startRequest, nil); err != nil { return nil, err } + + if !request.Foreground { + continue + } + + err = func() error { + attachRequest := &ContainerAttachRequest{ + Container: candidate.ID, + ContainerAttachOptions: types.ContainerAttachOptions{ + Stream: true, + Stdout: true, + Stderr: true, + }, + } + + resp := new(types.HijackedResponse) + err := runAdapter(context, attachRequest, resp) + if err != nil { + return err + } + + defer resp.Close() + stdout := new(strings.Builder) + stderr := new(strings.Builder) + _, err = stdcopy.StdCopy(stdout, stderr, resp.Reader) + context.Publish(msg.NewStdoutEvent("run", stdout.String())) + context.Publish(msg.NewStdoutEvent("run:stderr", stderr.String())) + return err + + }() + + if err != nil { + return nil, err + } } + return response, nil }