Browse code

Fix multiple copy from

Signed-off-by: Daniel Nephin <dnephin@docker.com>

Daniel Nephin authored on 2017/07/12 06:17:38
Showing 3 changed files
... ...
@@ -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 {