Decouple implementations and unit tests in container module
Unit test should follow black-box approach. Change-Id: I98c46c613a73b539f79d8dfe99cd73592792536d Signed-off-by: Ruslan Aliev <raliev@mirantis.com> Closes: #561
This commit is contained in:
parent
3cac887c7d
commit
d1abe6e1ea
@ -51,17 +51,19 @@ type ClientV1Alpha1FactoryFunc func(
|
|||||||
conf *v1alpha1.GenericContainer,
|
conf *v1alpha1.GenericContainer,
|
||||||
targetPath string) ClientV1Alpha1
|
targetPath string) ClientV1Alpha1
|
||||||
|
|
||||||
type clientV1Alpha1 struct {
|
// V1Alpha1 reflects inner struct of ClientV1Alpha1 Interface
|
||||||
|
type V1Alpha1 struct {
|
||||||
resultsDir string
|
resultsDir string
|
||||||
input io.Reader
|
input io.Reader
|
||||||
output io.Writer
|
output io.Writer
|
||||||
conf *v1alpha1.GenericContainer
|
conf *v1alpha1.GenericContainer
|
||||||
targetPath string
|
targetPath string
|
||||||
|
|
||||||
containerFunc containerFunc
|
containerFunc Func
|
||||||
}
|
}
|
||||||
|
|
||||||
type containerFunc func(ctx context.Context, driver string, url string) (Container, error)
|
// Func is type of function which returns Container object
|
||||||
|
type Func func(ctx context.Context, driver string, url string) (Container, error)
|
||||||
|
|
||||||
// NewClientV1Alpha1 constructor for ClientV1Alpha1
|
// NewClientV1Alpha1 constructor for ClientV1Alpha1
|
||||||
func NewClientV1Alpha1(
|
func NewClientV1Alpha1(
|
||||||
@ -70,7 +72,7 @@ func NewClientV1Alpha1(
|
|||||||
output io.Writer,
|
output io.Writer,
|
||||||
conf *v1alpha1.GenericContainer,
|
conf *v1alpha1.GenericContainer,
|
||||||
targetPath string) ClientV1Alpha1 {
|
targetPath string) ClientV1Alpha1 {
|
||||||
return &clientV1Alpha1{
|
return &V1Alpha1{
|
||||||
resultsDir: resultsDir,
|
resultsDir: resultsDir,
|
||||||
output: output,
|
output: output,
|
||||||
input: input,
|
input: input,
|
||||||
@ -80,8 +82,25 @@ func NewClientV1Alpha1(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewV1Alpha1 returns V1Alpha1 struct with desired parameters
|
||||||
|
func NewV1Alpha1(resultsDir string,
|
||||||
|
input io.Reader,
|
||||||
|
output io.Writer,
|
||||||
|
conf *v1alpha1.GenericContainer,
|
||||||
|
targetPath string,
|
||||||
|
containerFunc Func) V1Alpha1 {
|
||||||
|
return V1Alpha1{
|
||||||
|
resultsDir: resultsDir,
|
||||||
|
input: input,
|
||||||
|
output: output,
|
||||||
|
conf: conf,
|
||||||
|
targetPath: targetPath,
|
||||||
|
containerFunc: containerFunc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Run will perform container run action based on the configuration
|
// Run will perform container run action based on the configuration
|
||||||
func (c *clientV1Alpha1) Run() error {
|
func (c *V1Alpha1) Run() error {
|
||||||
// expand Src paths for mount if they are relative
|
// expand Src paths for mount if they are relative
|
||||||
ExpandSourceMounts(c.conf.Spec.StorageMounts, c.targetPath)
|
ExpandSourceMounts(c.conf.Spec.StorageMounts, c.targetPath)
|
||||||
// set default runtime
|
// set default runtime
|
||||||
@ -95,9 +114,9 @@ func (c *clientV1Alpha1) Run() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *clientV1Alpha1) runAirship() error {
|
func (c *V1Alpha1) runAirship() error {
|
||||||
if c.conf.Spec.Airship.ContainerRuntime == "" {
|
if c.conf.Spec.Airship.ContainerRuntime == "" {
|
||||||
c.conf.Spec.Airship.ContainerRuntime = ContainerDriverDocker
|
c.conf.Spec.Airship.ContainerRuntime = DriverDocker
|
||||||
}
|
}
|
||||||
|
|
||||||
var cont Container
|
var cont Container
|
||||||
@ -121,7 +140,7 @@ func (c *clientV1Alpha1) runAirship() error {
|
|||||||
// this will split the env vars into the ones to be exported and the ones that have values
|
// this will split the env vars into the ones to be exported and the ones that have values
|
||||||
contEnv := runtimeutil.NewContainerEnvFromStringSlice(c.conf.Spec.EnvVars)
|
contEnv := runtimeutil.NewContainerEnvFromStringSlice(c.conf.Spec.EnvVars)
|
||||||
|
|
||||||
envs := []string{}
|
envs := make([]string, 0)
|
||||||
for _, key := range contEnv.VarsToExport {
|
for _, key := range contEnv.VarsToExport {
|
||||||
envs = append(envs, strings.Join([]string{key, os.Getenv(key)}, "="))
|
envs = append(envs, strings.Join([]string{key, os.Getenv(key)}, "="))
|
||||||
}
|
}
|
||||||
@ -199,7 +218,7 @@ func (c *clientV1Alpha1) runAirship() error {
|
|||||||
return writeSink(c.resultsDir, parsedOut, c.output)
|
return writeSink(c.resultsDir, parsedOut, c.output)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *clientV1Alpha1) runKRM() error {
|
func (c *V1Alpha1) runKRM() error {
|
||||||
mounts := convertKRMMount(c.conf.Spec.StorageMounts)
|
mounts := convertKRMMount(c.conf.Spec.StorageMounts)
|
||||||
fns := &runfn.RunFns{
|
fns := &runfn.RunFns{
|
||||||
Network: c.conf.Spec.HostNetwork,
|
Network: c.conf.Spec.HostNetwork,
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package container
|
package container_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -29,6 +29,7 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
||||||
|
aircontainer "opendev.org/airship/airshipctl/pkg/container"
|
||||||
"opendev.org/airship/airshipctl/pkg/document"
|
"opendev.org/airship/airshipctl/pkg/document"
|
||||||
"opendev.org/airship/airshipctl/pkg/phase/ifc"
|
"opendev.org/airship/airshipctl/pkg/phase/ifc"
|
||||||
"opendev.org/airship/airshipctl/pkg/util"
|
"opendev.org/airship/airshipctl/pkg/util"
|
||||||
@ -54,7 +55,7 @@ func TestGenericContainer(t *testing.T) {
|
|||||||
|
|
||||||
output io.Writer
|
output io.Writer
|
||||||
containerAPI *v1alpha1.GenericContainer
|
containerAPI *v1alpha1.GenericContainer
|
||||||
execFunc containerFunc
|
execFunc aircontainer.Func
|
||||||
executorConfig ifc.ExecutorConfig
|
executorConfig ifc.ExecutorConfig
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@ -65,7 +66,7 @@ func TestGenericContainer(t *testing.T) {
|
|||||||
Type: "unknown",
|
Type: "unknown",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
execFunc: NewContainer,
|
execFunc: aircontainer.NewContainer,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "error kyaml can't parse config",
|
name: "error kyaml can't parse config",
|
||||||
@ -75,7 +76,7 @@ func TestGenericContainer(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Config: "~:~",
|
Config: "~:~",
|
||||||
},
|
},
|
||||||
execFunc: NewContainer,
|
execFunc: aircontainer.NewContainer,
|
||||||
expectedErr: "wrong Node Kind",
|
expectedErr: "wrong Node Kind",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -93,7 +94,7 @@ func TestGenericContainer(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Config: `kind: ConfigMap`,
|
Config: `kind: ConfigMap`,
|
||||||
},
|
},
|
||||||
execFunc: NewContainer,
|
execFunc: aircontainer.NewContainer,
|
||||||
expectedErr: "no such file or directory",
|
expectedErr: "no such file or directory",
|
||||||
outputPath: "directory doesn't exist",
|
outputPath: "directory doesn't exist",
|
||||||
},
|
},
|
||||||
@ -115,7 +116,7 @@ func TestGenericContainer(t *testing.T) {
|
|||||||
Config: `kind: ConfigMap`,
|
Config: `kind: ConfigMap`,
|
||||||
},
|
},
|
||||||
expectedErr: "no such file or directory",
|
expectedErr: "no such file or directory",
|
||||||
execFunc: func(ctx context.Context, driver, url string) (Container, error) {
|
execFunc: func(ctx context.Context, driver, url string) (aircontainer.Container, error) {
|
||||||
return getDockerContainerMock(mockDockerClient{
|
return getDockerContainerMock(mockDockerClient{
|
||||||
containerAttach: func() (types.HijackedResponse, error) {
|
containerAttach: func() (types.HijackedResponse, error) {
|
||||||
conn := types.HijackedResponse{
|
conn := types.HijackedResponse{
|
||||||
@ -158,7 +159,7 @@ func TestGenericContainer(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Config: `kind: ConfigMap`,
|
Config: `kind: ConfigMap`,
|
||||||
},
|
},
|
||||||
execFunc: func(ctx context.Context, driver, url string) (Container, error) {
|
execFunc: func(ctx context.Context, driver, url string) (aircontainer.Container, error) {
|
||||||
return getDockerContainerMock(mockDockerClient{
|
return getDockerContainerMock(mockDockerClient{
|
||||||
containerAttach: func() (types.HijackedResponse, error) {
|
containerAttach: func() (types.HijackedResponse, error) {
|
||||||
conn := types.HijackedResponse{
|
conn := types.HijackedResponse{
|
||||||
@ -203,7 +204,7 @@ func TestGenericContainer(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Config: `kind: ConfigMap`,
|
Config: `kind: ConfigMap`,
|
||||||
},
|
},
|
||||||
execFunc: func(ctx context.Context, driver, url string) (Container, error) {
|
execFunc: func(ctx context.Context, driver, url string) (aircontainer.Container, error) {
|
||||||
return getDockerContainerMock(mockDockerClient{
|
return getDockerContainerMock(mockDockerClient{
|
||||||
containerAttach: func() (types.HijackedResponse, error) {
|
containerAttach: func() (types.HijackedResponse, error) {
|
||||||
conn := types.HijackedResponse{
|
conn := types.HijackedResponse{
|
||||||
@ -240,7 +241,7 @@ func TestGenericContainer(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Config: `kind: ConfigMap`,
|
Config: `kind: ConfigMap`,
|
||||||
},
|
},
|
||||||
execFunc: func(ctx context.Context, driver, url string) (Container, error) {
|
execFunc: func(ctx context.Context, driver, url string) (aircontainer.Container, error) {
|
||||||
return getDockerContainerMock(mockDockerClient{
|
return getDockerContainerMock(mockDockerClient{
|
||||||
containerAttach: func() (types.HijackedResponse, error) {
|
containerAttach: func() (types.HijackedResponse, error) {
|
||||||
conn := types.HijackedResponse{
|
conn := types.HijackedResponse{
|
||||||
@ -266,13 +267,7 @@ func TestGenericContainer(t *testing.T) {
|
|||||||
tt := tt
|
tt := tt
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
input := bundlePathToInput(t, "testdata/single")
|
input := bundlePathToInput(t, "testdata/single")
|
||||||
client := &clientV1Alpha1{
|
client := aircontainer.NewV1Alpha1(tt.outputPath, input, tt.output, tt.containerAPI, "", tt.execFunc)
|
||||||
input: input,
|
|
||||||
resultsDir: tt.outputPath,
|
|
||||||
output: tt.output,
|
|
||||||
conf: tt.containerAPI,
|
|
||||||
containerFunc: tt.execFunc,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := client.Run()
|
err := client.Run()
|
||||||
|
|
||||||
@ -288,7 +283,7 @@ func TestGenericContainer(t *testing.T) {
|
|||||||
|
|
||||||
// Dummy test to keep up with coverage.
|
// Dummy test to keep up with coverage.
|
||||||
func TestNewClientV1alpha1(t *testing.T) {
|
func TestNewClientV1alpha1(t *testing.T) {
|
||||||
client := NewClientV1Alpha1("", nil, nil, v1alpha1.DefaultGenericContainer(), "")
|
client := aircontainer.NewClientV1Alpha1("", nil, nil, v1alpha1.DefaultGenericContainer(), "")
|
||||||
require.NotNil(t, client)
|
require.NotNil(t, client)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,7 +317,7 @@ func TestExpandSourceMounts(t *testing.T) {
|
|||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
tt := tt
|
tt := tt
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
ExpandSourceMounts(tt.inputMounts, tt.targetPath)
|
aircontainer.ExpandSourceMounts(tt.inputMounts, tt.targetPath)
|
||||||
require.Equal(t, tt.expectedMounts, tt.inputMounts)
|
require.Equal(t, tt.expectedMounts, tt.inputMounts)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// ContainerDriverDocker indicates that docker driver should be used in container constructor
|
// DriverDocker indicates that docker driver should be used in container constructor
|
||||||
ContainerDriverDocker = "docker"
|
DriverDocker = "docker"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Status type provides container status
|
// Status type provides container status
|
||||||
@ -86,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 ContainerDriverDocker:
|
case DriverDocker:
|
||||||
cli, err := NewDockerClient(ctx)
|
cli, err := NewDockerClient(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -99,11 +99,11 @@ type DockerClient interface {
|
|||||||
|
|
||||||
// DockerContainer docker container object wrapper
|
// DockerContainer docker container object wrapper
|
||||||
type DockerContainer struct {
|
type DockerContainer struct {
|
||||||
tag string
|
Tag string
|
||||||
imageURL string
|
ImageURL string
|
||||||
id string
|
ID string
|
||||||
dockerClient DockerClient
|
DockerClient DockerClient
|
||||||
ctx context.Context
|
Ctx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDockerClient returns instance of DockerClient.
|
// NewDockerClient returns instance of DockerClient.
|
||||||
@ -131,11 +131,11 @@ func NewDockerContainer(ctx context.Context, url string, cli DockerClient) (*Doc
|
|||||||
}
|
}
|
||||||
|
|
||||||
cnt := &DockerContainer{
|
cnt := &DockerContainer{
|
||||||
tag: t,
|
Tag: t,
|
||||||
imageURL: url,
|
ImageURL: url,
|
||||||
id: "",
|
ID: "",
|
||||||
dockerClient: cli,
|
DockerClient: cli,
|
||||||
ctx: ctx,
|
Ctx: ctx,
|
||||||
}
|
}
|
||||||
if err := cnt.ImagePull(); err != nil {
|
if err := cnt.ImagePull(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -143,7 +143,7 @@ func NewDockerContainer(ctx context.Context, url string, cli DockerClient) (*Doc
|
|||||||
return cnt, nil
|
return cnt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getCmd identifies container command. Accepts list of strings each element
|
// GetCmd identifies container command. Accepts list of strings each element
|
||||||
// represents command part (e.g "sample cmd --key" should be transformed to
|
// represents command part (e.g "sample cmd --key" should be transformed to
|
||||||
// []string{"sample", "command", "--key"})
|
// []string{"sample", "command", "--key"})
|
||||||
//
|
//
|
||||||
@ -153,17 +153,17 @@ func NewDockerContainer(ctx context.Context, url string, cli DockerClient) (*Doc
|
|||||||
// If input parameter is empty list method identifies container image and
|
// If input parameter is empty list method identifies container image and
|
||||||
// tries to extract Cmd option from this image description (i.e. tries to
|
// tries to extract Cmd option from this image description (i.e. tries to
|
||||||
// identify default command specified in Dockerfile)
|
// identify default command specified in Dockerfile)
|
||||||
func (c *DockerContainer) getCmd(cmd []string) ([]string, error) {
|
func (c *DockerContainer) GetCmd(cmd []string) ([]string, error) {
|
||||||
if len(cmd) > 0 {
|
if len(cmd) > 0 {
|
||||||
return cmd, nil
|
return cmd, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
id, err := c.getImageID(c.imageURL)
|
id, err := c.GetImageID(c.ImageURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
insp, _, err := c.dockerClient.ImageInspectWithRaw(c.ctx, id)
|
insp, _, err := c.DockerClient.ImageInspectWithRaw(c.Ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -173,12 +173,12 @@ func (c *DockerContainer) getCmd(cmd []string) ([]string, error) {
|
|||||||
|
|
||||||
// getConfig creates configuration structures for Docker API client.
|
// getConfig creates configuration structures for Docker API client.
|
||||||
func (c *DockerContainer) getConfig(opts RunCommandOptions) (container.Config, container.HostConfig, error) {
|
func (c *DockerContainer) getConfig(opts RunCommandOptions) (container.Config, container.HostConfig, error) {
|
||||||
cmd, err := c.getCmd(opts.Cmd)
|
cmd, err := c.GetCmd(opts.Cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return container.Config{}, container.HostConfig{}, err
|
return container.Config{}, container.HostConfig{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
mounts := []mount.Mount{}
|
mounts := make([]mount.Mount, 0)
|
||||||
for _, mnt := range opts.Mounts {
|
for _, mnt := range opts.Mounts {
|
||||||
mounts = append(mounts, mount.Mount{
|
mounts = append(mounts, mount.Mount{
|
||||||
Type: mount.Type(mnt.Type),
|
Type: mount.Type(mnt.Type),
|
||||||
@ -189,7 +189,7 @@ func (c *DockerContainer) getConfig(opts RunCommandOptions) (container.Config, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
cCfg := container.Config{
|
cCfg := container.Config{
|
||||||
Image: c.imageURL,
|
Image: c.ImageURL,
|
||||||
Cmd: cmd,
|
Cmd: cmd,
|
||||||
|
|
||||||
AttachStdin: true,
|
AttachStdin: true,
|
||||||
@ -210,9 +210,9 @@ func (c *DockerContainer) getConfig(opts RunCommandOptions) (container.Config, c
|
|||||||
return cCfg, hCfg, nil
|
return cCfg, hCfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getImageID return ID of container image specified by URL. Method executes
|
// GetImageID return ID of container image specified by URL. Method executes
|
||||||
// ImageList function supplied with "reference" filter
|
// ImageList function supplied with "reference" filter
|
||||||
func (c *DockerContainer) getImageID(url string) (string, error) {
|
func (c *DockerContainer) GetImageID(url string) (string, error) {
|
||||||
kv := filters.KeyValuePair{
|
kv := filters.KeyValuePair{
|
||||||
Key: "reference",
|
Key: "reference",
|
||||||
Value: url,
|
Value: url,
|
||||||
@ -222,7 +222,7 @@ func (c *DockerContainer) getImageID(url string) (string, error) {
|
|||||||
All: false,
|
All: false,
|
||||||
Filters: filter,
|
Filters: filter,
|
||||||
}
|
}
|
||||||
img, err := c.dockerClient.ImageList(c.ctx, opts)
|
img, err := c.DockerClient.ImageList(c.Ctx, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -236,7 +236,7 @@ func (c *DockerContainer) getImageID(url string) (string, error) {
|
|||||||
|
|
||||||
// GetID returns ID of the container
|
// GetID returns ID of the container
|
||||||
func (c *DockerContainer) GetID() string {
|
func (c *DockerContainer) GetID() string {
|
||||||
return c.id
|
return c.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImagePull downloads image for container
|
// ImagePull downloads image for container
|
||||||
@ -244,12 +244,12 @@ func (c *DockerContainer) ImagePull() error {
|
|||||||
// skip image download if already downloaded
|
// skip image download if already downloaded
|
||||||
// ImageInspectWithRaw returns err when image not found local and
|
// ImageInspectWithRaw returns err when image not found local and
|
||||||
// in this case it will proceed for ImagePull.
|
// in this case it will proceed for ImagePull.
|
||||||
_, _, err := c.dockerClient.ImageInspectWithRaw(c.ctx, c.imageURL)
|
_, _, err := c.DockerClient.ImageInspectWithRaw(c.Ctx, c.ImageURL)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
log.Debug("Image Already exists, skip download")
|
log.Debug("Image Already exists, skip download")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
resp, err := c.dockerClient.ImagePull(c.ctx, c.imageURL, types.ImagePullOptions{})
|
resp, err := c.DockerClient.ImagePull(c.Ctx, c.ImageURL, types.ImagePullOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -268,8 +268,8 @@ func (c *DockerContainer) RunCommand(opts RunCommandOptions) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
resp, err := c.dockerClient.ContainerCreate(
|
resp, err := c.DockerClient.ContainerCreate(
|
||||||
c.ctx,
|
c.Ctx,
|
||||||
&containerConfig,
|
&containerConfig,
|
||||||
&hostConfig,
|
&hostConfig,
|
||||||
nil,
|
nil,
|
||||||
@ -280,10 +280,10 @@ func (c *DockerContainer) RunCommand(opts RunCommandOptions) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.id = resp.ID
|
c.ID = resp.ID
|
||||||
|
|
||||||
if opts.Input != nil {
|
if opts.Input != nil {
|
||||||
conn, attachErr := c.dockerClient.ContainerAttach(c.ctx, c.id, types.ContainerAttachOptions{
|
conn, attachErr := c.DockerClient.ContainerAttach(c.Ctx, c.ID, types.ContainerAttachOptions{
|
||||||
Stream: true,
|
Stream: true,
|
||||||
Stdin: true,
|
Stdin: true,
|
||||||
})
|
})
|
||||||
@ -294,7 +294,7 @@ func (c *DockerContainer) RunCommand(opts RunCommandOptions) (err error) {
|
|||||||
|
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
// This code is smiplified version of docker cli code
|
// This code is simplified version of docker cli code
|
||||||
cErr := make(chan error, 1)
|
cErr := make(chan error, 1)
|
||||||
|
|
||||||
// Write to stdin asynchronously
|
// Write to stdin asynchronously
|
||||||
@ -303,7 +303,7 @@ func (c *DockerContainer) RunCommand(opts RunCommandOptions) (err error) {
|
|||||||
cErr <- copyErr
|
cErr <- copyErr
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if err = c.dockerClient.ContainerStart(c.ctx, c.id, types.ContainerStartOptions{}); err != nil {
|
if err = c.DockerClient.ContainerStart(c.Ctx, c.ID, types.ContainerStartOptions{}); err != nil {
|
||||||
<-cErr
|
<-cErr
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -311,7 +311,7 @@ func (c *DockerContainer) RunCommand(opts RunCommandOptions) (err error) {
|
|||||||
return <-cErr
|
return <-cErr
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = c.dockerClient.ContainerStart(c.ctx, c.id, types.ContainerStartOptions{}); err != nil {
|
if err = c.DockerClient.ContainerStart(c.Ctx, c.ID, types.ContainerStartOptions{}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,7 +321,7 @@ 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(opts GetLogOptions) (io.ReadCloser, error) {
|
func (c *DockerContainer) GetContainerLogs(opts GetLogOptions) (io.ReadCloser, error) {
|
||||||
return c.dockerClient.ContainerLogs(c.ctx, c.id, types.ContainerLogsOptions{
|
return c.DockerClient.ContainerLogs(c.Ctx, c.ID, types.ContainerLogsOptions{
|
||||||
ShowStderr: opts.Stderr,
|
ShowStderr: opts.Stderr,
|
||||||
Follow: opts.Follow,
|
Follow: opts.Follow,
|
||||||
ShowStdout: opts.Stdout,
|
ShowStdout: opts.Stdout,
|
||||||
@ -330,9 +330,9 @@ func (c *DockerContainer) GetContainerLogs(opts GetLogOptions) (io.ReadCloser, e
|
|||||||
|
|
||||||
// RmContainer kills and removes a container from the docker host.
|
// RmContainer kills and removes a container from the docker host.
|
||||||
func (c *DockerContainer) RmContainer() error {
|
func (c *DockerContainer) RmContainer() error {
|
||||||
return c.dockerClient.ContainerRemove(
|
return c.DockerClient.ContainerRemove(
|
||||||
c.ctx,
|
c.Ctx,
|
||||||
c.id,
|
c.ID,
|
||||||
types.ContainerRemoveOptions{
|
types.ContainerRemoveOptions{
|
||||||
Force: true,
|
Force: true,
|
||||||
},
|
},
|
||||||
@ -341,7 +341,7 @@ func (c *DockerContainer) RmContainer() error {
|
|||||||
|
|
||||||
// InspectContainer inspect the running container
|
// InspectContainer inspect the running container
|
||||||
func (c *DockerContainer) InspectContainer() (State, error) {
|
func (c *DockerContainer) InspectContainer() (State, error) {
|
||||||
json, err := c.dockerClient.ContainerInspect(context.Background(), c.id)
|
json, err := c.DockerClient.ContainerInspect(context.Background(), c.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to inspect container status")
|
log.Debug("Failed to inspect container status")
|
||||||
return State{}, err
|
return State{}, err
|
||||||
@ -356,7 +356,7 @@ func (c *DockerContainer) InspectContainer() (State, error) {
|
|||||||
|
|
||||||
// WaitUntilFinished waits unit container command is finished, return an error if failed
|
// WaitUntilFinished waits unit container command is finished, return an error if failed
|
||||||
func (c *DockerContainer) WaitUntilFinished() error {
|
func (c *DockerContainer) WaitUntilFinished() error {
|
||||||
statusCh, errCh := c.dockerClient.ContainerWait(c.ctx, c.id, container.WaitConditionNotRunning)
|
statusCh, errCh := c.DockerClient.ContainerWait(c.Ctx, c.ID, container.WaitConditionNotRunning)
|
||||||
log.Debugf("waiting until command is finished...")
|
log.Debugf("waiting until command is finished...")
|
||||||
select {
|
select {
|
||||||
case err := <-errCh:
|
case err := <-errCh:
|
||||||
@ -365,7 +365,7 @@ func (c *DockerContainer) WaitUntilFinished() error {
|
|||||||
}
|
}
|
||||||
case retCode := <-statusCh:
|
case retCode := <-statusCh:
|
||||||
if retCode.StatusCode != 0 {
|
if retCode.StatusCode != 0 {
|
||||||
logsCmd := fmt.Sprintf("docker logs %s", c.id)
|
logsCmd := fmt.Sprintf("docker logs %s", c.ID)
|
||||||
return ErrRunContainerCommand{Cmd: logsCmd}
|
return ErrRunContainerCommand{Cmd: logsCmd}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package container
|
package container_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -25,13 +25,14 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"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/network"
|
"github.com/docker/docker/api/types/network"
|
||||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
aircontainer "opendev.org/airship/airshipctl/pkg/container"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mockConn struct {
|
type mockConn struct {
|
||||||
@ -130,11 +131,11 @@ func (mdc *mockDockerClient) ContainerInspect(context.Context, string) (types.Co
|
|||||||
return types.ContainerJSON{}, nil
|
return types.ContainerJSON{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDockerContainerMock(mdc mockDockerClient) *DockerContainer {
|
func getDockerContainerMock(mdc mockDockerClient) *aircontainer.DockerContainer {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
cnt := &DockerContainer{
|
cnt := &aircontainer.DockerContainer{
|
||||||
dockerClient: &mdc,
|
DockerClient: &mdc,
|
||||||
ctx: ctx,
|
Ctx: ctx,
|
||||||
}
|
}
|
||||||
return cnt
|
return cnt
|
||||||
}
|
}
|
||||||
@ -187,7 +188,7 @@ func TestGetCmd(t *testing.T) {
|
|||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
cnt := getDockerContainerMock(tt.mockDockerClient)
|
cnt := getDockerContainerMock(tt.mockDockerClient)
|
||||||
actualRes, actualErr := cnt.getCmd(tt.cmd)
|
actualRes, actualErr := cnt.GetCmd(tt.cmd)
|
||||||
|
|
||||||
assert.Equal(t, tt.expectedErr, actualErr)
|
assert.Equal(t, tt.expectedErr, actualErr)
|
||||||
assert.Equal(t, tt.expectedResult, actualRes)
|
assert.Equal(t, tt.expectedResult, actualRes)
|
||||||
@ -220,12 +221,12 @@ func TestGetImageId(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedResult: "",
|
expectedResult: "",
|
||||||
expectedErr: ErrEmptyImageList{},
|
expectedErr: aircontainer.ErrEmptyImageList{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
cnt := getDockerContainerMock(tt.mockDockerClient)
|
cnt := getDockerContainerMock(tt.mockDockerClient)
|
||||||
actualRes, actualErr := cnt.getImageID(tt.url)
|
actualRes, actualErr := cnt.GetImageID(tt.url)
|
||||||
|
|
||||||
assert.Equal(t, tt.expectedErr, actualErr)
|
assert.Equal(t, tt.expectedErr, actualErr)
|
||||||
assert.Equal(t, tt.expectedResult, actualRes)
|
assert.Equal(t, tt.expectedResult, actualRes)
|
||||||
@ -271,7 +272,7 @@ func TestImagePull(t *testing.T) {
|
|||||||
|
|
||||||
func TestGetId(t *testing.T) {
|
func TestGetId(t *testing.T) {
|
||||||
cnt := getDockerContainerMock(mockDockerClient{})
|
cnt := getDockerContainerMock(mockDockerClient{})
|
||||||
err := cnt.RunCommand(RunCommandOptions{
|
err := cnt.RunCommand(aircontainer.RunCommandOptions{
|
||||||
Cmd: []string{"testCmd"},
|
Cmd: []string{"testCmd"},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -289,7 +290,7 @@ func TestRunCommand(t *testing.T) {
|
|||||||
cmd []string
|
cmd []string
|
||||||
containerInput io.Reader
|
containerInput io.Reader
|
||||||
volumeMounts []string
|
volumeMounts []string
|
||||||
mounts []Mount
|
mounts []aircontainer.Mount
|
||||||
debug bool
|
debug bool
|
||||||
mockDockerClient mockDockerClient
|
mockDockerClient mockDockerClient
|
||||||
expectedRunErr error
|
expectedRunErr error
|
||||||
@ -334,7 +335,7 @@ func TestRunCommand(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedRunErr: nil,
|
expectedRunErr: nil,
|
||||||
mounts: []Mount{
|
mounts: []aircontainer.Mount{
|
||||||
{
|
{
|
||||||
ReadOnly: true,
|
ReadOnly: true,
|
||||||
Type: "bind",
|
Type: "bind",
|
||||||
@ -434,7 +435,7 @@ func TestRunCommand(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedRunErr: nil,
|
expectedRunErr: nil,
|
||||||
expectedWaitErr: ErrRunContainerCommand{Cmd: "docker logs testID"},
|
expectedWaitErr: aircontainer.ErrRunContainerCommand{Cmd: "docker logs testID"},
|
||||||
assertF: func(t *testing.T) {},
|
assertF: func(t *testing.T) {},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -455,13 +456,13 @@ func TestRunCommand(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedRunErr: nil,
|
expectedRunErr: nil,
|
||||||
expectedWaitErr: ErrRunContainerCommand{Cmd: "docker logs testID"},
|
expectedWaitErr: aircontainer.ErrRunContainerCommand{Cmd: "docker logs testID"},
|
||||||
assertF: func(t *testing.T) {},
|
assertF: func(t *testing.T) {},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
cnt := getDockerContainerMock(tt.mockDockerClient)
|
cnt := getDockerContainerMock(tt.mockDockerClient)
|
||||||
actualErr := cnt.RunCommand(RunCommandOptions{
|
actualErr := cnt.RunCommand(aircontainer.RunCommandOptions{
|
||||||
Input: tt.containerInput,
|
Input: tt.containerInput,
|
||||||
Cmd: tt.cmd,
|
Cmd: tt.cmd,
|
||||||
Binds: tt.volumeMounts,
|
Binds: tt.volumeMounts,
|
||||||
@ -508,13 +509,13 @@ func TestRunCommandOutput(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
cnt := getDockerContainerMock(tt.mockDockerClient)
|
cnt := getDockerContainerMock(tt.mockDockerClient)
|
||||||
actualErr := cnt.RunCommand(RunCommandOptions{
|
actualErr := cnt.RunCommand(aircontainer.RunCommandOptions{
|
||||||
Input: tt.containerInput,
|
Input: tt.containerInput,
|
||||||
Cmd: tt.cmd,
|
Cmd: tt.cmd,
|
||||||
Binds: tt.volumeMounts,
|
Binds: tt.volumeMounts,
|
||||||
})
|
})
|
||||||
assert.Equal(t, tt.expectedErr, actualErr)
|
assert.Equal(t, tt.expectedErr, actualErr)
|
||||||
actualRes, actualErr := cnt.GetContainerLogs(GetLogOptions{Stdout: true, Follow: true})
|
actualRes, actualErr := cnt.GetContainerLogs(aircontainer.GetLogOptions{Stdout: true, Follow: true})
|
||||||
require.NoError(t, actualErr)
|
require.NoError(t, actualErr)
|
||||||
|
|
||||||
var actualResBytes []byte
|
var actualResBytes []byte
|
||||||
@ -579,7 +580,7 @@ func TestNewDockerContainer(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
actualRes, actualErr := NewDockerContainer((tt.ctx), tt.url, &(tt.cli))
|
actualRes, actualErr := aircontainer.NewDockerContainer(tt.ctx, tt.url, &(tt.cli))
|
||||||
|
|
||||||
assert.Equal(t, tt.expectedErr, actualErr)
|
assert.Equal(t, tt.expectedErr, actualErr)
|
||||||
|
|
||||||
@ -588,9 +589,9 @@ func TestNewDockerContainer(t *testing.T) {
|
|||||||
actualResStruct = resultStruct{}
|
actualResStruct = resultStruct{}
|
||||||
} else {
|
} else {
|
||||||
actualResStruct = resultStruct{
|
actualResStruct = resultStruct{
|
||||||
tag: actualRes.tag,
|
tag: actualRes.Tag,
|
||||||
imageURL: actualRes.imageURL,
|
imageURL: actualRes.ImageURL,
|
||||||
id: actualRes.id,
|
id: actualRes.ID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert.Equal(t, tt.expectedResult, actualResStruct)
|
assert.Equal(t, tt.expectedResult, actualResStruct)
|
||||||
@ -618,7 +619,7 @@ func TestRmContainer(t *testing.T) {
|
|||||||
func TestInspectContainer(t *testing.T) {
|
func TestInspectContainer(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
cli mockDockerClient
|
cli mockDockerClient
|
||||||
expectedState State
|
expectedState aircontainer.State
|
||||||
expectedErr error
|
expectedErr error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@ -630,13 +631,13 @@ func TestInspectContainer(t *testing.T) {
|
|||||||
json.ContainerJSONBase = &types.ContainerJSONBase{}
|
json.ContainerJSONBase = &types.ContainerJSONBase{}
|
||||||
json.ContainerJSONBase.State = &types.ContainerState{}
|
json.ContainerJSONBase.State = &types.ContainerState{}
|
||||||
json.ContainerJSONBase.State.ExitCode = 0
|
json.ContainerJSONBase.State.ExitCode = 0
|
||||||
json.ContainerJSONBase.State.Status = CreatedContainerStatus
|
json.ContainerJSONBase.State.Status = aircontainer.CreatedContainerStatus
|
||||||
return json, nil
|
return json, nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedState: State{
|
expectedState: aircontainer.State{
|
||||||
ExitCode: 0,
|
ExitCode: 0,
|
||||||
Status: CreatedContainerStatus,
|
Status: aircontainer.CreatedContainerStatus,
|
||||||
},
|
},
|
||||||
expectedErr: nil,
|
expectedErr: nil,
|
||||||
},
|
},
|
||||||
@ -649,13 +650,13 @@ func TestInspectContainer(t *testing.T) {
|
|||||||
json.ContainerJSONBase = &types.ContainerJSONBase{}
|
json.ContainerJSONBase = &types.ContainerJSONBase{}
|
||||||
json.ContainerJSONBase.State = &types.ContainerState{}
|
json.ContainerJSONBase.State = &types.ContainerState{}
|
||||||
json.ContainerJSONBase.State.ExitCode = 0
|
json.ContainerJSONBase.State.ExitCode = 0
|
||||||
json.ContainerJSONBase.State.Status = RunningContainerStatus
|
json.ContainerJSONBase.State.Status = aircontainer.RunningContainerStatus
|
||||||
return json, nil
|
return json, nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedState: State{
|
expectedState: aircontainer.State{
|
||||||
ExitCode: 0,
|
ExitCode: 0,
|
||||||
Status: RunningContainerStatus,
|
Status: aircontainer.RunningContainerStatus,
|
||||||
},
|
},
|
||||||
expectedErr: nil,
|
expectedErr: nil,
|
||||||
},
|
},
|
||||||
@ -668,13 +669,13 @@ func TestInspectContainer(t *testing.T) {
|
|||||||
json.ContainerJSONBase = &types.ContainerJSONBase{}
|
json.ContainerJSONBase = &types.ContainerJSONBase{}
|
||||||
json.ContainerJSONBase.State = &types.ContainerState{}
|
json.ContainerJSONBase.State = &types.ContainerState{}
|
||||||
json.ContainerJSONBase.State.ExitCode = 0
|
json.ContainerJSONBase.State.ExitCode = 0
|
||||||
json.ContainerJSONBase.State.Status = ExitedContainerStatus
|
json.ContainerJSONBase.State.Status = aircontainer.ExitedContainerStatus
|
||||||
return json, nil
|
return json, nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedState: State{
|
expectedState: aircontainer.State{
|
||||||
ExitCode: 0,
|
ExitCode: 0,
|
||||||
Status: ExitedContainerStatus,
|
Status: aircontainer.ExitedContainerStatus,
|
||||||
},
|
},
|
||||||
expectedErr: nil,
|
expectedErr: nil,
|
||||||
},
|
},
|
||||||
@ -687,13 +688,13 @@ func TestInspectContainer(t *testing.T) {
|
|||||||
json.ContainerJSONBase = &types.ContainerJSONBase{}
|
json.ContainerJSONBase = &types.ContainerJSONBase{}
|
||||||
json.ContainerJSONBase.State = &types.ContainerState{}
|
json.ContainerJSONBase.State = &types.ContainerState{}
|
||||||
json.ContainerJSONBase.State.ExitCode = 1
|
json.ContainerJSONBase.State.ExitCode = 1
|
||||||
json.ContainerJSONBase.State.Status = ExitedContainerStatus
|
json.ContainerJSONBase.State.Status = aircontainer.ExitedContainerStatus
|
||||||
return json, nil
|
return json, nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedState: State{
|
expectedState: aircontainer.State{
|
||||||
ExitCode: 1,
|
ExitCode: 1,
|
||||||
Status: ExitedContainerStatus,
|
Status: aircontainer.ExitedContainerStatus,
|
||||||
},
|
},
|
||||||
expectedErr: nil,
|
expectedErr: nil,
|
||||||
},
|
},
|
||||||
|
@ -12,29 +12,31 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package container
|
package container_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"opendev.org/airship/airshipctl/pkg/container"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewContainer(t *testing.T) {
|
func TestNewContainer(t *testing.T) {
|
||||||
assert := assert.New(t)
|
a := assert.New(t)
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
t.Run("not-supported-container", func(t *testing.T) {
|
t.Run("not-supported-container", func(t *testing.T) {
|
||||||
cnt, err := NewContainer(ctx, "test_drv", "")
|
cnt, err := container.NewContainer(ctx, "test_drv", "")
|
||||||
assert.Equal(nil, cnt)
|
a.Equal(nil, cnt)
|
||||||
assert.Equal(ErrContainerDrvNotSupported{Driver: "test_drv"}, err)
|
a.Equal(container.ErrContainerDrvNotSupported{Driver: "test_drv"}, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("empty-container", func(t *testing.T) {
|
t.Run("empty-container", func(t *testing.T) {
|
||||||
cnt, err := NewContainer(ctx, "", "")
|
cnt, err := container.NewContainer(ctx, "", "")
|
||||||
assert.Equal(nil, cnt)
|
a.Equal(nil, cnt)
|
||||||
assert.Equal(ErrNoContainerDriver{}, err)
|
a.Equal(container.ErrNoContainerDriver{}, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user