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
|
var exitCode int
|
||||||
exitCode = state.ExitCode
|
exitCode = state.ExitCode
|
||||||
if exitCode > 0 {
|
if exitCode > 0 {
|
||||||
reader, err := options.Container.GetContainerLogs()
|
reader, err := options.Container.GetContainerLogs(container.GetLogOptions{Stderr: true, Follow: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error while trying to retrieve the container logs")
|
log.Printf("Error while trying to retrieve the container logs")
|
||||||
return BootNullString, err
|
return BootNullString, err
|
||||||
@ -197,7 +197,7 @@ func (options *BootstrapContainerOptions) CreateBootstrapContainer() error {
|
|||||||
fmt.Sprintf("%s=%s", envBootstrapVolume, containerVolMount),
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -134,7 +134,7 @@ func (opts BootstrapIsoOptions) CreateBootstrapIso() error {
|
|||||||
fmt.Sprintf("NO_PROXY=%s", os.Getenv("NO_PROXY")),
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -143,7 +143,7 @@ func (opts BootstrapIsoOptions) CreateBootstrapIso() error {
|
|||||||
|
|
||||||
if log.DebugEnabled() {
|
if log.DebugEnabled() {
|
||||||
var cLogs io.ReadCloser
|
var cLogs io.ReadCloser
|
||||||
cLogs, err = opts.Builder.GetContainerLogs()
|
cLogs, err = opts.Builder.GetContainerLogs(container.GetLogOptions{Stderr: true, Follow: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("failed to read container logs %s", err)
|
log.Printf("failed to read container logs %s", err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -19,6 +19,11 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ContainerDriverDocker indicates that docker driver should be used in container constructor
|
||||||
|
ContainerDriverDocker = "docker"
|
||||||
|
)
|
||||||
|
|
||||||
// Status type provides container status
|
// Status type provides container status
|
||||||
type Status string
|
type Status string
|
||||||
|
|
||||||
@ -36,7 +41,7 @@ type State struct {
|
|||||||
type Container interface {
|
type Container interface {
|
||||||
ImagePull() error
|
ImagePull() error
|
||||||
RunCommand(RunCommandOptions) error
|
RunCommand(RunCommandOptions) error
|
||||||
GetContainerLogs() (io.ReadCloser, error)
|
GetContainerLogs(GetLogOptions) (io.ReadCloser, error)
|
||||||
InspectContainer() (State, error)
|
InspectContainer() (State, error)
|
||||||
WaitUntilFinished() error
|
WaitUntilFinished() error
|
||||||
RmContainer() error
|
RmContainer() error
|
||||||
@ -46,14 +51,32 @@ type Container interface {
|
|||||||
// RunCommandOptions options for RunCommand
|
// RunCommandOptions options for RunCommand
|
||||||
type RunCommandOptions struct {
|
type RunCommandOptions struct {
|
||||||
Privileged bool
|
Privileged bool
|
||||||
|
HostNewtork bool
|
||||||
|
|
||||||
Cmd []string
|
Cmd []string
|
||||||
EnvVars []string
|
EnvVars []string
|
||||||
VolumeMounts []string
|
Binds []string
|
||||||
|
|
||||||
|
Mounts []Mount
|
||||||
Input io.Reader
|
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
|
// NewContainer returns instance of Container interface implemented by particular driver
|
||||||
// Returned instance type (i.e. implementation) depends on driver specified via function
|
// Returned instance type (i.e. implementation) depends on driver specified via function
|
||||||
// arguments (e.g. "docker").
|
// arguments (e.g. "docker").
|
||||||
@ -63,7 +86,7 @@ func NewContainer(ctx context.Context, driver string, url string) (Container, er
|
|||||||
switch driver {
|
switch driver {
|
||||||
case "":
|
case "":
|
||||||
return nil, ErrNoContainerDriver{}
|
return nil, ErrNoContainerDriver{}
|
||||||
case "docker":
|
case ContainerDriverDocker:
|
||||||
cli, err := NewDockerClient(ctx)
|
cli, err := NewDockerClient(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"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/api/types/network"
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
|
|
||||||
@ -174,18 +175,36 @@ func (c *DockerContainer) getConfig(opts RunCommandOptions) (container.Config, c
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return container.Config{}, container.HostConfig{}, err
|
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{
|
cCfg := container.Config{
|
||||||
Image: c.imageURL,
|
Image: c.imageURL,
|
||||||
Cmd: cmd,
|
Cmd: cmd,
|
||||||
|
|
||||||
AttachStdin: true,
|
AttachStdin: true,
|
||||||
|
StdinOnce: true,
|
||||||
OpenStdin: true,
|
OpenStdin: true,
|
||||||
|
AttachStderr: true,
|
||||||
|
AttachStdout: true,
|
||||||
Env: opts.EnvVars,
|
Env: opts.EnvVars,
|
||||||
Tty: true,
|
|
||||||
}
|
}
|
||||||
hCfg := container.HostConfig{
|
hCfg := container.HostConfig{
|
||||||
Binds: opts.VolumeMounts,
|
Binds: opts.Binds,
|
||||||
|
Mounts: mounts,
|
||||||
Privileged: opts.Privileged,
|
Privileged: opts.Privileged,
|
||||||
}
|
}
|
||||||
|
if opts.HostNewtork {
|
||||||
|
hCfg.NetworkMode = "host"
|
||||||
|
}
|
||||||
return cCfg, hCfg, nil
|
return cCfg, hCfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,6 +287,8 @@ func (c *DockerContainer) RunCommand(opts RunCommandOptions) (err error) {
|
|||||||
if attachErr != nil {
|
if attachErr != nil {
|
||||||
return attachErr
|
return attachErr
|
||||||
}
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
if _, err = io.Copy(conn.Conn, opts.Input); err != nil {
|
if _, err = io.Copy(conn.Conn, opts.Input); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -282,8 +303,12 @@ func (c *DockerContainer) RunCommand(opts RunCommandOptions) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetContainerLogs returns logs from the container as io.ReadCloser
|
// GetContainerLogs returns logs from the container as io.ReadCloser
|
||||||
func (c *DockerContainer) GetContainerLogs() (io.ReadCloser, error) {
|
func (c *DockerContainer) GetContainerLogs(opts GetLogOptions) (io.ReadCloser, error) {
|
||||||
return c.dockerClient.ContainerLogs(c.ctx, c.id, types.ContainerLogsOptions{ShowStdout: true, Follow: true})
|
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.
|
// RmContainer kills and removes a container from the docker host.
|
||||||
|
@ -286,6 +286,7 @@ func TestRunCommand(t *testing.T) {
|
|||||||
cmd []string
|
cmd []string
|
||||||
containerInput io.Reader
|
containerInput io.Reader
|
||||||
volumeMounts []string
|
volumeMounts []string
|
||||||
|
mounts []Mount
|
||||||
debug bool
|
debug bool
|
||||||
mockDockerClient mockDockerClient
|
mockDockerClient mockDockerClient
|
||||||
expectedRunErr error
|
expectedRunErr error
|
||||||
@ -330,6 +331,14 @@ func TestRunCommand(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedRunErr: nil,
|
expectedRunErr: nil,
|
||||||
|
mounts: []Mount{
|
||||||
|
{
|
||||||
|
ReadOnly: true,
|
||||||
|
Type: "bind",
|
||||||
|
Dst: "/dev/vda0",
|
||||||
|
Src: "/dev/vd3",
|
||||||
|
},
|
||||||
|
},
|
||||||
expectedWaitErr: nil,
|
expectedWaitErr: nil,
|
||||||
assertF: func(t *testing.T) {},
|
assertF: func(t *testing.T) {},
|
||||||
},
|
},
|
||||||
@ -424,7 +433,8 @@ func TestRunCommand(t *testing.T) {
|
|||||||
actualErr := cnt.RunCommand(RunCommandOptions{
|
actualErr := cnt.RunCommand(RunCommandOptions{
|
||||||
Input: tt.containerInput,
|
Input: tt.containerInput,
|
||||||
Cmd: tt.cmd,
|
Cmd: tt.cmd,
|
||||||
VolumeMounts: tt.volumeMounts,
|
Binds: tt.volumeMounts,
|
||||||
|
Mounts: tt.mounts,
|
||||||
})
|
})
|
||||||
assert.Equal(t, tt.expectedRunErr, actualErr)
|
assert.Equal(t, tt.expectedRunErr, actualErr)
|
||||||
actualErr = cnt.WaitUntilFinished()
|
actualErr = cnt.WaitUntilFinished()
|
||||||
@ -470,10 +480,10 @@ func TestRunCommandOutput(t *testing.T) {
|
|||||||
actualErr := cnt.RunCommand(RunCommandOptions{
|
actualErr := cnt.RunCommand(RunCommandOptions{
|
||||||
Input: tt.containerInput,
|
Input: tt.containerInput,
|
||||||
Cmd: tt.cmd,
|
Cmd: tt.cmd,
|
||||||
VolumeMounts: tt.volumeMounts,
|
Binds: tt.volumeMounts,
|
||||||
})
|
})
|
||||||
assert.Equal(t, tt.expectedErr, actualErr)
|
assert.Equal(t, tt.expectedErr, actualErr)
|
||||||
actualRes, actualErr := cnt.GetContainerLogs()
|
actualRes, actualErr := cnt.GetContainerLogs(GetLogOptions{Stdout: true, Follow: true})
|
||||||
require.NoError(t, actualErr)
|
require.NoError(t, actualErr)
|
||||||
|
|
||||||
var actualResBytes []byte
|
var actualResBytes []byte
|
||||||
|
@ -42,7 +42,7 @@ func (mc *MockContainer) RunCommand(container.RunCommandOptions) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetContainerLogs Container interface implementation for unit test purposes
|
// 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()
|
return mc.MockGetContainerLogs()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user