Signed-off-by: Daniel Nephin <dnephin@docker.com>
Daniel Nephin authored on 2017/07/12 06:17:38... | ... |
@@ -137,10 +137,13 @@ type ChildConfig struct { |
137 | 137 |
// NewChildImage creates a new Image as a child of this image. |
138 | 138 |
func NewChildImage(img *Image, child ChildConfig, platform string) *Image { |
139 | 139 |
isEmptyLayer := layer.IsEmpty(child.DiffID) |
140 |
- rootFS := img.RootFS |
|
141 |
- if rootFS == nil { |
|
140 |
+ var rootFS *RootFS |
|
141 |
+ if img.RootFS != nil { |
|
142 |
+ rootFS = img.RootFS.Clone() |
|
143 |
+ } else { |
|
142 | 144 |
rootFS = NewRootFS() |
143 | 145 |
} |
146 |
+ |
|
144 | 147 |
if !isEmptyLayer { |
145 | 148 |
rootFS.Append(child.DiffID) |
146 | 149 |
} |
... | ... |
@@ -6,6 +6,8 @@ import ( |
6 | 6 |
"strings" |
7 | 7 |
"testing" |
8 | 8 |
|
9 |
+ "github.com/docker/docker/api/types/container" |
|
10 |
+ "github.com/docker/docker/layer" |
|
9 | 11 |
"github.com/stretchr/testify/assert" |
10 | 12 |
"github.com/stretchr/testify/require" |
11 | 13 |
) |
... | ... |
@@ -51,3 +53,38 @@ func TestMarshalKeyOrder(t *testing.T) { |
51 | 51 |
t.Fatal("invalid key order in JSON: ", string(b)) |
52 | 52 |
} |
53 | 53 |
} |
54 |
+ |
|
55 |
+func TestNewChildImageFromImageWithRootFS(t *testing.T) { |
|
56 |
+ rootFS := NewRootFS() |
|
57 |
+ rootFS.Append(layer.DiffID("ba5e")) |
|
58 |
+ parent := &Image{ |
|
59 |
+ RootFS: rootFS, |
|
60 |
+ History: []History{ |
|
61 |
+ NewHistory("a", "c", "r", false), |
|
62 |
+ }, |
|
63 |
+ } |
|
64 |
+ childConfig := ChildConfig{ |
|
65 |
+ DiffID: layer.DiffID("abcdef"), |
|
66 |
+ Author: "author", |
|
67 |
+ Comment: "comment", |
|
68 |
+ ContainerConfig: &container.Config{ |
|
69 |
+ Cmd: []string{"echo", "foo"}, |
|
70 |
+ }, |
|
71 |
+ Config: &container.Config{}, |
|
72 |
+ } |
|
73 |
+ |
|
74 |
+ newImage := NewChildImage(parent, childConfig, "platform") |
|
75 |
+ expectedDiffIDs := []layer.DiffID{layer.DiffID("ba5e"), layer.DiffID("abcdef")} |
|
76 |
+ assert.Equal(t, expectedDiffIDs, newImage.RootFS.DiffIDs) |
|
77 |
+ assert.Equal(t, childConfig.Author, newImage.Author) |
|
78 |
+ assert.Equal(t, childConfig.Config, newImage.Config) |
|
79 |
+ assert.Equal(t, *childConfig.ContainerConfig, newImage.ContainerConfig) |
|
80 |
+ assert.Equal(t, "platform", newImage.OS) |
|
81 |
+ assert.Equal(t, childConfig.Config, newImage.Config) |
|
82 |
+ |
|
83 |
+ assert.Len(t, newImage.History, 2) |
|
84 |
+ assert.Equal(t, childConfig.Comment, newImage.History[1].Comment) |
|
85 |
+ |
|
86 |
+ // RootFS should be copied not mutated |
|
87 |
+ assert.NotEqual(t, parent.RootFS.DiffIDs, newImage.RootFS.DiffIDs) |
|
88 |
+} |
... | ... |
@@ -34,6 +34,14 @@ func (r *RootFS) Append(id layer.DiffID) { |
34 | 34 |
r.DiffIDs = append(r.DiffIDs, id) |
35 | 35 |
} |
36 | 36 |
|
37 |
+// Clone returns a copy of the RootFS |
|
38 |
+func (r *RootFS) Clone() *RootFS { |
|
39 |
+ newRoot := NewRootFS() |
|
40 |
+ newRoot.Type = r.Type |
|
41 |
+ newRoot.DiffIDs = append(r.DiffIDs) |
|
42 |
+ return newRoot |
|
43 |
+} |
|
44 |
+ |
|
37 | 45 |
// ChainID returns the ChainID for the top layer in RootFS. |
38 | 46 |
func (r *RootFS) ChainID() layer.ChainID { |
39 | 47 |
if runtime.GOOS == "windows" && r.Type == typeLayersWithBase { |