Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Write docker output to op writer #234

Merged
merged 1 commit into from
Dec 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion action/operation_configs.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,13 @@ func (cfgs OperationConfigs) ApplyConfig(op *driver.Operation) error {
}
}

// If out wasn't configured, default it
// If outputs weren't configured, default them
if op.Out == nil {
op.Out = os.Stdout
}
if op.Err == nil {
op.Err = os.Stderr
}

return nil
}
9 changes: 6 additions & 3 deletions action/operation_configs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package action

import (
"errors"
"io/ioutil"
"os"
"testing"

Expand All @@ -18,6 +19,7 @@ func TestOperationConfigs_ApplyConfig(t *testing.T) {
err := a.ApplyConfig(op)
assert.NoError(t, err, "ApplyConfig should not have returned an error")
assert.Equal(t, os.Stdout, op.Out, "write to stdout when output is undefined")
assert.Equal(t, os.Stderr, op.Err, "write to stderr when output is undefined")
})

t.Run("all config is persisted", func(t *testing.T) {
Expand All @@ -30,15 +32,16 @@ func TestOperationConfigs_ApplyConfig(t *testing.T) {
return nil
},
func(op *driver.Operation) error {
op.Out = os.Stdout
op.Out = ioutil.Discard
return nil
},
}
op := &driver.Operation{}
err := a.ApplyConfig(op)
require.NoError(t, err, "ApplyConfig should not have returned an error")
assert.Contains(t, op.Files, "a", "Changes from the first config function were not persisted")
assert.Equal(t, os.Stdout, op.Out, "Changes from the second config function were not persisted")
assert.Equal(t, ioutil.Discard, op.Out, "Changes from the second config function were not persisted")
assert.Equal(t, os.Stderr, op.Err, "Changes from the second config function were not persisted")
})

t.Run("error is returned immediately", func(t *testing.T) {
Expand All @@ -47,7 +50,7 @@ func TestOperationConfigs_ApplyConfig(t *testing.T) {
return errors.New("oops")
},
func(op *driver.Operation) error {
op.Out = os.Stdout
op.Out = ioutil.Discard
return nil
},
}
Expand Down
2 changes: 1 addition & 1 deletion driver/command/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ func (d *Driver) exec(op *driver.Operation) (driver.OperationResult, error) {

// Errors not handled here as they only prevent output from the driver being shown, errors in the command execution are handled when command is executed

io.Copy(op.Out, stderr)
io.Copy(op.Err, stderr)
}()

if err = cmd.Start(); err != nil {
Expand Down
5 changes: 2 additions & 3 deletions driver/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"fmt"
"io"
"io/ioutil"
"os"
unix_path "path"

"github.com/docker/cli/cli/command"
Expand Down Expand Up @@ -251,8 +250,8 @@ func (d *Driver) exec(op *driver.Operation) (driver.OperationResult, error) {
return driver.OperationResult{}, fmt.Errorf("unable to retrieve logs: %v", err)
}
var (
stdout io.Writer = os.Stdout
stderr io.Writer = os.Stderr
stdout = op.Out
stderr = op.Err
)
if d.containerOut != nil {
stdout = d.containerOut
Expand Down
33 changes: 33 additions & 0 deletions driver/docker/docker_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ func TestDriver_Run(t *testing.T) {

docker := &Driver{}
docker.SetContainerOut(op.Out) // Docker driver writes container stdout to driver.containerOut.
docker.SetContainerOut(op.Err)
opResult, err := docker.Run(op)

assert.NoError(t, err)
Expand All @@ -81,6 +82,38 @@ func TestDriver_Run(t *testing.T) {
}, opResult.Outputs)
}

func TestDriver_Run_CaptureOutput(t *testing.T) {
image := bundle.InvocationImage{
BaseImage: bundle.BaseImage{
Image: "carolynvs/cnab-bad-invocation-image:v1",
Digest: "sha256:0705cbb5fdeec6752a0a0f707b8e1f7ad63070bf64713a4d23b69ca452fe3d37",
},
}

op := &driver.Operation{
Installation: "example",
Action: "install",
Image: image,
Bundle: &bundle.Bundle{},
}

var stdout bytes.Buffer
var stderr bytes.Buffer
op.Out = &stdout
op.Err = &stderr
op.Environment = map[string]string{
"CNAB_ACTION": op.Action,
"CNAB_INSTALLATION_NAME": op.Installation,
}

docker := &Driver{}
_, err := docker.Run(op)

assert.NoError(t, err)
assert.Equal(t, "installing bundle...\n", stdout.String())
assert.Equal(t, "cat: can't open 'missing-file.txt': No such file or directory\n", stderr.String())
}

func TestDriver_ValidateImageDigestFail(t *testing.T) {
imageFromEnv, ok := os.LookupEnv("DOCKER_INTEGRATION_TEST_IMAGE")
var image bundle.InvocationImage
Expand Down
2 changes: 2 additions & 0 deletions driver/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ type Operation struct {
Outputs map[string]string `json:"outputs"`
// Output stream for log messages from the driver
Out io.Writer `json:"-"`
// Output stream for error messages from the driver
Err io.Writer `json:"-"`
// Bundle represents the bundle information for use by the operation
Bundle *bundle.Bundle
}
Expand Down