1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge pull request #28623 from cpuguy83/update_graphdriver_docs

Ensure graphdriver only loads with experimental flag
This commit is contained in:
Vincent Demeester 2016-12-24 11:59:24 +01:00 committed by GitHub
commit d3e3a97cb2
9 changed files with 153 additions and 91 deletions

View file

@ -575,6 +575,7 @@ func NewDaemon(config *Config, registryService registry.Service, containerdRemot
UIDMaps: uidMaps, UIDMaps: uidMaps,
GIDMaps: gidMaps, GIDMaps: gidMaps,
PluginGetter: d.PluginStore, PluginGetter: d.PluginStore,
ExperimentalEnabled: config.Experimental,
}) })
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -150,16 +150,16 @@ func Register(name string, initFunc InitFunc) error {
} }
// GetDriver initializes and returns the registered driver // GetDriver initializes and returns the registered driver
func GetDriver(name, home string, options []string, uidMaps, gidMaps []idtools.IDMap, pg plugingetter.PluginGetter) (Driver, error) { func GetDriver(name string, pg plugingetter.PluginGetter, config Options) (Driver, error) {
if initFunc, exists := drivers[name]; exists { if initFunc, exists := drivers[name]; exists {
return initFunc(filepath.Join(home, name), options, uidMaps, gidMaps) return initFunc(filepath.Join(config.Root, name), config.DriverOptions, config.UIDMaps, config.GIDMaps)
} }
pluginDriver, err := lookupPlugin(name, home, options, pg) pluginDriver, err := lookupPlugin(name, pg, config)
if err == nil { if err == nil {
return pluginDriver, nil return pluginDriver, nil
} }
logrus.WithError(err).WithField("driver", name).WithField("home-dir", home).Error("Failed to GetDriver graph") logrus.WithError(err).WithField("driver", name).WithField("home-dir", config.Root).Error("Failed to GetDriver graph")
return nil, ErrNotSupported return nil, ErrNotSupported
} }
@ -172,15 +172,24 @@ func getBuiltinDriver(name, home string, options []string, uidMaps, gidMaps []id
return nil, ErrNotSupported return nil, ErrNotSupported
} }
// Options is used to initialize a graphdriver
type Options struct {
Root string
DriverOptions []string
UIDMaps []idtools.IDMap
GIDMaps []idtools.IDMap
ExperimentalEnabled bool
}
// New creates the driver and initializes it at the specified root. // New creates the driver and initializes it at the specified root.
func New(root, name string, options []string, uidMaps, gidMaps []idtools.IDMap, pg plugingetter.PluginGetter) (Driver, error) { func New(name string, pg plugingetter.PluginGetter, config Options) (Driver, error) {
if name != "" { if name != "" {
logrus.Debugf("[graphdriver] trying provided driver: %s", name) // so the logs show specified driver logrus.Debugf("[graphdriver] trying provided driver: %s", name) // so the logs show specified driver
return GetDriver(name, root, options, uidMaps, gidMaps, pg) return GetDriver(name, pg, config)
} }
// Guess for prior driver // Guess for prior driver
driversMap := scanPriorDrivers(root) driversMap := scanPriorDrivers(config.Root)
for _, name := range priority { for _, name := range priority {
if name == "vfs" { if name == "vfs" {
// don't use vfs even if there is state present. // don't use vfs even if there is state present.
@ -189,7 +198,7 @@ func New(root, name string, options []string, uidMaps, gidMaps []idtools.IDMap,
if _, prior := driversMap[name]; prior { if _, prior := driversMap[name]; prior {
// of the state found from prior drivers, check in order of our priority // of the state found from prior drivers, check in order of our priority
// which we would prefer // which we would prefer
driver, err := getBuiltinDriver(name, root, options, uidMaps, gidMaps) driver, err := getBuiltinDriver(name, config.Root, config.DriverOptions, config.UIDMaps, config.GIDMaps)
if err != nil { if err != nil {
// unlike below, we will return error here, because there is prior // unlike below, we will return error here, because there is prior
// state, and now it is no longer supported/prereq/compatible, so // state, and now it is no longer supported/prereq/compatible, so
@ -207,7 +216,7 @@ func New(root, name string, options []string, uidMaps, gidMaps []idtools.IDMap,
driversSlice = append(driversSlice, name) driversSlice = append(driversSlice, name)
} }
return nil, fmt.Errorf("%s contains several valid graphdrivers: %s; Please cleanup or explicitly choose storage driver (-s <DRIVER>)", root, strings.Join(driversSlice, ", ")) return nil, fmt.Errorf("%s contains several valid graphdrivers: %s; Please cleanup or explicitly choose storage driver (-s <DRIVER>)", config.Root, strings.Join(driversSlice, ", "))
} }
logrus.Infof("[graphdriver] using prior storage driver: %s", name) logrus.Infof("[graphdriver] using prior storage driver: %s", name)
@ -217,7 +226,7 @@ func New(root, name string, options []string, uidMaps, gidMaps []idtools.IDMap,
// Check for priority drivers first // Check for priority drivers first
for _, name := range priority { for _, name := range priority {
driver, err := getBuiltinDriver(name, root, options, uidMaps, gidMaps) driver, err := getBuiltinDriver(name, config.Root, config.DriverOptions, config.UIDMaps, config.GIDMaps)
if err != nil { if err != nil {
if isDriverNotSupported(err) { if isDriverNotSupported(err) {
continue continue
@ -229,7 +238,7 @@ func New(root, name string, options []string, uidMaps, gidMaps []idtools.IDMap,
// Check all registered drivers if no priority driver is found // Check all registered drivers if no priority driver is found
for name, initFunc := range drivers { for name, initFunc := range drivers {
driver, err := initFunc(filepath.Join(root, name), options, uidMaps, gidMaps) driver, err := initFunc(filepath.Join(config.Root, name), config.DriverOptions, config.UIDMaps, config.GIDMaps)
if err != nil { if err != nil {
if isDriverNotSupported(err) { if isDriverNotSupported(err) {
continue continue

View file

@ -41,7 +41,7 @@ func newDriver(t testing.TB, name string, options []string) *Driver {
t.Fatal(err) t.Fatal(err)
} }
d, err := graphdriver.GetDriver(name, root, options, nil, nil, nil) d, err := graphdriver.GetDriver(name, nil, graphdriver.Options{DriverOptions: options, Root: root})
if err != nil { if err != nil {
t.Logf("graphdriver: %v\n", err) t.Logf("graphdriver: %v\n", err)
if err == graphdriver.ErrNotSupported || err == graphdriver.ErrPrerequisites || err == graphdriver.ErrIncompatibleFS { if err == graphdriver.ErrNotSupported || err == graphdriver.ErrPrerequisites || err == graphdriver.ErrIncompatibleFS {

View file

@ -18,15 +18,19 @@ type pluginClient interface {
SendFile(string, io.Reader, interface{}) error SendFile(string, io.Reader, interface{}) error
} }
func lookupPlugin(name, home string, opts []string, pg plugingetter.PluginGetter) (Driver, error) { func lookupPlugin(name string, pg plugingetter.PluginGetter, config Options) (Driver, error) {
pl, err := pg.Get(name, "GraphDriver", plugingetter.LOOKUP) if !config.ExperimentalEnabled {
return nil, fmt.Errorf("graphdriver plugins are only supported with experimental mode")
}
pl, err := pg.Get(name, "GraphDriver", plugingetter.ACQUIRE)
if err != nil { if err != nil {
return nil, fmt.Errorf("Error looking up graphdriver plugin %s: %v", name, err) return nil, fmt.Errorf("Error looking up graphdriver plugin %s: %v", name, err)
} }
return newPluginDriver(name, home, opts, pl) return newPluginDriver(name, pl, config)
} }
func newPluginDriver(name, home string, opts []string, pl plugingetter.CompatPlugin) (Driver, error) { func newPluginDriver(name string, pl plugingetter.CompatPlugin, config Options) (Driver, error) {
home := config.Root
if !pl.IsV1() { if !pl.IsV1() {
if p, ok := pl.(*v2.Plugin); ok { if p, ok := pl.(*v2.Plugin); ok {
if p.PropagatedMount != "" { if p.PropagatedMount != "" {
@ -35,5 +39,5 @@ func newPluginDriver(name, home string, opts []string, pl plugingetter.CompatPlu
} }
} }
proxy := &graphDriverProxy{name, pl} proxy := &graphDriverProxy{name, pl}
return proxy, proxy.Init(filepath.Join(home, name), opts) return proxy, proxy.Init(filepath.Join(home, name), config.DriverOptions, config.UIDMaps, config.GIDMaps)
} }

View file

@ -7,6 +7,7 @@ import (
"path/filepath" "path/filepath"
"github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/plugingetter" "github.com/docker/docker/pkg/plugingetter"
) )
@ -16,9 +17,10 @@ type graphDriverProxy struct {
} }
type graphDriverRequest struct { type graphDriverRequest struct {
ID string `json:",omitempty"` ID string `json:",omitempty"`
Parent string `json:",omitempty"` Parent string `json:",omitempty"`
MountLabel string `json:",omitempty"` MountLabel string `json:",omitempty"`
StorageOpt map[string]string `json:",omitempty"`
} }
type graphDriverResponse struct { type graphDriverResponse struct {
@ -32,11 +34,13 @@ type graphDriverResponse struct {
} }
type graphDriverInitRequest struct { type graphDriverInitRequest struct {
Home string Home string
Opts []string Opts []string `json:"Opts"`
UIDMaps []idtools.IDMap `json:"UIDMaps"`
GIDMaps []idtools.IDMap `json:"GIDMaps"`
} }
func (d *graphDriverProxy) Init(home string, opts []string) error { func (d *graphDriverProxy) Init(home string, opts []string, uidMaps, gidMaps []idtools.IDMap) error {
if !d.p.IsV1() { if !d.p.IsV1() {
if cp, ok := d.p.(plugingetter.CountedPlugin); ok { if cp, ok := d.p.(plugingetter.CountedPlugin); ok {
// always acquire here, it will be cleaned up on daemon shutdown // always acquire here, it will be cleaned up on daemon shutdown
@ -44,8 +48,10 @@ func (d *graphDriverProxy) Init(home string, opts []string) error {
} }
} }
args := &graphDriverInitRequest{ args := &graphDriverInitRequest{
Home: home, Home: home,
Opts: opts, Opts: opts,
UIDMaps: uidMaps,
GIDMaps: gidMaps,
} }
var ret graphDriverResponse var ret graphDriverResponse
if err := d.p.Client().Call("GraphDriver.Init", args, &ret); err != nil { if err := d.p.Client().Call("GraphDriver.Init", args, &ret); err != nil {
@ -62,16 +68,15 @@ func (d *graphDriverProxy) String() string {
} }
func (d *graphDriverProxy) CreateReadWrite(id, parent string, opts *CreateOpts) error { func (d *graphDriverProxy) CreateReadWrite(id, parent string, opts *CreateOpts) error {
mountLabel := "" args := &graphDriverRequest{
ID: id,
Parent: parent,
}
if opts != nil { if opts != nil {
mountLabel = opts.MountLabel args.MountLabel = opts.MountLabel
args.StorageOpt = opts.StorageOpt
} }
args := &graphDriverRequest{
ID: id,
Parent: parent,
MountLabel: mountLabel,
}
var ret graphDriverResponse var ret graphDriverResponse
if err := d.p.Client().Call("GraphDriver.CreateReadWrite", args, &ret); err != nil { if err := d.p.Client().Call("GraphDriver.CreateReadWrite", args, &ret); err != nil {
return err return err
@ -83,14 +88,13 @@ func (d *graphDriverProxy) CreateReadWrite(id, parent string, opts *CreateOpts)
} }
func (d *graphDriverProxy) Create(id, parent string, opts *CreateOpts) error { func (d *graphDriverProxy) Create(id, parent string, opts *CreateOpts) error {
mountLabel := ""
if opts != nil {
mountLabel = opts.MountLabel
}
args := &graphDriverRequest{ args := &graphDriverRequest{
ID: id, ID: id,
Parent: parent, Parent: parent,
MountLabel: mountLabel, }
if opts != nil {
args.MountLabel = opts.MountLabel
args.StorageOpt = opts.StorageOpt
} }
var ret graphDriverResponse var ret graphDriverResponse
if err := d.p.Client().Call("GraphDriver.Create", args, &ret); err != nil { if err := d.p.Client().Call("GraphDriver.Create", args, &ret); err != nil {

View file

@ -1,12 +1,42 @@
# Experimental: Docker graph driver plugins ---
title: "Graphdriver plugins"
description: "How to manage image and container filesystems with external plugins"
keywords: "Examples, Usage, storage, image, docker, data, graph, plugin, api"
advisory: experimental
---
<!-- This file is maintained within the docker/docker Github
repository at https://github.com/docker/docker/. Make all
pull requests against that repo. If you see this file in
another repository, consider it read-only there, as it will
periodically be overwritten by the definitive file. Pull
requests which include edits to this file in other repositories
will be rejected.
-->
## Changelog
### 1.13.0
- Support v2 plugins
# Docker graph driver plugins
Docker graph driver plugins enable admins to use an external/out-of-process Docker graph driver plugins enable admins to use an external/out-of-process
graph driver for use with Docker engine. This is an alternative to using the graph driver for use with Docker engine. This is an alternative to using the
built-in storage drivers, such as aufs/overlay/devicemapper/btrfs. built-in storage drivers, such as aufs/overlay/devicemapper/btrfs.
A graph driver plugin is used for image and container filesystem storage, as such You need to install and enable the plugin and then restart the Docker daemon
the plugin must be started and available for connections prior to Docker Engine before using the plugin. See the following example for the correct ordering
being started. of steps.
```
$ docker plugin install cpuguy83/docker-overlay2-graphdriver-plugin # this command also enables the driver
<output supressed>
$ pkill dockerd
$ dockerd --experimental -s cpuguy83/docker-overlay2-graphdriver-plugin
```
# Write a graph driver plugin # Write a graph driver plugin
@ -22,20 +52,30 @@ expected to provide the rootfs for containers as well as image layer storage.
### /GraphDriver.Init ### /GraphDriver.Init
**Request**: **Request**:
``` ```json
{ {
"Home": "/graph/home/path", "Home": "/graph/home/path",
"Opts": [] "Opts": [],
"UIDMaps": [],
"GIDMaps": []
} }
``` ```
Initialize the graph driver plugin with a home directory and array of options. Initialize the graph driver plugin with a home directory and array of options.
Plugins are not required to accept these options as the Docker Engine does not These are passed through from the user, but the plugin is not required to parse
require that the plugin use this path or options, they are only being passed or honor them.
through from the user.
The request also includes a list of UID and GID mappings, structed as follows:
```json
{
"ContainerID": 0,
"HostID": 0,
"Size": 0
}
```
**Response**: **Response**:
``` ```json
{ {
"Err": "" "Err": ""
} }
@ -47,20 +87,21 @@ Respond with a non-empty string error if an error occurred.
### /GraphDriver.Create ### /GraphDriver.Create
**Request**: **Request**:
``` ```json
{ {
"ID": "46fe8644f2572fd1e505364f7581e0c9dbc7f14640bd1fb6ce97714fb6fc5187", "ID": "46fe8644f2572fd1e505364f7581e0c9dbc7f14640bd1fb6ce97714fb6fc5187",
"Parent": "2cd9c322cb78a55e8212aa3ea8425a4180236d7106938ec921d0935a4b8ca142" "Parent": "2cd9c322cb78a55e8212aa3ea8425a4180236d7106938ec921d0935a4b8ca142",
"MountLabel": "" "MountLabel": "",
"StorageOpt": {}
} }
``` ```
Create a new, empty, read-only filesystem layer with the specified Create a new, empty, read-only filesystem layer with the specified
`ID`, `Parent` and `MountLabel`. `Parent` may be an empty string, `ID`, `Parent` and `MountLabel`. If `Parent` is an empty string, there is no
which would indicate that there is no parent layer. parent layer. `StorageOpt` is map of strings which indicate storage options.
**Response**: **Response**:
``` ```json
{ {
"Err": "" "Err": ""
} }
@ -71,11 +112,12 @@ Respond with a non-empty string error if an error occurred.
### /GraphDriver.CreateReadWrite ### /GraphDriver.CreateReadWrite
**Request**: **Request**:
``` ```json
{ {
"ID": "46fe8644f2572fd1e505364f7581e0c9dbc7f14640bd1fb6ce97714fb6fc5187", "ID": "46fe8644f2572fd1e505364f7581e0c9dbc7f14640bd1fb6ce97714fb6fc5187",
"Parent": "2cd9c322cb78a55e8212aa3ea8425a4180236d7106938ec921d0935a4b8ca142" "Parent": "2cd9c322cb78a55e8212aa3ea8425a4180236d7106938ec921d0935a4b8ca142",
"MountLabel": "" "MountLabel": "",
"StorageOpt": {}
} }
``` ```
@ -84,7 +126,7 @@ Similar to `/GraphDriver.Create` but creates a read-write filesystem layer.
### /GraphDriver.Remove ### /GraphDriver.Remove
**Request**: **Request**:
``` ```json
{ {
"ID": "46fe8644f2572fd1e505364f7581e0c9dbc7f14640bd1fb6ce97714fb6fc5187" "ID": "46fe8644f2572fd1e505364f7581e0c9dbc7f14640bd1fb6ce97714fb6fc5187"
} }
@ -93,7 +135,7 @@ Similar to `/GraphDriver.Create` but creates a read-write filesystem layer.
Remove the filesystem layer with this given `ID`. Remove the filesystem layer with this given `ID`.
**Response**: **Response**:
``` ```json
{ {
"Err": "" "Err": ""
} }
@ -104,9 +146,9 @@ Respond with a non-empty string error if an error occurred.
### /GraphDriver.Get ### /GraphDriver.Get
**Request**: **Request**:
``` ```json
{ {
"ID": "46fe8644f2572fd1e505364f7581e0c9dbc7f14640bd1fb6ce97714fb6fc5187" "ID": "46fe8644f2572fd1e505364f7581e0c9dbc7f14640bd1fb6ce97714fb6fc5187",
"MountLabel": "" "MountLabel": ""
} }
``` ```
@ -114,7 +156,7 @@ Respond with a non-empty string error if an error occurred.
Get the mountpoint for the layered filesystem referred to by the given `ID`. Get the mountpoint for the layered filesystem referred to by the given `ID`.
**Response**: **Response**:
``` ```json
{ {
"Dir": "/var/mygraph/46fe8644f2572fd1e505364f7581e0c9dbc7f14640bd1fb6ce97714fb6fc5187", "Dir": "/var/mygraph/46fe8644f2572fd1e505364f7581e0c9dbc7f14640bd1fb6ce97714fb6fc5187",
"Err": "" "Err": ""
@ -127,7 +169,7 @@ Respond with a non-empty string error if an error occurred.
### /GraphDriver.Put ### /GraphDriver.Put
**Request**: **Request**:
``` ```json
{ {
"ID": "46fe8644f2572fd1e505364f7581e0c9dbc7f14640bd1fb6ce97714fb6fc5187" "ID": "46fe8644f2572fd1e505364f7581e0c9dbc7f14640bd1fb6ce97714fb6fc5187"
} }
@ -137,7 +179,7 @@ Release the system resources for the specified `ID`, such as unmounting the
filesystem layer. filesystem layer.
**Response**: **Response**:
``` ```json
{ {
"Err": "" "Err": ""
} }
@ -148,7 +190,7 @@ Respond with a non-empty string error if an error occurred.
### /GraphDriver.Exists ### /GraphDriver.Exists
**Request**: **Request**:
``` ```json
{ {
"ID": "46fe8644f2572fd1e505364f7581e0c9dbc7f14640bd1fb6ce97714fb6fc5187" "ID": "46fe8644f2572fd1e505364f7581e0c9dbc7f14640bd1fb6ce97714fb6fc5187"
} }
@ -157,7 +199,7 @@ Respond with a non-empty string error if an error occurred.
Determine if a filesystem layer with the specified `ID` exists. Determine if a filesystem layer with the specified `ID` exists.
**Response**: **Response**:
``` ```json
{ {
"Exists": true "Exists": true
} }
@ -169,14 +211,14 @@ Respond with a boolean for whether or not the filesystem layer with the specifie
### /GraphDriver.Status ### /GraphDriver.Status
**Request**: **Request**:
``` ```json
{} {}
``` ```
Get low-level diagnostic information about the graph driver. Get low-level diagnostic information about the graph driver.
**Response**: **Response**:
``` ```json
{ {
"Status": [[]] "Status": [[]]
} }
@ -189,7 +231,7 @@ information.
### /GraphDriver.GetMetadata ### /GraphDriver.GetMetadata
**Request**: **Request**:
``` ```json
{ {
"ID": "46fe8644f2572fd1e505364f7581e0c9dbc7f14640bd1fb6ce97714fb6fc5187" "ID": "46fe8644f2572fd1e505364f7581e0c9dbc7f14640bd1fb6ce97714fb6fc5187"
} }
@ -199,7 +241,7 @@ Get low-level diagnostic information about the layered filesystem with the
with the specified `ID` with the specified `ID`
**Response**: **Response**:
``` ```json
{ {
"Metadata": {}, "Metadata": {},
"Err": "" "Err": ""
@ -213,15 +255,15 @@ Respond with a non-empty string error if an error occurred.
### /GraphDriver.Cleanup ### /GraphDriver.Cleanup
**Request**: **Request**:
``` ```json
{} {}
``` ```
Perform necessary tasks to release resources help by the plugin, for example Perform necessary tasks to release resources help by the plugin, such as
unmounting all the layered file systems. unmounting all the layered file systems.
**Response**: **Response**:
``` ```json
{ {
"Err": "" "Err": ""
} }
@ -233,7 +275,7 @@ Respond with a non-empty string error if an error occurred.
### /GraphDriver.Diff ### /GraphDriver.Diff
**Request**: **Request**:
``` ```json
{ {
"ID": "46fe8644f2572fd1e505364f7581e0c9dbc7f14640bd1fb6ce97714fb6fc5187", "ID": "46fe8644f2572fd1e505364f7581e0c9dbc7f14640bd1fb6ce97714fb6fc5187",
"Parent": "2cd9c322cb78a55e8212aa3ea8425a4180236d7106938ec921d0935a4b8ca142" "Parent": "2cd9c322cb78a55e8212aa3ea8425a4180236d7106938ec921d0935a4b8ca142"
@ -251,7 +293,7 @@ and `Parent`. `Parent` may be an empty string, in which case there is no parent.
### /GraphDriver.Changes ### /GraphDriver.Changes
**Request**: **Request**:
``` ```json
{ {
"ID": "46fe8644f2572fd1e505364f7581e0c9dbc7f14640bd1fb6ce97714fb6fc5187", "ID": "46fe8644f2572fd1e505364f7581e0c9dbc7f14640bd1fb6ce97714fb6fc5187",
"Parent": "2cd9c322cb78a55e8212aa3ea8425a4180236d7106938ec921d0935a4b8ca142" "Parent": "2cd9c322cb78a55e8212aa3ea8425a4180236d7106938ec921d0935a4b8ca142"
@ -259,10 +301,10 @@ and `Parent`. `Parent` may be an empty string, in which case there is no parent.
``` ```
Get a list of changes between the filesystem layers specified by the `ID` and Get a list of changes between the filesystem layers specified by the `ID` and
`Parent`. `Parent` may be an empty string, in which case there is no parent. `Parent`. If `Parent` is an empty string, there is no parent.
**Response**: **Response**:
``` ```json
{ {
"Changes": [{}], "Changes": [{}],
"Err": "" "Err": ""
@ -270,7 +312,7 @@ Get a list of changes between the filesystem layers specified by the `ID` and
``` ```
Respond with a list of changes. The structure of a change is: Respond with a list of changes. The structure of a change is:
``` ```json
"Path": "/some/path", "Path": "/some/path",
"Kind": 0, "Kind": 0,
``` ```
@ -300,7 +342,7 @@ and `Parent`
- parent (required)- the `Parent` of the given `ID` - parent (required)- the `Parent` of the given `ID`
**Response**: **Response**:
``` ```json
{ {
"Size": 512366, "Size": 512366,
"Err": "" "Err": ""
@ -313,7 +355,7 @@ Respond with a non-empty string error if an error occurred.
### /GraphDriver.DiffSize ### /GraphDriver.DiffSize
**Request**: **Request**:
``` ```json
{ {
"ID": "46fe8644f2572fd1e505364f7581e0c9dbc7f14640bd1fb6ce97714fb6fc5187", "ID": "46fe8644f2572fd1e505364f7581e0c9dbc7f14640bd1fb6ce97714fb6fc5187",
"Parent": "2cd9c322cb78a55e8212aa3ea8425a4180236d7106938ec921d0935a4b8ca142" "Parent": "2cd9c322cb78a55e8212aa3ea8425a4180236d7106938ec921d0935a4b8ca142"
@ -323,7 +365,7 @@ Respond with a non-empty string error if an error occurred.
Calculate the changes between the specified `ID` Calculate the changes between the specified `ID`
**Response**: **Response**:
``` ```json
{ {
"Size": 512366, "Size": 512366,
"Err": "" "Err": ""

View file

@ -236,7 +236,7 @@ func (s *DockerDaemonSuite) TestVolumePlugin(c *check.C) {
} }
func (s *DockerDaemonSuite) TestGraphdriverPlugin(c *check.C) { func (s *DockerDaemonSuite) TestGraphdriverPlugin(c *check.C) {
testRequires(c, Network, IsAmd64, DaemonIsLinux, overlay2Supported) testRequires(c, Network, IsAmd64, DaemonIsLinux, overlay2Supported, ExperimentalDaemon)
s.d.Start(c) s.d.Start(c)

View file

@ -45,17 +45,18 @@ type StoreOptions struct {
UIDMaps []idtools.IDMap UIDMaps []idtools.IDMap
GIDMaps []idtools.IDMap GIDMaps []idtools.IDMap
PluginGetter plugingetter.PluginGetter PluginGetter plugingetter.PluginGetter
ExperimentalEnabled bool
} }
// NewStoreFromOptions creates a new Store instance // NewStoreFromOptions creates a new Store instance
func NewStoreFromOptions(options StoreOptions) (Store, error) { func NewStoreFromOptions(options StoreOptions) (Store, error) {
driver, err := graphdriver.New( driver, err := graphdriver.New(options.GraphDriver, options.PluginGetter, graphdriver.Options{
options.StorePath, Root: options.StorePath,
options.GraphDriver, DriverOptions: options.GraphDriverOptions,
options.GraphDriverOptions, UIDMaps: options.UIDMaps,
options.UIDMaps, GIDMaps: options.GIDMaps,
options.GIDMaps, ExperimentalEnabled: options.ExperimentalEnabled,
options.PluginGetter) })
if err != nil { if err != nil {
return nil, fmt.Errorf("error initializing graphdriver: %v", err) return nil, fmt.Errorf("error initializing graphdriver: %v", err)
} }

View file

@ -39,7 +39,8 @@ func newVFSGraphDriver(td string) (graphdriver.Driver, error) {
}, },
} }
return graphdriver.GetDriver("vfs", td, nil, uidMap, gidMap, nil) options := graphdriver.Options{Root: td, UIDMaps: uidMap, GIDMaps: gidMap}
return graphdriver.GetDriver("vfs", nil, options)
} }
func newTestGraphDriver(t *testing.T) (graphdriver.Driver, func()) { func newTestGraphDriver(t *testing.T) (graphdriver.Driver, func()) {