Extend container interface with mounts get log opts
This commit allows to specify options to get container logs, such as stderr, stdout and if logs should be followed. Also extends RunCommandOptions with ability to add mounts in addtion to binds Relates-To: #458 Change-Id: I83507f2f7ca6ea596f52f5d3e9f868467458b6a3
This commit is contained in:
parent
4671ea7f74
commit
971c81acdb
@ -123,7 +123,7 @@ func (options *BootstrapContainerOptions) GetContainerStatus() (container.Status
|
||||
var exitCode int
|
||||
exitCode = state.ExitCode
|
||||
if exitCode > 0 {
|
||||
reader, err := options.Container.GetContainerLogs()
|
||||
reader, err := options.Container.GetContainerLogs(container.GetLogOptions{Stderr: true, Follow: true})
|
||||
if err != nil {
|
||||
log.Printf("Error while trying to retrieve the container logs")
|
||||
return BootNullString, err
|
||||
@ -197,7 +197,7 @@ func (options *BootstrapContainerOptions) CreateBootstrapContainer() error {
|
||||
fmt.Sprintf("%s=%s", envBootstrapVolume, containerVolMount),
|
||||
}
|
||||
|
||||
err := options.Container.RunCommand(container.RunCommandOptions{EnvVars: envVars, VolumeMounts: vols})
|
||||
err := options.Container.RunCommand(container.RunCommandOptions{EnvVars: envVars, Binds: vols})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ func (opts BootstrapIsoOptions) CreateBootstrapIso() error {
|
||||
fmt.Sprintf("NO_PROXY=%s", os.Getenv("NO_PROXY")),
|
||||
}
|
||||
|
||||
err = opts.Builder.RunCommand(container.RunCommandOptions{EnvVars: envVars, VolumeMounts: vols})
|
||||
err = opts.Builder.RunCommand(container.RunCommandOptions{EnvVars: envVars, Binds: vols})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -143,7 +143,7 @@ func (opts BootstrapIsoOptions) CreateBootstrapIso() error {
|
||||
|
||||
if log.DebugEnabled() {
|
||||
var cLogs io.ReadCloser
|
||||
cLogs, err = opts.Builder.GetContainerLogs()
|
||||
cLogs, err = opts.Builder.GetContainerLogs(container.GetLogOptions{Stderr: true, Follow: true})
|
||||
if err != nil {
|
||||
log.Printf("failed to read container logs %s", err)
|
||||
} else {
|
||||
|
@ -19,6 +19,11 @@ import (
|
||||
"io"
|
||||
)
|
||||
|
||||
const (
|
||||
// ContainerDriverDocker indicates that docker driver should be used in container constructor
|
||||
ContainerDriverDocker = "docker"
|
||||
)
|
||||
|
||||
// Status type provides container status
|
||||
type Status string
|
||||
|
||||
@ -36,7 +41,7 @@ type State struct {
|
||||
type Container interface {
|
||||
ImagePull() error
|
||||
RunCommand(RunCommandOptions) error
|
||||
GetContainerLogs() (io.ReadCloser, error)
|
||||
GetContainerLogs(GetLogOptions) (io.ReadCloser, error)
|
||||
InspectContainer() (State, error)
|
||||
WaitUntilFinished() error
|
||||
RmContainer() error
|
||||
@ -45,13 +50,31 @@ type Container interface {
|
||||
|
||||
// RunCommandOptions options for RunCommand
|
||||
type RunCommandOptions struct {
|
||||
Privileged bool
|
||||
Privileged bool
|
||||
HostNewtork bool
|
||||
|
||||
Cmd []string
|
||||
EnvVars []string
|
||||
VolumeMounts []string
|
||||
Cmd []string
|
||||
EnvVars []string
|
||||
Binds []string
|
||||
|
||||
Input io.Reader
|
||||
Mounts []Mount
|
||||
Input io.Reader
|
||||
}
|
||||
|
||||
// Mount describes mount settings
|
||||
type Mount struct {
|
||||
ReadOnly bool
|
||||
Type string
|
||||
Dst string
|
||||
Src string
|
||||
}
|
||||
|
||||
// GetLogOptions options for getting logs
|
||||
// If both Stderr and Stdout are specified the logs will contain both stderr and stdout
|
||||
type GetLogOptions struct {
|
||||
Stderr bool
|
||||
Stdout bool
|
||||
Follow bool
|
||||
}
|
||||
|
||||
// NewContainer returns instance of Container interface implemented by particular driver
|
||||
@ -63,7 +86,7 @@ func NewContainer(ctx context.Context, driver string, url string) (Container, er
|
||||
switch driver {
|
||||
case "":
|
||||
return nil, ErrNoContainerDriver{}
|
||||
case "docker":
|
||||
case ContainerDriverDocker:
|
||||
cli, err := NewDockerClient(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -24,6 +24,7 @@ import (
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/mount"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/client"
|
||||
|
||||
@ -174,18 +175,36 @@ func (c *DockerContainer) getConfig(opts RunCommandOptions) (container.Config, c
|
||||
if err != nil {
|
||||
return container.Config{}, container.HostConfig{}, err
|
||||
}
|
||||
|
||||
mounts := []mount.Mount{}
|
||||
for _, mnt := range opts.Mounts {
|
||||
mounts = append(mounts, mount.Mount{
|
||||
Type: mount.Type(mnt.Type),
|
||||
Source: mnt.Src,
|
||||
Target: mnt.Dst,
|
||||
ReadOnly: mnt.ReadOnly,
|
||||
})
|
||||
}
|
||||
|
||||
cCfg := container.Config{
|
||||
Image: c.imageURL,
|
||||
Cmd: cmd,
|
||||
AttachStdin: true,
|
||||
OpenStdin: true,
|
||||
Env: opts.EnvVars,
|
||||
Tty: true,
|
||||
Image: c.imageURL,
|
||||
Cmd: cmd,
|
||||
|
||||
AttachStdin: true,
|
||||
StdinOnce: true,
|
||||
OpenStdin: true,
|
||||
AttachStderr: true,
|
||||
AttachStdout: true,
|
||||
Env: opts.EnvVars,
|
||||
}
|
||||
hCfg := container.HostConfig{
|
||||
Binds: opts.VolumeMounts,
|
||||
Binds: opts.Binds,
|
||||
Mounts: mounts,
|
||||
Privileged: opts.Privileged,
|
||||
}
|
||||
if opts.HostNewtork {
|
||||
hCfg.NetworkMode = "host"
|
||||
}
|
||||
return cCfg, hCfg, nil
|
||||
}
|
||||
|
||||
@ -268,6 +287,8 @@ func (c *DockerContainer) RunCommand(opts RunCommandOptions) (err error) {
|
||||
if attachErr != nil {
|
||||
return attachErr
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
if _, err = io.Copy(conn.Conn, opts.Input); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -282,8 +303,12 @@ func (c *DockerContainer) RunCommand(opts RunCommandOptions) (err error) {
|
||||
}
|
||||
|
||||
// GetContainerLogs returns logs from the container as io.ReadCloser
|
||||
func (c *DockerContainer) GetContainerLogs() (io.ReadCloser, error) {
|
||||
return c.dockerClient.ContainerLogs(c.ctx, c.id, types.ContainerLogsOptions{ShowStdout: true, Follow: true})
|
||||
func (c *DockerContainer) GetContainerLogs(opts GetLogOptions) (io.ReadCloser, error) {
|
||||
return c.dockerClient.ContainerLogs(c.ctx, c.id, types.ContainerLogsOptions{
|
||||
ShowStderr: opts.Stderr,
|
||||
Follow: opts.Follow,
|
||||
ShowStdout: opts.Stdout,
|
||||
})
|
||||
}
|
||||
|
||||
// RmContainer kills and removes a container from the docker host.
|
||||
|
@ -286,6 +286,7 @@ func TestRunCommand(t *testing.T) {
|
||||
cmd []string
|
||||
containerInput io.Reader
|
||||
volumeMounts []string
|
||||
mounts []Mount
|
||||
debug bool
|
||||
mockDockerClient mockDockerClient
|
||||
expectedRunErr error
|
||||
@ -329,7 +330,15 @@ func TestRunCommand(t *testing.T) {
|
||||
return conn, nil
|
||||
},
|
||||
},
|
||||
expectedRunErr: nil,
|
||||
expectedRunErr: nil,
|
||||
mounts: []Mount{
|
||||
{
|
||||
ReadOnly: true,
|
||||
Type: "bind",
|
||||
Dst: "/dev/vda0",
|
||||
Src: "/dev/vd3",
|
||||
},
|
||||
},
|
||||
expectedWaitErr: nil,
|
||||
assertF: func(t *testing.T) {},
|
||||
},
|
||||
@ -422,9 +431,10 @@ func TestRunCommand(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
cnt := getDockerContainerMock(tt.mockDockerClient)
|
||||
actualErr := cnt.RunCommand(RunCommandOptions{
|
||||
Input: tt.containerInput,
|
||||
Cmd: tt.cmd,
|
||||
VolumeMounts: tt.volumeMounts,
|
||||
Input: tt.containerInput,
|
||||
Cmd: tt.cmd,
|
||||
Binds: tt.volumeMounts,
|
||||
Mounts: tt.mounts,
|
||||
})
|
||||
assert.Equal(t, tt.expectedRunErr, actualErr)
|
||||
actualErr = cnt.WaitUntilFinished()
|
||||
@ -468,12 +478,12 @@ func TestRunCommandOutput(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
cnt := getDockerContainerMock(tt.mockDockerClient)
|
||||
actualErr := cnt.RunCommand(RunCommandOptions{
|
||||
Input: tt.containerInput,
|
||||
Cmd: tt.cmd,
|
||||
VolumeMounts: tt.volumeMounts,
|
||||
Input: tt.containerInput,
|
||||
Cmd: tt.cmd,
|
||||
Binds: tt.volumeMounts,
|
||||
})
|
||||
assert.Equal(t, tt.expectedErr, actualErr)
|
||||
actualRes, actualErr := cnt.GetContainerLogs()
|
||||
actualRes, actualErr := cnt.GetContainerLogs(GetLogOptions{Stdout: true, Follow: true})
|
||||
require.NoError(t, actualErr)
|
||||
|
||||
var actualResBytes []byte
|
||||
|
@ -42,7 +42,7 @@ func (mc *MockContainer) RunCommand(container.RunCommandOptions) error {
|
||||
}
|
||||
|
||||
// GetContainerLogs Container interface implementation for unit test purposes
|
||||
func (mc *MockContainer) GetContainerLogs() (io.ReadCloser, error) {
|
||||
func (mc *MockContainer) GetContainerLogs(container.GetLogOptions) (io.ReadCloser, error) {
|
||||
return mc.MockGetContainerLogs()
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user