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

bugfix: missing merge some config from image #2156

Merged
merged 1 commit into from
Aug 27, 2018
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
27 changes: 15 additions & 12 deletions daemon/mgr/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,21 @@ func (mgr *ContainerManager) Create(ctx context.Context, name string, config *ty
HostConfig: config.HostConfig,
}

// merge image's config into container
if err := container.merge(func() (ocispec.ImageConfig, error) {
img, err := mgr.Client.GetImage(ctx, config.Image)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no error check?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should ask the one wrote for it, seems like a bug.

if err != nil {
return ocispec.ImageConfig{}, err
}
ociImage, err := containerdImageToOciImage(ctx, img)
if err != nil {
return ocispec.ImageConfig{}, err
}
return ociImage.Config, nil
}); err != nil {
return nil, err
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

put merge funtion before initContainerStorage, make mount points generate completely.

// set container basefs, basefs is not created in pouchd, it will created
// after create options passed to containerd.
mgr.setBaseFS(ctx, container, id)
Expand Down Expand Up @@ -382,18 +397,6 @@ func (mgr *ContainerManager) Create(ctx context.Context, name string, config *ty
return nil, err
}

// merge image's config into container
if err := container.merge(func() (ocispec.ImageConfig, error) {
img, err := mgr.Client.GetImage(ctx, config.Image)
ociImage, err := containerdImageToOciImage(ctx, img)
if err != nil {
return ocispec.ImageConfig{}, err
}
return ociImage.Config, nil
}); err != nil {
return nil, err
}

// Get snapshot UpperDir
mounts, err := mgr.Client.GetMounts(ctx, id)
if err != nil {
Expand Down
57 changes: 52 additions & 5 deletions daemon/mgr/container_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ func (c *Container) StopTimeout() int64 {
func (c *Container) merge(getconfig func() (v1.ImageConfig, error)) error {
c.Lock()
defer c.Unlock()
config, err := getconfig()
imageConf, err := getconfig()
if err != nil {
return err
}
Expand All @@ -294,19 +294,66 @@ func (c *Container) merge(getconfig func() (v1.ImageConfig, error)) error {
// Otherwise use the image's configuration to fill it.
if len(c.Config.Entrypoint) == 0 {
if len(c.Config.Cmd) == 0 {
c.Config.Cmd = config.Cmd
c.Config.Cmd = imageConf.Cmd
}
c.Config.Entrypoint = config.Entrypoint
c.Config.Entrypoint = imageConf.Entrypoint
}

// ContainerConfig.Env is new, and the ImageConfig.Env is old
newEnvSlice, err := mergeEnvSlice(c.Config.Env, config.Env)
newEnvSlice, err := mergeEnvSlice(c.Config.Env, imageConf.Env)
if err != nil {
return err
}
c.Config.Env = newEnvSlice
if c.Config.WorkingDir == "" {
c.Config.WorkingDir = config.WorkingDir
c.Config.WorkingDir = imageConf.WorkingDir
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing volumes here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update and add.

// merge user from image image config.
if c.Config.User == "" {
c.Config.User = imageConf.User
}

// merge stop signal from image config.
if c.Config.StopSignal == "" {
c.Config.StopSignal = imageConf.StopSignal
}

// merge label from image image config, if same label key exist,
// use container config.
if imageConf.Labels != nil {
if c.Config.Labels == nil {
c.Config.Labels = make(map[string]string)
}
for k, v := range c.Config.Labels {
imageConf.Labels[k] = v
}
c.Config.Labels = imageConf.Labels
}

// merge exposed ports from image config, if same label key exist,
// use container config.
if len(imageConf.ExposedPorts) > 0 {
if c.Config.ExposedPorts == nil {
c.Config.ExposedPorts = make(map[string]interface{})
}
for k, v := range imageConf.ExposedPorts {
if _, exist := c.Config.ExposedPorts[k]; !exist {
c.Config.ExposedPorts[k] = interface{}(v)
}
}
}

// merge volumes from image config.
if len(imageConf.Volumes) > 0 {
if c.Config.Volumes == nil {
c.Config.Volumes = make(map[string]interface{})
}
for k, v := range imageConf.Volumes {
if _, exist := c.Config.Volumes[k]; !exist {
c.Config.Volumes[k] = interface{}(v)
}
}
}

return nil
Expand Down
174 changes: 174 additions & 0 deletions daemon/mgr/container_types_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package mgr

import (
"fmt"
"reflect"
"sort"
"testing"
"time"

"github.com/alibaba/pouch/apis/types"
"github.com/alibaba/pouch/pkg/utils"
"github.com/opencontainers/image-spec/specs-go/v1"

"github.com/stretchr/testify/assert"
)
Expand Down Expand Up @@ -82,3 +86,173 @@ func TestContainer_FormatStatus(t *testing.T) {
assert.Equal(t, err, tc.err, tc.name)
}
}

func TestMerge(t *testing.T) {
assert := assert.New(t)

type TPort struct {
p int
}

type TVolume struct {
v int
}

for idx, tc := range []struct {
c *Container
image v1.ImageConfig
expected *types.ContainerConfig
}{
{
// test merge from image when both config is not empty
c: &Container{
Config: &types.ContainerConfig{
Cmd: []string{"a"},
Entrypoint: []string{"b"},
Env: []string{"e1=e1", "e2=e2"},
User: "user1",
StopSignal: "1",
Labels: map[string]string{
"l1": "l2",
"l3": "l4",
},
ExposedPorts: map[string]interface{}{
"e1": interface{}(TPort{
p: 1,
}),
"e2": interface{}(TPort{
p: 2,
}),
},
Volumes: map[string]interface{}{
"v1": interface{}(TVolume{
v: 1,
}),
"v2": interface{}(TVolume{
v: 2,
}),
},
},
},
image: v1.ImageConfig{
Cmd: []string{"ia"},
Entrypoint: []string{"ib"},
Env: []string{"e1=e1", "ie2=ie2"},
User: "iuser1",
StopSignal: "2",
Labels: map[string]string{
"il1": "l2",
"il3": "l4",
},
ExposedPorts: map[string]struct{}{
"ie1": {},
"e2": {},
},
Volumes: map[string]struct{}{
"iv1": {},
"iv2": {},
},
},
expected: &types.ContainerConfig{
Cmd: []string{"a"},
Entrypoint: []string{"b"},
Env: []string{"e1=e1", "e2=e2", "ie2=ie2"},
User: "user1",
StopSignal: "1",
Labels: map[string]string{
"l3": "l4",
"il1": "l2",
"l1": "l2",
"il3": "l4",
},
ExposedPorts: map[string]interface{}{
"e1": interface{}(TPort{
p: 1,
}),
"e2": interface{}(TPort{
p: 2,
}),
"ie1": struct{}{},
},
Volumes: map[string]interface{}{
"v1": interface{}(TVolume{
v: 1,
}),
"v2": interface{}(TVolume{
v: 2,
}),
"iv1": struct{}{},
"iv2": struct{}{},
},
},
},
{
// test merge image config, when image config is empty
c: &Container{
Config: &types.ContainerConfig{
Cmd: []string{"a"},
Entrypoint: []string{"b"},
Env: []string{"e1=e1", "e2=e2"},
User: "user1",
StopSignal: "1",
Labels: map[string]string{
"l1": "l2",
"l3": "l4",
},
},
},
image: v1.ImageConfig{},
expected: &types.ContainerConfig{
Cmd: []string{"a"},
Entrypoint: []string{"b"},
Env: []string{"e1=e1", "e2=e2"},
User: "user1",
StopSignal: "1",
Labels: map[string]string{
"l1": "l2",
"l3": "l4",
},
},
},
{
// test merge image config, when container config is empty
c: &Container{
Config: &types.ContainerConfig{},
},
image: v1.ImageConfig{
Cmd: []string{"ia"},
Entrypoint: []string{"ib"},
Env: []string{"ie1=ie1", "ie2=ie2"},
User: "iuser1",
StopSignal: "1",
Labels: map[string]string{
"il1": "l2",
"il3": "l4",
},
},
expected: &types.ContainerConfig{
Cmd: []string{"ia"},
Entrypoint: []string{"ib"},
Env: []string{"ie1=ie1", "ie2=ie2"},
User: "iuser1",
StopSignal: "1",
Labels: map[string]string{
"il1": "l2",
"il3": "l4",
},
},
},
} {
err := tc.c.merge(func() (v1.ImageConfig, error) {
return tc.image, nil
})
assert.NoError(err)

// sort slice
sort.Strings(tc.c.Config.Env)
sort.Strings(tc.expected.Env)

ret := reflect.DeepEqual(tc.c.Config, tc.expected)
assert.Equal(true, ret, fmt.Sprintf("test %d fails\n %+v should equal with %+v\n", idx, tc.c.Config, tc.expected))
}
}