Skip to content

Commit 10cb5da

Browse files
author
Wei Fu
authored
Merge pull request #2156 from Ace-Tang/merge_image_config
bugfix: missing merge some config from image
2 parents c5a3796 + f12744a commit 10cb5da

File tree

3 files changed

+241
-17
lines changed

3 files changed

+241
-17
lines changed

daemon/mgr/container.go

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,21 @@ func (mgr *ContainerManager) Create(ctx context.Context, name string, config *ty
355355
HostConfig: config.HostConfig,
356356
}
357357

358+
// merge image's config into container
359+
if err := container.merge(func() (ocispec.ImageConfig, error) {
360+
img, err := mgr.Client.GetImage(ctx, config.Image)
361+
if err != nil {
362+
return ocispec.ImageConfig{}, err
363+
}
364+
ociImage, err := containerdImageToOciImage(ctx, img)
365+
if err != nil {
366+
return ocispec.ImageConfig{}, err
367+
}
368+
return ociImage.Config, nil
369+
}); err != nil {
370+
return nil, err
371+
}
372+
358373
// set container basefs, basefs is not created in pouchd, it will created
359374
// after create options passed to containerd.
360375
mgr.setBaseFS(ctx, container, id)
@@ -382,18 +397,6 @@ func (mgr *ContainerManager) Create(ctx context.Context, name string, config *ty
382397
return nil, err
383398
}
384399

