Browse code

daemon/config: fix filter type in BuildKit GC config

For backwards compatibility, the old incorrect object format for
builder.GC.Rule.Filter still works but is deprecated in favor of array of
strings akin to what needs to be passed on the CLI.

Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit fbdd437d295595e88466b33a550a8707b9ebb709)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>

Tibor Vass authored on 2019/09/25 02:53:39
Showing 3 changed files
... ...
@@ -8,6 +8,7 @@ import (
8 8
 	"github.com/containerd/containerd/content/local"
9 9
 	"github.com/containerd/containerd/platforms"
10 10
 	"github.com/docker/docker/api/types"
11
+	"github.com/docker/docker/api/types/filters"
11 12
 	"github.com/docker/docker/builder/builder-next/adapters/containerimage"
12 13
 	"github.com/docker/docker/builder/builder-next/adapters/localinlinecache"
13 14
 	"github.com/docker/docker/builder/builder-next/adapters/snapshot"
... ...
@@ -232,7 +233,7 @@ func getGCPolicy(conf config.BuilderConfig, root string) ([]client.PruneInfo, er
232 232
 				gcPolicy[i], err = toBuildkitPruneInfo(types.BuildCachePruneOptions{
233 233
 					All:         p.All,
234 234
 					KeepStorage: b,
235
-					Filters:     p.Filter,
235
+					Filters:     filters.Args(p.Filter),
236 236
 				})
237 237
 				if err != nil {
238 238
 					return nil, err
... ...
@@ -1,12 +1,38 @@
1 1
 package config
2 2
 
3
-import "github.com/docker/docker/api/types/filters"
3
+import (
4
+	"encoding/json"
5
+	"strings"
6
+
7
+	"github.com/docker/docker/api/types/filters"
8
+)
4 9
 
5 10
 // BuilderGCRule represents a GC rule for buildkit cache
6 11
 type BuilderGCRule struct {
7
-	All         bool         `json:",omitempty"`
8
-	Filter      filters.Args `json:",omitempty"`
9
-	KeepStorage string       `json:",omitempty"`
12
+	All         bool            `json:",omitempty"`
13
+	Filter      BuilderGCFilter `json:",omitempty"`
14
+	KeepStorage string          `json:",omitempty"`
15
+}
16
+
17
+type BuilderGCFilter filters.Args
18
+
19
+func (x *BuilderGCFilter) UnmarshalJSON(data []byte) error {
20
+	var arr []string
21
+	f := filters.NewArgs()
22
+	if err := json.Unmarshal(data, &arr); err != nil {
23
+		// backwards compat for deprecated buggy form
24
+		err := json.Unmarshal(data, &f)
25
+		*x = BuilderGCFilter(f)
26
+		return err
27
+	}
28
+	for _, s := range arr {
29
+		fields := strings.SplitN(s, "=", 2)
30
+		name := strings.ToLower(strings.TrimSpace(fields[0]))
31
+		value := strings.TrimSpace(fields[1])
32
+		f.Add(name, value)
33
+	}
34
+	*x = BuilderGCFilter(f)
35
+	return nil
10 36
 }
11 37
 
12 38
 // BuilderGCConfig contains GC config for a buildkit builder
13 39
new file mode 100644
... ...
@@ -0,0 +1,44 @@
0
+package config
1
+
2
+import (
3
+	"testing"
4
+
5
+	"github.com/docker/docker/api/types/filters"
6
+	"github.com/google/go-cmp/cmp"
7
+	"gotest.tools/assert"
8
+	"gotest.tools/fs"
9
+)
10
+
11
+func TestBuilderGC(t *testing.T) {
12
+	tempFile := fs.NewFile(t, "config", fs.WithContent(`{
13
+  "builder": {
14
+    "gc": {
15
+      "enabled": true,
16
+      "policy": [
17
+        {"keepStorage": "10GB", "filter": ["unused-for=2200h"]},
18
+        {"keepStorage": "50GB", "filter": {"unused-for": {"3300h": true}}},
19
+        {"keepStorage": "100GB", "all": true}
20
+      ]
21
+    }
22
+  }
23
+}`))
24
+	defer tempFile.Remove()
25
+	configFile := tempFile.Path()
26
+
27
+	cfg, err := MergeDaemonConfigurations(&Config{}, nil, configFile)
28
+	assert.NilError(t, err)
29
+	assert.Assert(t, cfg.Builder.GC.Enabled)
30
+	f1 := filters.NewArgs()
31
+	f1.Add("unused-for", "2200h")
32
+	f2 := filters.NewArgs()
33
+	f2.Add("unused-for", "3300h")
34
+	expectedPolicy := []BuilderGCRule{
35
+		{KeepStorage: "10GB", Filter: BuilderGCFilter(f1)},
36
+		{KeepStorage: "50GB", Filter: BuilderGCFilter(f2)}, /* parsed from deprecated form */
37
+		{KeepStorage: "100GB", All: true},
38
+	}
39
+	assert.DeepEqual(t, cfg.Builder.GC.Policy, expectedPolicy, cmp.AllowUnexported(BuilderGCFilter{}))
40
+	// double check to please the skeptics
41
+	assert.Assert(t, filters.Args(cfg.Builder.GC.Policy[0].Filter).UniqueExactMatch("unused-for", "2200h"))
42
+	assert.Assert(t, filters.Args(cfg.Builder.GC.Policy[1].Filter).UniqueExactMatch("unused-for", "3300h"))
43
+}