Browse code

Merge pull request #48072 from thaJeztah/remove_graphdriver_plugins

daemon/graphdriver: remove support for external graphdriver plugins

Paweł Gronowski authored on 2024/06/28 02:53:32
Showing 13 changed files
... ...
@@ -1154,7 +1154,6 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S
1154 1154
 			GraphDriver:               driverName,
1155 1155
 			GraphDriverOptions:        cfgStore.GraphOptions,
1156 1156
 			IDMapping:                 idMapping,
1157
-			PluginGetter:              d.PluginStore,
1158 1157
 			ExperimentalEnabled:       cfgStore.Experimental,
1159 1158
 		})
1160 1159
 		if err != nil {
... ...
@@ -11,7 +11,6 @@ import (
11 11
 	"github.com/containerd/log"
12 12
 	"github.com/docker/docker/pkg/archive"
13 13
 	"github.com/docker/docker/pkg/idtools"
14
-	"github.com/docker/docker/pkg/plugingetter"
15 14
 	"github.com/pkg/errors"
16 15
 	"github.com/vbatts/tar-split/tar/storage"
17 16
 )
... ...
@@ -158,16 +157,17 @@ func Register(name string, initFunc InitFunc) error {
158 158
 }
159 159
 
160 160
 // GetDriver initializes and returns the registered driver
161
-func GetDriver(name string, pg plugingetter.PluginGetter, config Options) (Driver, error) {
161
+func GetDriver(name string, config Options) (Driver, error) {
162 162
 	if initFunc, exists := drivers[name]; exists {
163 163
 		return initFunc(filepath.Join(config.Root, name), config.DriverOptions, config.IDMap)
164 164
 	}
165
+	log.G(context.TODO()).WithFields(log.Fields{"driver": name, "home-dir": config.Root}).Error("Failed to GetDriver graph")
165 166
 
166
-	pluginDriver, err := lookupPlugin(name, pg, config)
167
-	if err == nil {
168
-		return pluginDriver, nil
167
+	// TODO(thaJeztah): remove in next release.
168
+	if config.ExperimentalEnabled && os.Getenv("DOCKERD_DEPRECATED_GRAPHDRIVER_PLUGINS") != "" {
169
+		return nil, fmt.Errorf("DEPRECATED: Support for experimental graphdriver plugins has been removed. See https://docs.docker.com/go/deprecated/")
169 170
 	}
170
-	log.G(context.TODO()).WithError(err).WithField("driver", name).WithField("home-dir", config.Root).Error("Failed to GetDriver graph")
171
+
171 172
 	return nil, ErrNotSupported
172 173
 }
173 174
 
... ...
@@ -189,14 +189,14 @@ type Options struct {
189 189
 }
190 190
 
191 191
 // New creates the driver and initializes it at the specified root.
192
-func New(name string, pg plugingetter.PluginGetter, config Options) (Driver, error) {
192
+func New(name string, config Options) (Driver, error) {
193 193
 	ctx := context.TODO()
194 194
 	if name != "" {
195 195
 		log.G(ctx).Infof("[graphdriver] trying configured driver: %s", name)
196 196
 		if err := checkRemoved(name); err != nil {
197 197
 			return nil, err
198 198
 		}
199
-		return GetDriver(name, pg, config)
199
+		return GetDriver(name, config)
200 200
 	}
201 201
 
202 202
 	// Guess for prior driver
... ...
@@ -34,7 +34,7 @@ func newDriver(t testing.TB, name string, options []string) *Driver {
34 34
 	assert.NilError(t, err)
35 35
 
36 36
 	assert.NilError(t, os.MkdirAll(root, 0o755))
37
-	d, err := graphdriver.GetDriver(name, nil, graphdriver.Options{DriverOptions: options, Root: root})
37
+	d, err := graphdriver.GetDriver(name, graphdriver.Options{DriverOptions: options, Root: root})
38 38
 	if err != nil {
39 39
 		t.Logf("graphdriver: %v\n", err)
40 40
 		if graphdriver.IsDriverNotSupported(err) {
41 41
deleted file mode 100644
... ...
@@ -1,59 +0,0 @@
1
-package graphdriver // import "github.com/docker/docker/daemon/graphdriver"
2
-
3
-import (
4
-	"fmt"
5
-	"os"
6
-	"path/filepath"
7
-
8
-	"github.com/docker/docker/errdefs"
9
-	"github.com/docker/docker/pkg/plugingetter"
10
-	"github.com/docker/docker/pkg/plugins"
11
-	v2 "github.com/docker/docker/plugin/v2"
12
-	"github.com/pkg/errors"
13
-)
14
-
15
-func lookupPlugin(name string, pg plugingetter.PluginGetter, config Options) (Driver, error) {
16
-	if os.Getenv("DOCKERD_DEPRECATED_GRAPHDRIVER_PLUGINS") == "" {
17
-		return nil, fmt.Errorf("DEPRECATED: Experimental graphdriver plugins are deprecated, and disabled by default. This feature will be removed in the next release. See https://docs.docker.com/go/deprecated/")
18
-	}
19
-	if !config.ExperimentalEnabled {
20
-		return nil, fmt.Errorf("graphdriver plugins are only supported with experimental mode")
21
-	}
22
-	pl, err := pg.Get(name, "GraphDriver", plugingetter.Acquire)
23
-	if err != nil {
24
-		return nil, fmt.Errorf("Error looking up graphdriver plugin %s: %v", name, err)
25
-	}
26
-	return newPluginDriver(name, pl, config)
27
-}
28
-
29
-func newPluginDriver(name string, pl plugingetter.CompatPlugin, config Options) (Driver, error) {
30
-	home := config.Root
31
-	if !pl.IsV1() {
32
-		if p, ok := pl.(*v2.Plugin); ok {
33
-			if p.PluginObj.Config.PropagatedMount != "" {
34
-				home = p.PluginObj.Config.PropagatedMount
35
-			}
36
-		}
37
-	}
38
-
39
-	var proxy *graphDriverProxy
40
-
41
-	switch pt := pl.(type) {
42
-	case plugingetter.PluginWithV1Client:
43
-		proxy = &graphDriverProxy{name, pl, Capabilities{}, pt.Client()}
44
-	case plugingetter.PluginAddr:
45
-		if pt.Protocol() != plugins.ProtocolSchemeHTTPV1 {
46
-			return nil, errors.Errorf("plugin protocol not supported: %s", pt.Protocol())
47
-		}
48
-		addr := pt.Addr()
49
-		client, err := plugins.NewClientWithTimeout(addr.Network()+"://"+addr.String(), nil, pt.Timeout())
50
-		if err != nil {
51
-			return nil, errors.Wrap(err, "error creating plugin client")
52
-		}
53
-		proxy = &graphDriverProxy{name, pl, Capabilities{}, client}
54
-	default:
55
-		return nil, errdefs.System(errors.Errorf("got unknown plugin type %T", pt))
56
-	}
57
-
58
-	return proxy, proxy.Init(filepath.Join(home, name), config.DriverOptions, config.IDMap)
59
-}
60 1
deleted file mode 100644
... ...
@@ -1,261 +0,0 @@
1
-package graphdriver // import "github.com/docker/docker/daemon/graphdriver"
2
-
3
-import (
4
-	"errors"
5
-	"fmt"
6
-	"io"
7
-
8
-	"github.com/docker/docker/pkg/archive"
9
-	"github.com/docker/docker/pkg/idtools"
10
-	"github.com/docker/docker/pkg/plugingetter"
11
-	"github.com/docker/docker/pkg/plugins"
12
-)
13
-
14
-type graphDriverProxy struct {
15
-	name   string
16
-	p      plugingetter.CompatPlugin
17
-	caps   Capabilities
18
-	client *plugins.Client
19
-}
20
-
21
-type graphDriverRequest struct {
22
-	ID         string            `json:",omitempty"`
23
-	Parent     string            `json:",omitempty"`
24
-	MountLabel string            `json:",omitempty"`
25
-	StorageOpt map[string]string `json:",omitempty"`
26
-}
27
-
28
-type graphDriverResponse struct {
29
-	Err          string            `json:",omitempty"`
30
-	Dir          string            `json:",omitempty"`
31
-	Exists       bool              `json:",omitempty"`
32
-	Status       [][2]string       `json:",omitempty"`
33
-	Changes      []archive.Change  `json:",omitempty"`
34
-	Size         int64             `json:",omitempty"`
35
-	Metadata     map[string]string `json:",omitempty"`
36
-	Capabilities Capabilities      `json:",omitempty"`
37
-}
38
-
39
-type graphDriverInitRequest struct {
40
-	Home string
41
-	Opts []string `json:"Opts"`
42
-	idtools.IdentityMapping
43
-}
44
-
45
-func (d *graphDriverProxy) Init(home string, opts []string, idMap idtools.IdentityMapping) error {
46
-	if !d.p.IsV1() {
47
-		if cp, ok := d.p.(plugingetter.CountedPlugin); ok {
48
-			// always acquire here, it will be cleaned up on daemon shutdown
49
-			cp.Acquire()
50
-		}
51
-	}
52
-	args := &graphDriverInitRequest{
53
-		Home:            home,
54
-		Opts:            opts,
55
-		IdentityMapping: idMap,
56
-	}
57
-	var ret graphDriverResponse
58
-	if err := d.client.Call("GraphDriver.Init", args, &ret); err != nil {
59
-		return err
60
-	}
61
-	if ret.Err != "" {
62
-		return errors.New(ret.Err)
63
-	}
64
-	caps, err := d.fetchCaps()
65
-	if err != nil {
66
-		return err
67
-	}
68
-	d.caps = caps
69
-	return nil
70
-}
71
-
72
-func (d *graphDriverProxy) fetchCaps() (Capabilities, error) {
73
-	args := &graphDriverRequest{}
74
-	var ret graphDriverResponse
75
-	if err := d.client.Call("GraphDriver.Capabilities", args, &ret); err != nil {
76
-		if !plugins.IsNotFound(err) {
77
-			return Capabilities{}, err
78
-		}
79
-	}
80
-	return ret.Capabilities, nil
81
-}
82
-
83
-func (d *graphDriverProxy) String() string {
84
-	return d.name
85
-}
86
-
87
-func (d *graphDriverProxy) Capabilities() Capabilities {
88
-	return d.caps
89
-}
90
-
91
-func (d *graphDriverProxy) CreateReadWrite(id, parent string, opts *CreateOpts) error {
92
-	return d.create("GraphDriver.CreateReadWrite", id, parent, opts)
93
-}
94
-
95
-func (d *graphDriverProxy) Create(id, parent string, opts *CreateOpts) error {
96
-	return d.create("GraphDriver.Create", id, parent, opts)
97
-}
98
-
99
-func (d *graphDriverProxy) create(method, id, parent string, opts *CreateOpts) error {
100
-	args := &graphDriverRequest{
101
-		ID:     id,
102
-		Parent: parent,
103
-	}
104
-	if opts != nil {
105
-		args.MountLabel = opts.MountLabel
106
-		args.StorageOpt = opts.StorageOpt
107
-	}
108
-	var ret graphDriverResponse
109
-	if err := d.client.Call(method, args, &ret); err != nil {
110
-		return err
111
-	}
112
-	if ret.Err != "" {
113
-		return errors.New(ret.Err)
114
-	}
115
-	return nil
116
-}
117
-
118
-func (d *graphDriverProxy) Remove(id string) error {
119
-	args := &graphDriverRequest{ID: id}
120
-	var ret graphDriverResponse
121
-	if err := d.client.Call("GraphDriver.Remove", args, &ret); err != nil {
122
-		return err
123
-	}
124
-	if ret.Err != "" {
125
-		return errors.New(ret.Err)
126
-	}
127
-	return nil
128
-}
129
-
130
-func (d *graphDriverProxy) Get(id, mountLabel string) (string, error) {
131
-	args := &graphDriverRequest{
132
-		ID:         id,
133
-		MountLabel: mountLabel,
134
-	}
135
-	var ret graphDriverResponse
136
-	if err := d.client.Call("GraphDriver.Get", args, &ret); err != nil {
137
-		return "", err
138
-	}
139
-	var err error
140
-	if ret.Err != "" {
141
-		err = errors.New(ret.Err)
142
-	}
143
-	return d.p.ScopedPath(ret.Dir), err
144
-}
145
-
146
-func (d *graphDriverProxy) Put(id string) error {
147
-	args := &graphDriverRequest{ID: id}
148
-	var ret graphDriverResponse
149
-	if err := d.client.Call("GraphDriver.Put", args, &ret); err != nil {
150
-		return err
151
-	}
152
-	if ret.Err != "" {
153
-		return errors.New(ret.Err)
154
-	}
155
-	return nil
156
-}
157
-
158
-func (d *graphDriverProxy) Exists(id string) bool {
159
-	args := &graphDriverRequest{ID: id}
160
-	var ret graphDriverResponse
161
-	if err := d.client.Call("GraphDriver.Exists", args, &ret); err != nil {
162
-		return false
163
-	}
164
-	return ret.Exists
165
-}
166
-
167
-func (d *graphDriverProxy) Status() [][2]string {
168
-	args := &graphDriverRequest{}
169
-	var ret graphDriverResponse
170
-	if err := d.client.Call("GraphDriver.Status", args, &ret); err != nil {
171
-		return nil
172
-	}
173
-	return ret.Status
174
-}
175
-
176
-func (d *graphDriverProxy) GetMetadata(id string) (map[string]string, error) {
177
-	args := &graphDriverRequest{
178
-		ID: id,
179
-	}
180
-	var ret graphDriverResponse
181
-	if err := d.client.Call("GraphDriver.GetMetadata", args, &ret); err != nil {
182
-		return nil, err
183
-	}
184
-	if ret.Err != "" {
185
-		return nil, errors.New(ret.Err)
186
-	}
187
-	return ret.Metadata, nil
188
-}
189
-
190
-func (d *graphDriverProxy) Cleanup() error {
191
-	if !d.p.IsV1() {
192
-		if cp, ok := d.p.(plugingetter.CountedPlugin); ok {
193
-			// always release
194
-			defer cp.Release()
195
-		}
196
-	}
197
-
198
-	args := &graphDriverRequest{}
199
-	var ret graphDriverResponse
200
-	if err := d.client.Call("GraphDriver.Cleanup", args, &ret); err != nil {
201
-		return nil
202
-	}
203
-	if ret.Err != "" {
204
-		return errors.New(ret.Err)
205
-	}
206
-	return nil
207
-}
208
-
209
-func (d *graphDriverProxy) Diff(id, parent string) (io.ReadCloser, error) {
210
-	args := &graphDriverRequest{
211
-		ID:     id,
212
-		Parent: parent,
213
-	}
214
-	body, err := d.client.Stream("GraphDriver.Diff", args)
215
-	if err != nil {
216
-		return nil, err
217
-	}
218
-	return body, nil
219
-}
220
-
221
-func (d *graphDriverProxy) Changes(id, parent string) ([]archive.Change, error) {
222
-	args := &graphDriverRequest{
223
-		ID:     id,
224
-		Parent: parent,
225
-	}
226
-	var ret graphDriverResponse
227
-	if err := d.client.Call("GraphDriver.Changes", args, &ret); err != nil {
228
-		return nil, err
229
-	}
230
-	if ret.Err != "" {
231
-		return nil, errors.New(ret.Err)
232
-	}
233
-
234
-	return ret.Changes, nil
235
-}
236
-
237
-func (d *graphDriverProxy) ApplyDiff(id, parent string, diff io.Reader) (int64, error) {
238
-	var ret graphDriverResponse
239
-	if err := d.client.SendFile(fmt.Sprintf("GraphDriver.ApplyDiff?id=%s&parent=%s", id, parent), diff, &ret); err != nil {
240
-		return -1, err
241
-	}
242
-	if ret.Err != "" {
243
-		return -1, errors.New(ret.Err)
244
-	}
245
-	return ret.Size, nil
246
-}
247
-
248
-func (d *graphDriverProxy) DiffSize(id, parent string) (int64, error) {
249
-	args := &graphDriverRequest{
250
-		ID:     id,
251
-		Parent: parent,
252
-	}
253
-	var ret graphDriverResponse
254
-	if err := d.client.Call("GraphDriver.DiffSize", args, &ret); err != nil {
255
-		return -1, err
256
-	}
257
-	if ret.Err != "" {
258
-		return -1, errors.New(ret.Err)
259
-	}
260
-	return ret.Size, nil
261
-}
262 1
deleted file mode 100644
... ...
@@ -1,43 +0,0 @@
1
-package graphdriver // import "github.com/docker/docker/daemon/graphdriver"
2
-
3
-import (
4
-	"encoding/json"
5
-	"testing"
6
-
7
-	"github.com/docker/docker/pkg/idtools"
8
-	"gotest.tools/v3/assert"
9
-)
10
-
11
-func TestGraphDriverInitRequestIsCompatible(t *testing.T) {
12
-	// Graph driver plugins may unmarshal into this version of the init
13
-	// request struct. Verify that the serialization of
14
-	// graphDriverInitRequest is fully backwards compatible.
15
-
16
-	type graphDriverInitRequestV1 struct {
17
-		Home    string
18
-		Opts    []string        `json:"Opts"`
19
-		UIDMaps []idtools.IDMap `json:"UIDMaps"`
20
-		GIDMaps []idtools.IDMap `json:"GIDMaps"`
21
-	}
22
-
23
-	args := graphDriverInitRequest{
24
-		Home: "homedir",
25
-		Opts: []string{"option1", "option2"},
26
-		IdentityMapping: idtools.IdentityMapping{
27
-			UIDMaps: []idtools.IDMap{{ContainerID: 123, HostID: 456, Size: 42}},
28
-			GIDMaps: []idtools.IDMap{{ContainerID: 789, HostID: 1011, Size: 16}},
29
-		},
30
-	}
31
-	v, err := json.Marshal(&args)
32
-	assert.NilError(t, err)
33
-
34
-	var got graphDriverInitRequestV1
35
-	assert.NilError(t, json.Unmarshal(v, &got))
36
-	want := graphDriverInitRequestV1{
37
-		Home:    args.Home,
38
-		Opts:    args.Opts,
39
-		UIDMaps: args.UIDMaps,
40
-		GIDMaps: args.GIDMaps,
41
-	}
42
-	assert.DeepEqual(t, got, want)
43
-}
... ...
@@ -92,8 +92,10 @@ func TestXattrUnsupportedByBackingFS(t *testing.T) {
92 92
 		t.Run(tt.name, func(t *testing.T) {
93 93
 			subdir := filepath.Join(rootdir, tt.name)
94 94
 			assert.NilError(t, os.Mkdir(subdir, 0o755))
95
-			d, err := graphdriver.GetDriver("vfs", nil,
96
-				graphdriver.Options{DriverOptions: tt.opts, Root: subdir})
95
+			d, err := graphdriver.GetDriver("vfs", graphdriver.Options{
96
+				DriverOptions: tt.opts,
97
+				Root:          subdir,
98
+			})
97 99
 			assert.NilError(t, err)
98 100
 			defer d.Cleanup()
99 101
 
... ...
@@ -52,7 +52,6 @@ func TestRemoveImageGarbageCollector(t *testing.T) {
52 52
 		GraphDriver:               d.StorageDriver(),
53 53
 		GraphDriverOptions:        nil,
54 54
 		IDMapping:                 idtools.IdentityMapping{},
55
-		PluginGetter:              nil,
56 55
 		ExperimentalEnabled:       false,
57 56
 	})
58 57
 	i := images.NewImageService(images.ImageServiceConfig{
59 58
deleted file mode 100644
... ...
@@ -1,469 +0,0 @@
1
-package graphdriver
2
-
3
-import (
4
-	"context"
5
-	"encoding/json"
6
-	"fmt"
7
-	"io"
8
-	"net/http"
9
-	"net/http/httptest"
10
-	"os"
11
-	"runtime"
12
-	"testing"
13
-
14
-	"github.com/docker/docker/api/types"
15
-	containertypes "github.com/docker/docker/api/types/container"
16
-	"github.com/docker/docker/api/types/image"
17
-	"github.com/docker/docker/client"
18
-	"github.com/docker/docker/daemon/graphdriver"
19
-	"github.com/docker/docker/daemon/graphdriver/vfs"
20
-	"github.com/docker/docker/integration/internal/container"
21
-	"github.com/docker/docker/integration/internal/requirement"
22
-	"github.com/docker/docker/pkg/archive"
23
-	"github.com/docker/docker/pkg/idtools"
24
-	"github.com/docker/docker/pkg/plugins"
25
-	"github.com/docker/docker/testutil"
26
-	"github.com/docker/docker/testutil/daemon"
27
-	"gotest.tools/v3/assert"
28
-	is "gotest.tools/v3/assert/cmp"
29
-	"gotest.tools/v3/skip"
30
-)
31
-
32
-type graphEventsCounter struct {
33
-	activations int
34
-	creations   int
35
-	removals    int
36
-	gets        int
37
-	puts        int
38
-	stats       int
39
-	cleanups    int
40
-	exists      int
41
-	init        int
42
-	metadata    int
43
-	diff        int
44
-	applydiff   int
45
-	changes     int
46
-	diffsize    int
47
-}
48
-
49
-func TestExternalGraphDriver(t *testing.T) {
50
-	skip.If(t, testEnv.UsingSnapshotter())
51
-	skip.If(t, runtime.GOOS == "windows")
52
-	skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon")
53
-	skip.If(t, !requirement.HasHubConnectivity(t))
54
-	skip.If(t, testEnv.IsRootless, "rootless mode doesn't support external graph driver")
55
-
56
-	ctx := testutil.StartSpan(baseContext, t)
57
-
58
-	// Setup plugin(s)
59
-	ec := make(map[string]*graphEventsCounter)
60
-	sserver := setupPluginViaSpecFile(t, ec)
61
-	jserver := setupPluginViaJSONFile(t, ec)
62
-	// Create daemon
63
-	d := daemon.New(t, daemon.WithExperimental(), daemon.WithEnvVars("DOCKERD_DEPRECATED_GRAPHDRIVER_PLUGINS=1"))
64
-	c := d.NewClientT(t)
65
-
66
-	for _, tc := range []struct {
67
-		name string
68
-		test func(context.Context, client.APIClient, *daemon.Daemon) func(*testing.T)
69
-	}{
70
-		{
71
-			name: "json",
72
-			test: testExternalGraphDriver("json", ec),
73
-		},
74
-		{
75
-			name: "spec",
76
-			test: testExternalGraphDriver("spec", ec),
77
-		},
78
-		{
79
-			name: "pull",
80
-			test: testGraphDriverPull,
81
-		},
82
-	} {
83
-		t.Run(tc.name, func(t *testing.T) {
84
-			ctx := testutil.StartSpan(ctx, t)
85
-			tc.test(ctx, c, d)
86
-		})
87
-	}
88
-
89
-	sserver.Close()
90
-	jserver.Close()
91
-	err := os.RemoveAll("/etc/docker/plugins")
92
-	assert.NilError(t, err)
93
-}
94
-
95
-func setupPluginViaSpecFile(t *testing.T, ec map[string]*graphEventsCounter) *httptest.Server {
96
-	mux := http.NewServeMux()
97
-	server := httptest.NewServer(mux)
98
-
99
-	setupPlugin(t, ec, "spec", mux, []byte(server.URL))
100
-
101
-	return server
102
-}
103
-
104
-func setupPluginViaJSONFile(t *testing.T, ec map[string]*graphEventsCounter) *httptest.Server {
105
-	mux := http.NewServeMux()
106
-	server := httptest.NewServer(mux)
107
-
108
-	p := plugins.NewLocalPlugin("json-external-graph-driver", server.URL)
109
-	b, err := json.Marshal(p)
110
-	assert.NilError(t, err)
111
-
112
-	setupPlugin(t, ec, "json", mux, b)
113
-
114
-	return server
115
-}
116
-
117
-func setupPlugin(t *testing.T, ec map[string]*graphEventsCounter, ext string, mux *http.ServeMux, b []byte) {
118
-	name := fmt.Sprintf("%s-external-graph-driver", ext)
119
-	type graphDriverRequest struct {
120
-		ID         string `json:",omitempty"`
121
-		Parent     string `json:",omitempty"`
122
-		MountLabel string `json:",omitempty"`
123
-		ReadOnly   bool   `json:",omitempty"`
124
-	}
125
-
126
-	type graphDriverResponse struct {
127
-		Err      error             `json:",omitempty"`
128
-		Dir      string            `json:",omitempty"`
129
-		Exists   bool              `json:",omitempty"`
130
-		Status   [][2]string       `json:",omitempty"`
131
-		Metadata map[string]string `json:",omitempty"`
132
-		Changes  []archive.Change  `json:",omitempty"`
133
-		Size     int64             `json:",omitempty"`
134
-	}
135
-
136
-	respond := func(w http.ResponseWriter, data interface{}) {
137
-		w.Header().Set("Content-Type", plugins.VersionMimetype)
138
-		switch t := data.(type) {
139
-		case error:
140
-			fmt.Fprintf(w, "{\"Err\": %q}\n", t.Error())
141
-		case string:
142
-			fmt.Fprintln(w, t)
143
-		default:
144
-			json.NewEncoder(w).Encode(&data)
145
-		}
146
-	}
147
-
148
-	decReq := func(b io.ReadCloser, out interface{}, w http.ResponseWriter) error {
149
-		defer b.Close()
150
-		if err := json.NewDecoder(b).Decode(&out); err != nil {
151
-			http.Error(w, fmt.Sprintf("error decoding json: %s", err.Error()), 500)
152
-		}
153
-		return nil
154
-	}
155
-
156
-	base, err := os.MkdirTemp("", name)
157
-	assert.NilError(t, err)
158
-	vfsProto, err := vfs.Init(base, []string{}, idtools.IdentityMapping{})
159
-	assert.NilError(t, err, "error initializing graph driver")
160
-	driver := graphdriver.NewNaiveDiffDriver(vfsProto, idtools.IdentityMapping{})
161
-
162
-	ec[ext] = &graphEventsCounter{}
163
-	mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
164
-		ec[ext].activations++
165
-		respond(w, `{"Implements": ["GraphDriver"]}`)
166
-	})
167
-
168
-	mux.HandleFunc("/GraphDriver.Init", func(w http.ResponseWriter, r *http.Request) {
169
-		ec[ext].init++
170
-		respond(w, "{}")
171
-	})
172
-
173
-	mux.HandleFunc("/GraphDriver.CreateReadWrite", func(w http.ResponseWriter, r *http.Request) {
174
-		ec[ext].creations++
175
-
176
-		var req graphDriverRequest
177
-		if err := decReq(r.Body, &req, w); err != nil {
178
-			return
179
-		}
180
-		if err := driver.CreateReadWrite(req.ID, req.Parent, nil); err != nil {
181
-			respond(w, err)
182
-			return
183
-		}
184
-		respond(w, "{}")
185
-	})
186
-
187
-	mux.HandleFunc("/GraphDriver.Create", func(w http.ResponseWriter, r *http.Request) {
188
-		ec[ext].creations++
189
-
190
-		var req graphDriverRequest
191
-		if err := decReq(r.Body, &req, w); err != nil {
192
-			return
193
-		}
194
-		if err := driver.Create(req.ID, req.Parent, nil); err != nil {
195
-			respond(w, err)
196
-			return
197
-		}
198
-		respond(w, "{}")
199
-	})
200
-
201
-	mux.HandleFunc("/GraphDriver.Remove", func(w http.ResponseWriter, r *http.Request) {
202
-		ec[ext].removals++
203
-
204
-		var req graphDriverRequest
205
-		if err := decReq(r.Body, &req, w); err != nil {
206
-			return
207
-		}
208
-
209
-		if err := driver.Remove(req.ID); err != nil {
210
-			respond(w, err)
211
-			return
212
-		}
213
-		respond(w, "{}")
214
-	})
215
-
216
-	mux.HandleFunc("/GraphDriver.Get", func(w http.ResponseWriter, r *http.Request) {
217
-		ec[ext].gets++
218
-
219
-		var req graphDriverRequest
220
-		if err := decReq(r.Body, &req, w); err != nil {
221
-			return
222
-		}
223
-
224
-		dir, err := driver.Get(req.ID, req.MountLabel)
225
-		if err != nil {
226
-			respond(w, err)
227
-			return
228
-		}
229
-		respond(w, &graphDriverResponse{Dir: dir})
230
-	})
231
-
232
-	mux.HandleFunc("/GraphDriver.Put", func(w http.ResponseWriter, r *http.Request) {
233
-		ec[ext].puts++
234
-
235
-		var req graphDriverRequest
236
-		if err := decReq(r.Body, &req, w); err != nil {
237
-			return
238
-		}
239
-
240
-		if err := driver.Put(req.ID); err != nil {
241
-			respond(w, err)
242
-			return
243
-		}
244
-		respond(w, "{}")
245
-	})
246
-
247
-	mux.HandleFunc("/GraphDriver.Exists", func(w http.ResponseWriter, r *http.Request) {
248
-		ec[ext].exists++
249
-
250
-		var req graphDriverRequest
251
-		if err := decReq(r.Body, &req, w); err != nil {
252
-			return
253
-		}
254
-		respond(w, &graphDriverResponse{Exists: driver.Exists(req.ID)})
255
-	})
256
-
257
-	mux.HandleFunc("/GraphDriver.Status", func(w http.ResponseWriter, r *http.Request) {
258
-		ec[ext].stats++
259
-		respond(w, &graphDriverResponse{Status: driver.Status()})
260
-	})
261
-
262
-	mux.HandleFunc("/GraphDriver.Cleanup", func(w http.ResponseWriter, r *http.Request) {
263
-		ec[ext].cleanups++
264
-		err := driver.Cleanup()
265
-		if err != nil {
266
-			respond(w, err)
267
-			return
268
-		}
269
-		respond(w, `{}`)
270
-	})
271
-
272
-	mux.HandleFunc("/GraphDriver.GetMetadata", func(w http.ResponseWriter, r *http.Request) {
273
-		ec[ext].metadata++
274
-
275
-		var req graphDriverRequest
276
-		if err := decReq(r.Body, &req, w); err != nil {
277
-			return
278
-		}
279
-
280
-		data, err := driver.GetMetadata(req.ID)
281
-		if err != nil {
282
-			respond(w, err)
283
-			return
284
-		}
285
-		respond(w, &graphDriverResponse{Metadata: data})
286
-	})
287
-
288
-	mux.HandleFunc("/GraphDriver.Diff", func(w http.ResponseWriter, r *http.Request) {
289
-		ec[ext].diff++
290
-
291
-		var req graphDriverRequest
292
-		if err := decReq(r.Body, &req, w); err != nil {
293
-			return
294
-		}
295
-
296
-		diff, err := driver.Diff(req.ID, req.Parent)
297
-		if err != nil {
298
-			respond(w, err)
299
-			return
300
-		}
301
-		io.Copy(w, diff)
302
-	})
303
-
304
-	mux.HandleFunc("/GraphDriver.Changes", func(w http.ResponseWriter, r *http.Request) {
305
-		ec[ext].changes++
306
-		var req graphDriverRequest
307
-		if err := decReq(r.Body, &req, w); err != nil {
308
-			return
309
-		}
310
-
311
-		changes, err := driver.Changes(req.ID, req.Parent)
312
-		if err != nil {
313
-			respond(w, err)
314
-			return
315
-		}
316
-		respond(w, &graphDriverResponse{Changes: changes})
317
-	})
318
-
319
-	mux.HandleFunc("/GraphDriver.ApplyDiff", func(w http.ResponseWriter, r *http.Request) {
320
-		ec[ext].applydiff++
321
-		diff := r.Body
322
-		defer r.Body.Close()
323
-
324
-		id := r.URL.Query().Get("id")
325
-		parent := r.URL.Query().Get("parent")
326
-
327
-		if id == "" {
328
-			http.Error(w, "missing id", 409)
329
-		}
330
-
331
-		size, err := driver.ApplyDiff(id, parent, diff)
332
-		if err != nil {
333
-			respond(w, err)
334
-			return
335
-		}
336
-		respond(w, &graphDriverResponse{Size: size})
337
-	})
338
-
339
-	mux.HandleFunc("/GraphDriver.DiffSize", func(w http.ResponseWriter, r *http.Request) {
340
-		ec[ext].diffsize++
341
-
342
-		var req graphDriverRequest
343
-		if err := decReq(r.Body, &req, w); err != nil {
344
-			return
345
-		}
346
-
347
-		size, err := driver.DiffSize(req.ID, req.Parent)
348
-		if err != nil {
349
-			respond(w, err)
350
-			return
351
-		}
352
-		respond(w, &graphDriverResponse{Size: size})
353
-	})
354
-
355
-	err = os.MkdirAll("/etc/docker/plugins", 0o755)
356
-	assert.NilError(t, err)
357
-
358
-	specFile := "/etc/docker/plugins/" + name + "." + ext
359
-	err = os.WriteFile(specFile, b, 0o644)
360
-	assert.NilError(t, err)
361
-}
362
-
363
-func testExternalGraphDriver(ext string, ec map[string]*graphEventsCounter) func(context.Context, client.APIClient, *daemon.Daemon) func(*testing.T) {
364
-	return func(ctx context.Context, c client.APIClient, d *daemon.Daemon) func(*testing.T) {
365
-		return func(t *testing.T) {
366
-			driverName := fmt.Sprintf("%s-external-graph-driver", ext)
367
-			d.StartWithBusybox(ctx, t, "-s", driverName)
368
-
369
-			testGraphDriver(ctx, t, c, driverName, func(t *testing.T) {
370
-				d.Restart(t, "-s", driverName)
371
-			})
372
-
373
-			_, err := c.Info(ctx)
374
-			assert.NilError(t, err)
375
-
376
-			d.Stop(t)
377
-
378
-			// Don't check ec.exists, because the daemon no longer calls the
379
-			// Exists function.
380
-			assert.Check(t, is.Equal(ec[ext].activations, 2))
381
-			assert.Check(t, is.Equal(ec[ext].init, 2))
382
-			assert.Check(t, ec[ext].creations >= 1)
383
-			assert.Check(t, ec[ext].removals >= 1)
384
-			assert.Check(t, ec[ext].gets >= 1)
385
-			assert.Check(t, ec[ext].puts >= 1)
386
-			assert.Check(t, is.Equal(ec[ext].stats, 5))
387
-			assert.Check(t, is.Equal(ec[ext].cleanups, 2))
388
-			assert.Check(t, ec[ext].applydiff >= 1)
389
-			assert.Check(t, is.Equal(ec[ext].changes, 1))
390
-			assert.Check(t, is.Equal(ec[ext].diffsize, 0))
391
-			assert.Check(t, is.Equal(ec[ext].diff, 0))
392
-			assert.Check(t, is.Equal(ec[ext].metadata, 1))
393
-		}
394
-	}
395
-}
396
-
397
-func testGraphDriverPull(ctx context.Context, c client.APIClient, d *daemon.Daemon) func(*testing.T) {
398
-	return func(t *testing.T) {
399
-		d.Start(t)
400
-		defer d.Stop(t)
401
-
402
-		r, err := c.ImagePull(ctx, "busybox:latest@sha256:95cf004f559831017cdf4628aaf1bb30133677be8702a8c5f2994629f637a209", image.PullOptions{})
403
-		assert.NilError(t, err)
404
-		_, err = io.Copy(io.Discard, r)
405
-		assert.NilError(t, err)
406
-
407
-		container.Run(ctx, t, c, container.WithImage("busybox:latest@sha256:95cf004f559831017cdf4628aaf1bb30133677be8702a8c5f2994629f637a209"))
408
-	}
409
-}
410
-
411
-func TestGraphdriverPluginV2(t *testing.T) {
412
-	skip.If(t, testEnv.UsingSnapshotter())
413
-	skip.If(t, runtime.GOOS == "windows")
414
-	skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon")
415
-	skip.If(t, !requirement.HasHubConnectivity(t))
416
-	skip.If(t, testEnv.NotAmd64)
417
-	skip.If(t, !requirement.Overlay2Supported(testEnv.DaemonInfo.KernelVersion))
418
-
419
-	ctx := testutil.StartSpan(baseContext, t)
420
-
421
-	d := daemon.New(t, daemon.WithExperimental(), daemon.WithEnvVars("DOCKERD_DEPRECATED_GRAPHDRIVER_PLUGINS=1"))
422
-	d.Start(t)
423
-	defer d.Stop(t)
424
-
425
-	apiClient := d.NewClientT(t)
426
-	defer apiClient.Close()
427
-
428
-	// install the plugin
429
-	plugin := "cpuguy83/docker-overlay2-graphdriver-plugin"
430
-	responseReader, err := apiClient.PluginInstall(ctx, plugin, types.PluginInstallOptions{
431
-		RemoteRef:            plugin,
432
-		AcceptAllPermissions: true,
433
-	})
434
-	assert.NilError(t, err)
435
-	defer responseReader.Close()
436
-	// ensure it's done by waiting for EOF on the response
437
-	_, err = io.Copy(io.Discard, responseReader)
438
-	assert.NilError(t, err)
439
-
440
-	// restart the daemon with the plugin set as the storage driver
441
-	d.Stop(t)
442
-	d.StartWithBusybox(ctx, t, "-s", plugin)
443
-
444
-	testGraphDriver(ctx, t, apiClient, plugin, nil)
445
-}
446
-
447
-func testGraphDriver(ctx context.Context, t *testing.T, c client.APIClient, driverName string, afterContainerRunFn func(*testing.T)) {
448
-	id := container.Run(ctx, t, c, container.WithCmd("sh", "-c", "echo hello > /hello"))
449
-
450
-	if afterContainerRunFn != nil {
451
-		afterContainerRunFn(t)
452
-	}
453
-
454
-	i, err := c.ContainerInspect(ctx, id)
455
-	assert.NilError(t, err)
456
-	assert.Check(t, is.Equal(i.GraphDriver.Name, driverName))
457
-
458
-	diffs, err := c.ContainerDiff(ctx, id)
459
-	assert.NilError(t, err)
460
-	assert.Check(t, is.Contains(diffs, containertypes.FilesystemChange{
461
-		Kind: containertypes.ChangeAdd,
462
-		Path: "/hello",
463
-	}), "diffs: %v", diffs)
464
-
465
-	err = c.ContainerRemove(ctx, id, containertypes.RemoveOptions{
466
-		Force: true,
467
-	})
468
-	assert.NilError(t, err)
469
-}
470 1
deleted file mode 100644
... ...
@@ -1,46 +0,0 @@
1
-package graphdriver // import "github.com/docker/docker/integration/plugin/graphdriver"
2
-
3
-import (
4
-	"context"
5
-	"os"
6
-	"testing"
7
-
8
-	"github.com/docker/docker/testutil"
9
-	"github.com/docker/docker/testutil/environment"
10
-	"go.opentelemetry.io/otel"
11
-	"go.opentelemetry.io/otel/codes"
12
-)
13
-
14
-var (
15
-	testEnv     *environment.Execution
16
-	baseContext context.Context
17
-)
18
-
19
-func TestMain(m *testing.M) {
20
-	shutdown := testutil.ConfigureTracing()
21
-	ctx, span := otel.Tracer("").Start(context.Background(), "integration/plugin/graphdriver.TestMain")
22
-	baseContext = ctx
23
-
24
-	var err error
25
-	testEnv, err = environment.New(ctx)
26
-	if err != nil {
27
-		span.SetStatus(codes.Error, err.Error())
28
-		span.End()
29
-		shutdown(ctx)
30
-		panic(err)
31
-	}
32
-	err = environment.EnsureFrozenImagesLinux(ctx, testEnv)
33
-	if err != nil {
34
-		span.SetStatus(codes.Error, err.Error())
35
-		span.End()
36
-		shutdown(ctx)
37
-		panic(err)
38
-	}
39
-	testEnv.Print()
40
-	code := m.Run()
41
-	if code != 0 {
42
-		span.SetStatus(codes.Error, "m.Run() exited with non-zero code")
43
-	}
44
-	shutdown(ctx)
45
-	os.Exit(code)
46
-}
... ...
@@ -13,7 +13,6 @@ import (
13 13
 	"github.com/docker/distribution"
14 14
 	"github.com/docker/docker/daemon/graphdriver"
15 15
 	"github.com/docker/docker/pkg/idtools"
16
-	"github.com/docker/docker/pkg/plugingetter"
17 16
 	"github.com/docker/docker/pkg/stringid"
18 17
 	"github.com/moby/locker"
19 18
 	"github.com/opencontainers/go-digest"
... ...
@@ -50,13 +49,12 @@ type StoreOptions struct {
50 50
 	GraphDriver               string
51 51
 	GraphDriverOptions        []string
52 52
 	IDMapping                 idtools.IdentityMapping
53
-	PluginGetter              plugingetter.PluginGetter
54 53
 	ExperimentalEnabled       bool
55 54
 }
56 55
 
57 56
 // NewStoreFromOptions creates a new Store instance
58 57
 func NewStoreFromOptions(options StoreOptions) (Store, error) {
59
-	driver, err := graphdriver.New(options.GraphDriver, options.PluginGetter, graphdriver.Options{
58
+	driver, err := graphdriver.New(options.GraphDriver, graphdriver.Options{
60 59
 		Root:                options.Root,
61 60
 		DriverOptions:       options.GraphDriverOptions,
62 61
 		IDMap:               options.IDMapping,
... ...
@@ -26,23 +26,21 @@ func init() {
26 26
 }
27 27
 
28 28
 func newVFSGraphDriver(td string) (graphdriver.Driver, error) {
29
-	uidMap := []idtools.IDMap{
30
-		{
31
-			ContainerID: 0,
32
-			HostID:      os.Getuid(),
33
-			Size:        1,
29
+	return graphdriver.GetDriver("vfs", graphdriver.Options{
30
+		Root: td,
31
+		IDMap: idtools.IdentityMapping{
32
+			UIDMaps: []idtools.IDMap{{
33
+				ContainerID: 0,
34
+				HostID:      os.Getuid(),
35
+				Size:        1,
36
+			}},
37
+			GIDMaps: []idtools.IDMap{{
38
+				ContainerID: 0,
39
+				HostID:      os.Getgid(),
40
+				Size:        1,
41
+			}},
34 42
 		},
35
-	}
36
-	gidMap := []idtools.IDMap{
37
-		{
38
-			ContainerID: 0,
39
-			HostID:      os.Getgid(),
40
-			Size:        1,
41
-		},
42
-	}
43
-
44
-	options := graphdriver.Options{Root: td, IDMap: idtools.IdentityMapping{UIDMaps: uidMap, GIDMaps: gidMap}}
45
-	return graphdriver.GetDriver("vfs", nil, options)
43
+	})
46 44
 }
47 45
 
48 46
 func newTestGraphDriver(t *testing.T) (graphdriver.Driver, func()) {
... ...
@@ -204,6 +204,7 @@ func (pm *Manager) reload() error { // todo: restore
204 204
 
205 205
 		go func(p *v2.Plugin) {
206 206
 			defer wg.Done()
207
+			// TODO(thaJeztah): make this fail if the plugin has "graphdriver" capability ?
207 208
 			if err := pm.restorePlugin(p, c); err != nil {
208 209
 				log.G(context.TODO()).WithError(err).WithField("id", p.GetID()).Error("Failed to restore plugin")
209 210
 				return
... ...
@@ -219,6 +220,11 @@ func (pm *Manager) reload() error { // todo: restore
219 219
 					if p.PluginObj.Config.PropagatedMount != "" {
220 220
 						propRoot := filepath.Join(filepath.Dir(p.Rootfs), "propagated-mount")
221 221
 
222
+						if typ.Capability == "graphdriver" {
223
+							// TODO(thaJeztah): remove this for next release.
224
+							log.G(context.TODO()).WithError(err).WithField("dir", propRoot).Warn("skipping migrating propagated mount storage for deprecated graphdriver plugin")
225
+						}
226
+
222 227
 						// check if we need to migrate an older propagated mount from before
223 228
 						// these mounts were stored outside the plugin rootfs
224 229
 						if _, err := os.Stat(propRoot); os.IsNotExist(err) {