For API < v1.52:
- In container inspect:
- Restore GraphDriver when a snapshotter is used.
- Remove field Storage
- Related to commit efa077848f912b1c8febe579f345387e38008eb0
- In image inspect:
- Restore GraphDriver when a snapshotter is used.
- Related to commit c441b2ef19feb9ce2b97eb0ebd40e0b1a45344a7
Co-authored-by: Sebastiaan van Stijn <github@gone.nl>
Signed-off-by: Rob Murray <rob.murray@docker.com>
| ... | ... |
@@ -12,6 +12,7 @@ import ( |
| 12 | 12 |
"github.com/distribution/reference" |
| 13 | 13 |
dockerspec "github.com/moby/docker-image-spec/specs-go/v1" |
| 14 | 14 |
imagetypes "github.com/moby/moby/api/types/image" |
| 15 |
+ "github.com/moby/moby/api/types/storage" |
|
| 15 | 16 |
"github.com/moby/moby/v2/daemon/server/imagebackend" |
| 16 | 17 |
"github.com/moby/moby/v2/internal/sliceutil" |
| 17 | 18 |
ocispec "github.com/opencontainers/image-spec/specs-go/v1" |
| ... | ... |
@@ -98,6 +99,9 @@ func (i *ImageService) ImageInspect(ctx context.Context, refOrID string, opts im |
| 98 | 98 |
}, |
| 99 | 99 |
}, |
| 100 | 100 |
Parent: parent, // field is deprecated with the legacy builder, but returned by the API if present. |
| 101 |
+ |
|
| 102 |
+ // GraphDriver is omitted in API v1.52 unless using a graphdriver. |
|
| 103 |
+ GraphDriverLegacy: &storage.DriverData{Name: i.snapshotter},
|
|
| 101 | 104 |
} |
| 102 | 105 |
|
| 103 | 106 |
if multi.Best != nil {
|
| ... | ... |
@@ -7,6 +7,7 @@ import ( |
| 7 | 7 |
"github.com/moby/moby/api/types/container" |
| 8 | 8 |
imagetypes "github.com/moby/moby/api/types/image" |
| 9 | 9 |
"github.com/moby/moby/api/types/registry" |
| 10 |
+ "github.com/moby/moby/api/types/storage" |
|
| 10 | 11 |
"github.com/moby/moby/v2/daemon/internal/filters" |
| 11 | 12 |
ocispec "github.com/opencontainers/image-spec/specs-go/v1" |
| 12 | 13 |
) |
| ... | ... |
@@ -92,4 +93,8 @@ type InspectData struct {
|
| 92 | 92 |
// |
| 93 | 93 |
// This field is removed in API v1.45, but used for API <= v1.44 responses. |
| 94 | 94 |
ContainerConfig *container.Config |
| 95 |
+ |
|
| 96 |
+ // GraphDriverLegacy is used for API versions < v1.52, which included the |
|
| 97 |
+ // name of the snapshotter the GraphDriver field. |
|
| 98 |
+ GraphDriverLegacy *storage.DriverData |
|
| 95 | 99 |
} |
| ... | ... |
@@ -5,6 +5,7 @@ import ( |
| 5 | 5 |
"net/http" |
| 6 | 6 |
|
| 7 | 7 |
"github.com/moby/moby/api/types/container" |
| 8 |
+ "github.com/moby/moby/api/types/storage" |
|
| 8 | 9 |
"github.com/moby/moby/api/types/versions" |
| 9 | 10 |
"github.com/moby/moby/v2/daemon/internal/compat" |
| 10 | 11 |
"github.com/moby/moby/v2/daemon/internal/stringid" |
| ... | ... |
@@ -69,6 +70,15 @@ func (c *containerRouter) getContainersByName(ctx context.Context, w http.Respon |
| 69 | 69 |
}, |
| 70 | 70 |
})) |
| 71 | 71 |
} |
| 72 |
+ |
|
| 73 |
+ // Restore the GraphDriver field, now omitted when a snapshotter is used. |
|
| 74 |
+ // Remove the Storage field that replaced it. |
|
| 75 |
+ if ctr.GraphDriver == nil && ctr.Storage != nil && ctr.Storage.RootFS != nil && ctr.Storage.RootFS.Snapshot != nil {
|
|
| 76 |
+ ctr.GraphDriver = &storage.DriverData{
|
|
| 77 |
+ Name: ctr.Storage.RootFS.Snapshot.Name, |
|
| 78 |
+ } |
|
| 79 |
+ ctr.Storage = nil |
|
| 80 |
+ } |
|
| 72 | 81 |
} |
| 73 | 82 |
|
| 74 | 83 |
return httputils.WriteJSON(w, http.StatusOK, compat.Wrap(ctr, wrapOpts...)) |
| ... | ... |
@@ -440,6 +440,11 @@ func (ir *imageRouter) getImagesByName(ctx context.Context, w http.ResponseWrite |
| 440 | 440 |
"Config": legacyConfigFields["v1.50-v1.51"], |
| 441 | 441 |
})) |
| 442 | 442 |
} |
| 443 |
+ |
|
| 444 |
+ // Restore the GraphDriver field, now omitted when a snapshotter is used. |
|
| 445 |
+ if imageInspect.GraphDriver == nil && inspectData.GraphDriverLegacy != nil {
|
|
| 446 |
+ imageInspect.GraphDriver = inspectData.GraphDriverLegacy |
|
| 447 |
+ } |
|
| 443 | 448 |
} else {
|
| 444 | 449 |
if inspectData.Parent != "" {
|
| 445 | 450 |
// field is deprecated, but still included in response when present (built with legacy builder). |
| ... | ... |
@@ -19,16 +19,10 @@ func (s *DockerAPISuite) TestInspectAPIContainerResponse(c *testing.T) {
|
| 19 | 19 |
|
| 20 | 20 |
keysBase := []string{
|
| 21 | 21 |
"Id", "State", "Created", "Path", "Args", "Config", "Image", "NetworkSettings", |
| 22 |
- "ResolvConfPath", "HostnamePath", "HostsPath", "LogPath", "Name", "Driver", "MountLabel", "ProcessLabel", |
|
| 22 |
+ "ResolvConfPath", "HostnamePath", "HostsPath", "LogPath", "Name", "Driver", "MountLabel", "ProcessLabel", "GraphDriver", |
|
| 23 | 23 |
"Mounts", |
| 24 | 24 |
} |
| 25 | 25 |
|
| 26 |
- if testEnv.UsingSnapshotter() {
|
|
| 27 |
- keysBase = append(keysBase, "Storage") |
|
| 28 |
- } else {
|
|
| 29 |
- keysBase = append(keysBase, "GraphDriver") |
|
| 30 |
- } |
|
| 31 |
- |
|
| 32 | 26 |
cases := []struct {
|
| 33 | 27 |
version string |
| 34 | 28 |
keys []string |
| ... | ... |
@@ -4,6 +4,8 @@ import ( |
| 4 | 4 |
"testing" |
| 5 | 5 |
|
| 6 | 6 |
containertypes "github.com/moby/moby/api/types/container" |
| 7 |
+ "github.com/moby/moby/api/types/storage" |
|
| 8 |
+ "github.com/moby/moby/client" |
|
| 7 | 9 |
"github.com/moby/moby/v2/internal/testutil" |
| 8 | 10 |
"github.com/moby/moby/v2/internal/testutil/daemon" |
| 9 | 11 |
"gotest.tools/v3/assert" |
| ... | ... |
@@ -84,3 +86,91 @@ func TestGraphDriverPersistence(t *testing.T) {
|
| 84 | 84 |
assert.Check(t, containerInspect.GraphDriver != nil, "GraphDriver should be set for graphdriver backend") |
| 85 | 85 |
assert.Check(t, is.Equal(containerInspect.GraphDriver.Name, prevDriver), "Container graphdriver data should match") |
| 86 | 86 |
} |
| 87 |
+ |
|
| 88 |
+// TestInspectGraphDriverAPIBC checks API backward compatibility of the GraphDriver field in image/container inspect. |
|
| 89 |
+func TestInspectGraphDriverAPIBC(t *testing.T) {
|
|
| 90 |
+ skip.If(t, testEnv.DaemonInfo.OSType == "windows", "Windows does not support running sub-daemons") |
|
| 91 |
+ t.Setenv("DOCKER_DRIVER", "")
|
|
| 92 |
+ t.Setenv("DOCKER_GRAPHDRIVER", "")
|
|
| 93 |
+ t.Setenv("TEST_INTEGRATION_USE_GRAPHDRIVER", "")
|
|
| 94 |
+ ctx := testutil.StartSpan(baseContext, t) |
|
| 95 |
+ |
|
| 96 |
+ tests := []struct {
|
|
| 97 |
+ name string |
|
| 98 |
+ apiVersion string |
|
| 99 |
+ storageDriver string |
|
| 100 |
+ |
|
| 101 |
+ expContainerdSnapshotter bool |
|
| 102 |
+ expGraphDriver string |
|
| 103 |
+ expRootFSStorage bool |
|
| 104 |
+ }{
|
|
| 105 |
+ {
|
|
| 106 |
+ name: "vCurrent/containerd", |
|
| 107 |
+ expContainerdSnapshotter: true, |
|
| 108 |
+ expRootFSStorage: true, |
|
| 109 |
+ }, |
|
| 110 |
+ {
|
|
| 111 |
+ name: "v1.51/containerd", |
|
| 112 |
+ apiVersion: "v1.51", |
|
| 113 |
+ expContainerdSnapshotter: true, |
|
| 114 |
+ expGraphDriver: "overlayfs", |
|
| 115 |
+ }, |
|
| 116 |
+ {
|
|
| 117 |
+ name: "vCurrent/graphdriver", |
|
| 118 |
+ storageDriver: "vfs", |
|
| 119 |
+ expGraphDriver: "vfs", |
|
| 120 |
+ }, |
|
| 121 |
+ } |
|
| 122 |
+ |
|
| 123 |
+ for _, tc := range tests {
|
|
| 124 |
+ t.Run(tc.name, func(t *testing.T) {
|
|
| 125 |
+ d := daemon.New(t) |
|
| 126 |
+ defer d.Stop(t) |
|
| 127 |
+ d.StartWithBusybox(ctx, t, "--iptables=false", "--ip6tables=false", "--storage-driver="+tc.storageDriver) |
|
| 128 |
+ c := d.NewClientT(t, client.WithVersion(tc.apiVersion)) |
|
| 129 |
+ |
|
| 130 |
+ // Check selection of containerd / storage-driver worked. |
|
| 131 |
+ info := d.Info(t) |
|
| 132 |
+ if tc.expContainerdSnapshotter {
|
|
| 133 |
+ assert.Check(t, is.Equal(info.Driver, "overlayfs")) |
|
| 134 |
+ assert.Check(t, is.Equal(info.DriverStatus[0][0], "driver-type")) |
|
| 135 |
+ assert.Check(t, is.Equal(info.DriverStatus[0][1], "io.containerd.snapshotter.v1")) |
|
| 136 |
+ } else {
|
|
| 137 |
+ assert.Check(t, is.Equal(info.Driver, "vfs")) |
|
| 138 |
+ assert.Check(t, is.Len(info.DriverStatus, 0)) |
|
| 139 |
+ } |
|
| 140 |
+ |
|
| 141 |
+ const testImage = "busybox:latest" |
|
| 142 |
+ ctr, err := c.ContainerCreate(ctx, &containertypes.Config{Image: testImage}, nil, nil, nil, "test-container")
|
|
| 143 |
+ assert.NilError(t, err) |
|
| 144 |
+ defer func() { _ = c.ContainerRemove(ctx, ctr.ID, client.ContainerRemoveOptions{Force: true}) }()
|
|
| 145 |
+ |
|
| 146 |
+ if imageInspect, err := c.ImageInspect(ctx, testImage); assert.Check(t, err) {
|
|
| 147 |
+ if tc.expGraphDriver != "" {
|
|
| 148 |
+ if assert.Check(t, imageInspect.GraphDriver != nil) {
|
|
| 149 |
+ assert.Check(t, is.Equal(imageInspect.GraphDriver.Name, tc.expGraphDriver)) |
|
| 150 |
+ } |
|
| 151 |
+ } else {
|
|
| 152 |
+ assert.Check(t, is.Nil(imageInspect.GraphDriver)) |
|
| 153 |
+ } |
|
| 154 |
+ } |
|
| 155 |
+ |
|
| 156 |
+ if containerInspect, err := c.ContainerInspect(ctx, ctr.ID); assert.Check(t, err) {
|
|
| 157 |
+ if tc.expGraphDriver != "" {
|
|
| 158 |
+ if assert.Check(t, containerInspect.GraphDriver != nil) {
|
|
| 159 |
+ assert.Check(t, is.Equal(containerInspect.GraphDriver.Name, tc.expGraphDriver)) |
|
| 160 |
+ } |
|
| 161 |
+ } else {
|
|
| 162 |
+ assert.Check(t, is.Nil(containerInspect.GraphDriver)) |
|
| 163 |
+ } |
|
| 164 |
+ if tc.expRootFSStorage {
|
|
| 165 |
+ assert.DeepEqual(t, containerInspect.Storage, &storage.Storage{
|
|
| 166 |
+ RootFS: &storage.RootFSStorage{Snapshot: &storage.RootFSStorageSnapshot{Name: "overlayfs"}},
|
|
| 167 |
+ }) |
|
| 168 |
+ } else {
|
|
| 169 |
+ assert.Check(t, is.Nil(containerInspect.Storage)) |
|
| 170 |
+ } |
|
| 171 |
+ } |
|
| 172 |
+ }) |
|
| 173 |
+ } |
|
| 174 |
+} |