385-
// merge image's config into container
386-
if err := container.merge(func() (ocispec.ImageConfig, error) {
387-
img, err := mgr.Client.GetImage(ctx, config.Image)
388-
ociImage, err := containerdImageToOciImage(ctx, img)
389-
if err != nil {
390-
return ocispec.ImageConfig{}, err
391-
}
392-
return ociImage.Config, nil
393-
}); err != nil {
394-
return nil, err
395-
}
396-
397400
// Get snapshot UpperDir
398401
mounts, err := mgr.Client.GetMounts(ctx, id)
399402
if err != nil {

daemon/mgr/container_types.go

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ func (c *Container) StopTimeout() int64 {
285285
func (c *Container) merge(getconfig func() (v1.ImageConfig, error)) error {
286286
c.Lock()
287287
defer c.Unlock()
288-
config, err := getconfig()
288+
imageConf, err := getconfig()
289289
if err != nil {
290290
return err
291291
}
@@ -294,19 +294,66 @@ func (c *Container) merge(getconfig func() (v1.ImageConfig, error)) error {
294294
// Otherwise use the image's configuration to fill it.
295295
if len(c.Config.Entrypoint) == 0 {
296296
if len(c.Config.Cmd) == 0 {
297-
c.Config.Cmd = config.Cmd
297+
c.Config.Cmd = imageConf.Cmd
298298
}
299-
c.Config.Entrypoint = config.Entrypoint
299+
c.Config.Entrypoint = imageConf.Entrypoint
300300
}
301301

302302
// ContainerConfig.Env is new, and the ImageConfig.Env is old
303-
newEnvSlice, err := mergeEnvSlice(c.Config.Env, config.Env)
303+
newEnvSlice, err := mergeEnvSlice(c.Config.Env, imageConf.Env)
304304
if err != nil {
305305
return err
306306
}
307307
c.Config.Env = newEnvSlice
308308
if c.Config.WorkingDir == "" {
309-
c.Config.WorkingDir = config.WorkingDir
309+
c.Config.WorkingDir = imageConf.WorkingDir
310+
}
311+
312+
// merge user from image image config.
313+
if c.Config.User == "" {
314+
c.Config.User = imageConf.User
315+
}
316+
317+
// merge stop signal from image config.
318+
if c.Config.StopSignal == "" {
319+
c.Config.StopSignal = imageConf.StopSignal
320+
}
321+
322+
// merge label from image image config, if same label key exist,
323+
// use container config.
324+
if imageConf.Labels != nil {
325+
if c.Config.Labels == nil {
326+
c.Config.Labels = make(map[string]string)
327+
}
328+
for k, v := range c.Config.Labels {
329+
imageConf.Labels[k] = v
330+
}
331+
c.Config.Labels = imageConf.Labels
332+
}
333+
334+
// merge exposed ports from image config, if same label key exist,
335+
// use container config.
336+
if len(imageConf.ExposedPorts) > 0 {
337+
if c.Config.ExposedPorts == nil {
338+
c.Config.ExposedPorts = make(map[string]interface{})
339+
}
340+
for k, v := range imageConf.ExposedPorts {
341+
if _, exist := c.Config.ExposedPorts[k]; !exist {
342+
c.Config.ExposedPorts[k] = interface{}(v)
343+
}
344+
}
345+
}
346+
347+
// merge volumes from image config.
348+
if len(imageConf.Volumes) > 0 {
349+
if c.Config.Volumes == nil {
350+
c.Config.Volumes = make(map[string]interface{})
351+
}
352+
for k, v := range imageConf.Volumes {
353+
if _, exist := c.Config.Volumes[k]; !exist {
354+
c.Config.Volumes[k] = interface{}(v)
355+
}
356+
}
310357
}
311358

312359
return nil

daemon/mgr/container_types_test.go

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
package mgr
22

33
import (
4+
"fmt"
5+
"reflect"
6+
"sort"
47
"testing"
58
"time"
69

710
"github.com/alibaba/pouch/apis/types"
811
"github.com/alibaba/pouch/pkg/utils"
12+
"github.com/opencontainers/image-spec/specs-go/v1"
913

1014
"github.com/stretchr/testify/assert"
1115
)
@@ -82,3 +86,173 @@ func TestContainer_FormatStatus(t *testing.T) {
8286
assert.Equal(t, err, tc.err, tc.name)
8387
}
8488
}
89+
90+
func TestMerge(t *testing.T) {
91+
assert := assert.New(t)
92+
93+
type TPort struct {
94+
p int
95+
}
96+
97+
type TVolume struct {
98+
v int
99+
}
100+
101+
for idx, tc := range []struct {
102+
c *Container
103+
image v1.ImageConfig
104+
expected *types.ContainerConfig
105+
}{
106+
{
107+
// test merge from image when both config is not empty
108+
c: &Container{
109+
Config: &types.ContainerConfig{
110+
Cmd: []string{"a"},
111+
Entrypoint: []string{"b"},
112+
Env: []string{"e1=e1", "e2=e2"},
113+
User: "user1",
114+
StopSignal: "1",
115+
Labels: map[string]string{
116+
"l1": "l2",
117+
"l3": "l4",
118+
},
119+
ExposedPorts: map[string]interface{}{
120+
"e1": interface{}(TPort{
121+
p: 1,
122+
}),
123+
"e2": interface{}(TPort{
124+
p: 2,
125+
}),
126+
},
127+
Volumes: map[string]interface{}{
128+
"v1": interface{}(TVolume{
129+
v: 1,
130+
}),
131+
"v2": interface{}(TVolume{
132+
v: 2,
133+
}),
134+
},
135+
},
136+
},
137+
image: v1.ImageConfig{
138+
Cmd: []string{"ia"},
139+
Entrypoint: []string{"ib"},
140+
Env: []string{"e1=e1", "ie2=ie2"},
141+
User: "iuser1",
142+
StopSignal: "2",
143+
Labels: map[string]string{
144+
"il1": "l2",
145+
"il3": "l4",
146+
},
147+
ExposedPorts: map[string]struct{}{
148+
"ie1": {},
149+
"e2": {},
150+
},
151+
Volumes: map[string]struct{}{
152+
"iv1": {},
153+
"iv2": {},
154+
},
155+
},
156+
expected: &types.ContainerConfig{
157+
Cmd: []string{"a"},
158+
Entrypoint: []string{"b"},
159+
Env: []string{"e1=e1", "e2=e2", "ie2=ie2"},
160+
User: "user1",
161+
StopSignal: "1",
162+
Labels: map[string]string{
163+
"l3": "l4",
164+
"il1": "l2",
165+
"l1": "l2",
166+
"il3": "l4",
167+
},
168+
ExposedPorts: map[string]interface{}{
169+
"e1": interface{}(TPort{
170+
p: 1,
171+
}),
172+
"e2": interface{}(TPort{
173+
p: 2,
174+
}),
175+
"ie1": struct{}{},
176+
},
177+
Volumes: map[string]interface{}{
178+
"v1": interface{}(TVolume{
179+
v: 1,
180+
}),
181+
"v2": interface{}(TVolume{
182+
v: 2,
183+
}),
184+
"iv1": struct{}{},
185+
"iv2": struct{}{},
186+
},
187+
},
188+
},
189+
{
190+
// test merge image config, when image config is empty
191+
c: &Container{
192+
Config: &types.ContainerConfig{
193+
Cmd: []string{"a"},
194+
Entrypoint: []string{"b"},
195+
Env: []string{"e1=e1", "e2=e2"},
196+
User: "user1",
197+
StopSignal: "1",
198+
Labels: map[string]string{
199+
"l1": "l2",
200+
"l3": "l4",
201+
},
202+
},
203+
},
204+
image: v1.ImageConfig{},
205+
expected: &types.ContainerConfig{
206+
Cmd: []string{"a"},
207+
Entrypoint: []string{"b"},
208+
Env: []string{"e1=e1", "e2=e2"},
209+
User: "user1",
210+
StopSignal: "1",
211+
Labels: map[string]string{
212+
"l1": "l2",
213+
"l3": "l4",
214+
},
215+
},
216+
},
217+
{
218+
// test merge image config, when container config is empty
219+
c: &Container{
220+
Config: &types.ContainerConfig{},
221+
},
222+
image: v1.ImageConfig{
223+
Cmd: []string{"ia"},
224+
Entrypoint: []string{"ib"},
225+
Env: []string{"ie1=ie1", "ie2=ie2"},
226+
User: "iuser1",
227+
StopSignal: "1",
228+
Labels: map[string]string{
229+
"il1": "l2",
230+
"il3": "l4",
231+
},
232+
},
233+
expected: &types.ContainerConfig{
234+
Cmd: []string{"ia"},
235+
Entrypoint: []string{"ib"},
236+
Env: []string{"ie1=ie1", "ie2=ie2"},
237+
User: "iuser1",
238+
StopSignal: "1",
239+
Labels: map[string]string{
240+
"il1": "l2",
241+
"il3": "l4",
242+
},
243+
},
244+
},
245+
} {
246+
err := tc.c.merge(func() (v1.ImageConfig, error) {
247+
return tc.image, nil
248+
})
249+
assert.NoError(err)
250+
251+
// sort slice
252+
sort.Strings(tc.c.Config.Env)
253+
sort.Strings(tc.expected.Env)
254+
255+
ret := reflect.DeepEqual(tc.c.Config, tc.expected)
256+
assert.Equal(true, ret, fmt.Sprintf("test %d fails\n %+v should equal with %+v\n", idx, tc.c.Config, tc.expected))
257+
}
258+
}

0 commit comments

Comments
 (0)