Merge pull request #43831 from thaJeztah/containerd_restructure
containerd-integration: restructure code to match existing implementation
This commit is contained in:
commit
992961c56c
20 changed files with 491 additions and 399 deletions
10
daemon/containerd/cache.go
Normal file
10
daemon/containerd/cache.go
Normal file
|
@ -0,0 +1,10 @@
|
|||
package containerd
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/builder"
|
||||
)
|
||||
|
||||
// MakeImageCache creates a stateful image cache.
|
||||
func (i *ImageService) MakeImageCache(cacheFrom []string) builder.ImageCache {
|
||||
panic("not implemented")
|
||||
}
|
11
daemon/containerd/image.go
Normal file
11
daemon/containerd/image.go
Normal file
|
@ -0,0 +1,11 @@
|
|||
package containerd
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/image"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
// GetImage returns an image corresponding to the image referred to by refOrID.
|
||||
func (i *ImageService) GetImage(refOrID string, platform *specs.Platform) (retImg *image.Image, retErr error) {
|
||||
panic("not implemented")
|
||||
}
|
22
daemon/containerd/image_builder.go
Normal file
22
daemon/containerd/image_builder.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
package containerd
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/builder"
|
||||
)
|
||||
|
||||
// GetImageAndReleasableLayer returns an image and releaseable layer for a
|
||||
// reference or ID. Every call to GetImageAndReleasableLayer MUST call
|
||||
// releasableLayer.Release() to prevent leaking of layers.
|
||||
func (i *ImageService) GetImageAndReleasableLayer(ctx context.Context, refOrID string, opts backend.GetImageAndLayerOptions) (builder.Image, builder.ROLayer, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// CreateImage creates a new image by adding a config and ID to the image store.
|
||||
// This is similar to LoadImage() except that it receives JSON encoded bytes of
|
||||
// an image instead of a tar archive.
|
||||
func (i *ImageService) CreateImage(config []byte, parent string) (builder.Image, error) {
|
||||
panic("not implemented")
|
||||
}
|
24
daemon/containerd/image_commit.go
Normal file
24
daemon/containerd/image_commit.go
Normal file
|
@ -0,0 +1,24 @@
|
|||
package containerd
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/image"
|
||||
)
|
||||
|
||||
// CommitImage creates a new image from a commit config.
|
||||
func (i *ImageService) CommitImage(c backend.CommitConfig) (image.ID, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// CommitBuildStep is used by the builder to create an image for each step in
|
||||
// the build.
|
||||
//
|
||||
// This method is different from CreateImageFromContainer:
|
||||
// - it doesn't attempt to validate container state
|
||||
// - it doesn't send a commit action to metrics
|
||||
// - it doesn't log a container commit event
|
||||
//
|
||||
// This is a temporary shim. Should be removed when builder stops using commit.
|
||||
func (i *ImageService) CommitBuildStep(c backend.CommitConfig) (image.ID, error) {
|
||||
panic("not implemented")
|
||||
}
|
40
daemon/containerd/image_delete.go
Normal file
40
daemon/containerd/image_delete.go
Normal file
|
@ -0,0 +1,40 @@
|
|||
package containerd
|
||||
|
||||
import "github.com/docker/docker/api/types"
|
||||
|
||||
// ImageDelete deletes the image referenced by the given imageRef from this
|
||||
// daemon. The given imageRef can be an image ID, ID prefix, or a repository
|
||||
// reference (with an optional tag or digest, defaulting to the tag name
|
||||
// "latest"). There is differing behavior depending on whether the given
|
||||
// imageRef is a repository reference or not.
|
||||
//
|
||||
// If the given imageRef is a repository reference then that repository
|
||||
// reference will be removed. However, if there exists any containers which
|
||||
// were created using the same image reference then the repository reference
|
||||
// cannot be removed unless either there are other repository references to the
|
||||
// same image or force is true. Following removal of the repository reference,
|
||||
// the referenced image itself will attempt to be deleted as described below
|
||||
// but quietly, meaning any image delete conflicts will cause the image to not
|
||||
// be deleted and the conflict will not be reported.
|
||||
//
|
||||
// There may be conflicts preventing deletion of an image and these conflicts
|
||||
// are divided into two categories grouped by their severity:
|
||||
//
|
||||
// Hard Conflict:
|
||||
// - a pull or build using the image.
|
||||
// - any descendant image.
|
||||
// - any running container using the image.
|
||||
//
|
||||
// Soft Conflict:
|
||||
// - any stopped container using the image.
|
||||
// - any repository tag or digest references to the image.
|
||||
//
|
||||
// The image cannot be removed if there are any hard conflicts and can be
|
||||
// removed if there are soft conflicts only if force is true.
|
||||
//
|
||||
// If prune is true, ancestor images will each attempt to be deleted quietly,
|
||||
// meaning any delete conflicts will cause the image to not be deleted and the
|
||||
// conflict will not be reported.
|
||||
func (i *ImageService) ImageDelete(imageRef string, force, prune bool) ([]types.ImageDeleteResponseItem, error) {
|
||||
panic("not implemented")
|
||||
}
|
13
daemon/containerd/image_events.go
Normal file
13
daemon/containerd/image_events.go
Normal file
|
@ -0,0 +1,13 @@
|
|||
package containerd
|
||||
|
||||
// LogImageEvent generates an event related to an image with only the
|
||||
// default attributes.
|
||||
func (i *ImageService) LogImageEvent(imageID, refName, action string) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// LogImageEventWithAttributes generates an event related to an image with
|
||||
// specific given attributes.
|
||||
func (i *ImageService) LogImageEventWithAttributes(imageID, refName, action string, attributes map[string]string) {
|
||||
panic("not implemented")
|
||||
}
|
19
daemon/containerd/image_exporter.go
Normal file
19
daemon/containerd/image_exporter.go
Normal file
|
@ -0,0 +1,19 @@
|
|||
package containerd
|
||||
|
||||
import "io"
|
||||
|
||||
// ExportImage exports a list of images to the given output stream. The
|
||||
// exported images are archived into a tar when written to the output
|
||||
// stream. All images with the given tag and all versions containing
|
||||
// the same tag are exported. names is the set of tags to export, and
|
||||
// outStream is the writer which the images are written to.
|
||||
func (i *ImageService) ExportImage(names []string, outStream io.Writer) error {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// LoadImage uploads a set of images into the repository. This is the
|
||||
// complement of ExportImage. The input stream is an uncompressed tar
|
||||
// ball containing images and metadata.
|
||||
func (i *ImageService) LoadImage(inTar io.ReadCloser, outStream io.Writer, quiet bool) error {
|
||||
panic("not implemented")
|
||||
}
|
9
daemon/containerd/image_history.go
Normal file
9
daemon/containerd/image_history.go
Normal file
|
@ -0,0 +1,9 @@
|
|||
package containerd
|
||||
|
||||
import imagetype "github.com/docker/docker/api/types/image"
|
||||
|
||||
// ImageHistory returns a slice of ImageHistory structures for the specified
|
||||
// image name by walking the image lineage.
|
||||
func (i *ImageService) ImageHistory(name string) ([]*imagetype.HistoryResponseItem, error) {
|
||||
panic("not implemented")
|
||||
}
|
15
daemon/containerd/image_import.go
Normal file
15
daemon/containerd/image_import.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
package containerd
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
// ImportImage imports an image, getting the archived layer data either from
|
||||
// inConfig (if src is "-"), or from a URI specified in src. Progress output is
|
||||
// written to outStream. Repository and tag names can optionally be given in
|
||||
// the repo and tag arguments, respectively.
|
||||
func (i *ImageService) ImportImage(src string, repository string, platform *specs.Platform, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error {
|
||||
panic("not implemented")
|
||||
}
|
37
daemon/containerd/image_list.go
Normal file
37
daemon/containerd/image_list.go
Normal file
|
@ -0,0 +1,37 @@
|
|||
package containerd
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
)
|
||||
|
||||
// Images returns a filtered list of images.
|
||||
func (i *ImageService) Images(ctx context.Context, opts types.ImageListOptions) ([]*types.ImageSummary, error) {
|
||||
imgs, err := i.client.ListImages(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ret []*types.ImageSummary
|
||||
for _, img := range imgs {
|
||||
size, err := img.Size(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret = append(ret, &types.ImageSummary{
|
||||
RepoDigests: []string{img.Name() + "@" + img.Target().Digest.String()}, // "hello-world@sha256:bfea6278a0a267fad2634554f4f0c6f31981eea41c553fdf5a83e95a41d40c38"},
|
||||
RepoTags: []string{img.Name()},
|
||||
Containers: -1,
|
||||
ParentID: "",
|
||||
SharedSize: -1,
|
||||
VirtualSize: 10,
|
||||
ID: img.Target().Digest.String(),
|
||||
Created: img.Metadata().CreatedAt.Unix(),
|
||||
Size: size,
|
||||
})
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
13
daemon/containerd/image_prune.go
Normal file
13
daemon/containerd/image_prune.go
Normal file
|
@ -0,0 +1,13 @@
|
|||
package containerd
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
)
|
||||
|
||||
// ImagesPrune removes unused images
|
||||
func (i *ImageService) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (*types.ImagesPruneReport, error) {
|
||||
panic("not implemented")
|
||||
}
|
51
daemon/containerd/image_pull.go
Normal file
51
daemon/containerd/image_pull.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
package containerd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/opencontainers/go-digest"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
// PullImage initiates a pull operation. image is the repository name to pull, and
|
||||
// tagOrDigest may be either empty, or indicate a specific tag or digest to pull.
|
||||
func (i *ImageService) PullImage(ctx context.Context, image, tagOrDigest string, platform *specs.Platform, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
|
||||
var opts []containerd.RemoteOpt
|
||||
if platform != nil {
|
||||
opts = append(opts, containerd.WithPlatform(platforms.Format(*platform)))
|
||||
}
|
||||
ref, err := reference.ParseNormalizedNamed(image)
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
|
||||
// TODO(thaJeztah) this could use a WithTagOrDigest() utility
|
||||
if tagOrDigest != "" {
|
||||
// The "tag" could actually be a digest.
|
||||
var dgst digest.Digest
|
||||
dgst, err = digest.Parse(tagOrDigest)
|
||||
if err == nil {
|
||||
ref, err = reference.WithDigest(reference.TrimNamed(ref), dgst)
|
||||
} else {
|
||||
ref, err = reference.WithTag(ref, tagOrDigest)
|
||||
}
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
}
|
||||
|
||||
_, err = i.client.Pull(ctx, ref.String(), opts...)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetRepository returns a repository from the registry.
|
||||
func (i *ImageService) GetRepository(ctx context.Context, ref reference.Named, authConfig *types.AuthConfig) (distribution.Repository, error) {
|
||||
panic("not implemented")
|
||||
}
|
13
daemon/containerd/image_push.go
Normal file
13
daemon/containerd/image_push.go
Normal file
|
@ -0,0 +1,13 @@
|
|||
package containerd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
)
|
||||
|
||||
// PushImage initiates a push operation on the repository named localName.
|
||||
func (i *ImageService) PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
|
||||
panic("not implemented")
|
||||
}
|
18
daemon/containerd/image_search.go
Normal file
18
daemon/containerd/image_search.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
package containerd
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
)
|
||||
|
||||
// SearchRegistryForImages queries the registry for images matching
|
||||
// term. authConfig is used to login.
|
||||
//
|
||||
// TODO: this could be implemented in a registry service instead of the image
|
||||
// service.
|
||||
func (i *ImageService) SearchRegistryForImages(ctx context.Context, searchFilters filters.Args, term string, limit int, authConfig *types.AuthConfig, metaHeaders map[string][]string) (*registrytypes.SearchResults, error) {
|
||||
panic("not implemented")
|
||||
}
|
11
daemon/containerd/image_squash.go
Normal file
11
daemon/containerd/image_squash.go
Normal file
|
@ -0,0 +1,11 @@
|
|||
package containerd
|
||||
|
||||
// SquashImage creates a new image with the diff of the specified image and
|
||||
// the specified parent. This new image contains only the layers from its
|
||||
// parent + 1 extra layer which contains the diff of all the layers in between.
|
||||
// The existing image(s) is not destroyed. If no parent is specified, a new
|
||||
// image with the diff of all the specified image's layers merged into a new
|
||||
// layer that has no parents.
|
||||
func (i *ImageService) SquashImage(id, parent string) (string, error) {
|
||||
panic("not implemented")
|
||||
}
|
17
daemon/containerd/image_tag.go
Normal file
17
daemon/containerd/image_tag.go
Normal file
|
@ -0,0 +1,17 @@
|
|||
package containerd
|
||||
|
||||
import (
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/image"
|
||||
)
|
||||
|
||||
// TagImage creates the tag specified by newTag, pointing to the image named
|
||||
// imageName (alternatively, imageName can also be an image ID).
|
||||
func (i *ImageService) TagImage(imageName, repository, tag string) (string, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// TagImageWithReference adds the given reference to the image ID provided.
|
||||
func (i *ImageService) TagImageWithReference(imageID image.ID, newTag reference.Named) error {
|
||||
panic("not implemented")
|
||||
}
|
|
@ -2,25 +2,13 @@ package containerd
|
|||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
imagetype "github.com/docker/docker/api/types/image"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/builder"
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/daemon/images"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/opencontainers/go-digest"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
// ImageService implements daemon.ImageService
|
||||
|
@ -35,298 +23,15 @@ func NewService(c *containerd.Client) *ImageService {
|
|||
}
|
||||
}
|
||||
|
||||
// PullImage initiates a pull operation. image is the repository name to pull, and
|
||||
// tagOrDigest may be either empty, or indicate a specific tag or digest to pull.
|
||||
func (cs *ImageService) PullImage(ctx context.Context, image, tagOrDigest string, platform *ocispec.Platform, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
|
||||
var opts []containerd.RemoteOpt
|
||||
if platform != nil {
|
||||
opts = append(opts, containerd.WithPlatform(platforms.Format(*platform)))
|
||||
}
|
||||
ref, err := reference.ParseNormalizedNamed(image)
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
|
||||
// TODO(thaJeztah) this could use a WithTagOrDigest() utility
|
||||
if tagOrDigest != "" {
|
||||
// The "tag" could actually be a digest.
|
||||
var dgst digest.Digest
|
||||
dgst, err = digest.Parse(tagOrDigest)
|
||||
if err == nil {
|
||||
ref, err = reference.WithDigest(reference.TrimNamed(ref), dgst)
|
||||
} else {
|
||||
ref, err = reference.WithTag(ref, tagOrDigest)
|
||||
}
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
}
|
||||
|
||||
_, err = cs.client.Pull(ctx, ref.String(), opts...)
|
||||
return err
|
||||
}
|
||||
|
||||
// Images returns a filtered list of images.
|
||||
func (cs *ImageService) Images(ctx context.Context, opts types.ImageListOptions) ([]*types.ImageSummary, error) {
|
||||
imgs, err := cs.client.ListImages(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ret []*types.ImageSummary
|
||||
for _, img := range imgs {
|
||||
size, err := img.Size(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret = append(ret, &types.ImageSummary{
|
||||
RepoDigests: []string{img.Name() + "@" + img.Target().Digest.String()}, // "hello-world@sha256:bfea6278a0a267fad2634554f4f0c6f31981eea41c553fdf5a83e95a41d40c38"},
|
||||
RepoTags: []string{img.Name()},
|
||||
Containers: -1,
|
||||
ParentID: "",
|
||||
SharedSize: -1,
|
||||
VirtualSize: 10,
|
||||
ID: img.Target().Digest.String(),
|
||||
Created: img.Metadata().CreatedAt.Unix(),
|
||||
Size: size,
|
||||
})
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// LogImageEvent generates an event related to an image with only the
|
||||
// default attributes.
|
||||
func (cs *ImageService) LogImageEvent(imageID, refName, action string) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// LogImageEventWithAttributes generates an event related to an image with
|
||||
// specific given attributes.
|
||||
func (cs *ImageService) LogImageEventWithAttributes(imageID, refName, action string, attributes map[string]string) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// GetLayerFolders returns the layer folders from an image RootFS.
|
||||
func (cs *ImageService) GetLayerFolders(img *image.Image, rwLayer layer.RWLayer) ([]string, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// GetLayerByID returns a layer by ID
|
||||
// called from daemon.go Daemon.restore(), and Daemon.containerExport().
|
||||
func (cs *ImageService) GetLayerByID(string) (layer.RWLayer, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// GetLayerMountID returns the mount ID for a layer
|
||||
// called from daemon.go Daemon.Shutdown(), and Daemon.Cleanup() (cleanup is actually continerCleanup)
|
||||
// TODO: needs to be refactored to Unmount (see callers), or removed and replaced with GetLayerByID
|
||||
func (cs *ImageService) GetLayerMountID(string) (string, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// Cleanup resources before the process is shutdown.
|
||||
// called from daemon.go Daemon.Shutdown()
|
||||
func (cs *ImageService) Cleanup() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GraphDriverName returns the name of the graph drvier
|
||||
// moved from Daemon.GraphDriverName, used by:
|
||||
// - newContainer
|
||||
// - to report an error in Daemon.Mount(container)
|
||||
func (cs *ImageService) GraphDriverName() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// CommitBuildStep is used by the builder to create an image for each step in
|
||||
// the build.
|
||||
//
|
||||
// This method is different from CreateImageFromContainer:
|
||||
// - it doesn't attempt to validate container state
|
||||
// - it doesn't send a commit action to metrics
|
||||
// - it doesn't log a container commit event
|
||||
//
|
||||
// This is a temporary shim. Should be removed when builder stops using commit.
|
||||
func (cs *ImageService) CommitBuildStep(c backend.CommitConfig) (image.ID, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// CreateImage creates a new image by adding a config and ID to the image store.
|
||||
// This is similar to LoadImage() except that it receives JSON encoded bytes of
|
||||
// an image instead of a tar archive.
|
||||
func (cs *ImageService) CreateImage(config []byte, parent string) (builder.Image, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// GetImageAndReleasableLayer returns an image and releaseable layer for a
|
||||
// eference or ID. Every call to GetImageAndReleasableLayer MUST call
|
||||
// releasableLayer.Release() to prevent leaking of layers.
|
||||
func (cs *ImageService) GetImageAndReleasableLayer(ctx context.Context, refOrID string, opts backend.GetImageAndLayerOptions) (builder.Image, builder.ROLayer, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// MakeImageCache creates a stateful image cache.
|
||||
func (cs *ImageService) MakeImageCache(sourceRefs []string) builder.ImageCache {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// TagImageWithReference adds the given reference to the image ID provided.
|
||||
func (cs *ImageService) TagImageWithReference(imageID image.ID, newTag reference.Named) error {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// SquashImage creates a new image with the diff of the specified image and
|
||||
// the specified parent. This new image contains only the layers from its
|
||||
// parent + 1 extra layer which contains the diff of all the layers in between.
|
||||
// The existing image(s) is not destroyed. If no parent is specified, a new
|
||||
// image with the diff of all the specified image's layers merged into a new
|
||||
// layer that has no parents.
|
||||
func (cs *ImageService) SquashImage(id, parent string) (string, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// ExportImage exports a list of images to the given output stream. The
|
||||
// exported images are archived into a tar when written to the output
|
||||
// stream. All images with the given tag and all versions containing
|
||||
// the same tag are exported. names is the set of tags to export, and
|
||||
// outStream is the writer which the images are written to.
|
||||
func (cs *ImageService) ExportImage(names []string, outStream io.Writer) error {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// ImageDelete deletes the image referenced by the given imageRef from this
|
||||
// daemon. The given imageRef can be an image ID, ID prefix, or a repository
|
||||
// reference (with an optional tag or digest, defaulting to the tag name
|
||||
// "latest"). There is differing behavior depending on whether the given
|
||||
// imageRef is a repository reference or not.
|
||||
//
|
||||
// If the given imageRef is a repository reference then that repository
|
||||
// reference will be removed. However, if there exists any containers which
|
||||
// were created using the same image reference then the repository reference
|
||||
// cannot be removed unless either there are other repository references to the
|
||||
// same image or force is true. Following removal of the repository reference,
|
||||
// the referenced image itself will attempt to be deleted as described below
|
||||
// but quietly, meaning any image delete conflicts will cause the image to not
|
||||
// be deleted and the conflict will not be reported.
|
||||
//
|
||||
// There may be conflicts preventing deletion of an image and these conflicts
|
||||
// are divided into two categories grouped by their severity:
|
||||
//
|
||||
// Hard Conflict:
|
||||
// - a pull or build using the image.
|
||||
// - any descendant image.
|
||||
// - any running container using the image.
|
||||
//
|
||||
// Soft Conflict:
|
||||
// - any stopped container using the image.
|
||||
// - any repository tag or digest references to the image.
|
||||
//
|
||||
// The image cannot be removed if there are any hard conflicts and can be
|
||||
// removed if there are soft conflicts only if force is true.
|
||||
//
|
||||
// If prune is true, ancestor images will each attempt to be deleted quietly,
|
||||
// meaning any delete conflicts will cause the image to not be deleted and the
|
||||
// conflict will not be reported.
|
||||
func (cs *ImageService) ImageDelete(imageRef string, force, prune bool) ([]types.ImageDeleteResponseItem, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// ImageHistory returns a slice of ImageHistory structures for the specified
|
||||
// image name by walking the image lineage.
|
||||
func (cs *ImageService) ImageHistory(name string) ([]*imagetype.HistoryResponseItem, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// ImagesPrune removes unused images
|
||||
func (cs *ImageService) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (*types.ImagesPruneReport, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// ImportImage imports an image, getting the archived layer data either from
|
||||
// inConfig (if src is "-"), or from a URI specified in src. Progress output is
|
||||
// written to outStream. Repository and tag names can optionally be given in
|
||||
// the repo and tag arguments, respectively.
|
||||
func (cs *ImageService) ImportImage(src string, repository string, platform *ocispec.Platform, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// LoadImage uploads a set of images into the repository. This is the
|
||||
// complement of ExportImage. The input stream is an uncompressed tar
|
||||
// ball containing images and metadata.
|
||||
func (cs *ImageService) LoadImage(inTar io.ReadCloser, outStream io.Writer, quiet bool) error {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// PushImage initiates a push operation on the repository named localName.
|
||||
func (cs *ImageService) PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// SearchRegistryForImages queries the registry for images matching
|
||||
// term. authConfig is used to login.
|
||||
//
|
||||
// TODO: this could be implemented in a registry service instead of the image
|
||||
// service.
|
||||
func (cs *ImageService) SearchRegistryForImages(ctx context.Context, searchFilters filters.Args, term string, limit int, authConfig *types.AuthConfig, metaHeaders map[string][]string) (*registrytypes.SearchResults, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// TagImage creates the tag specified by newTag, pointing to the image named
|
||||
// imageName (alternatively, imageName can also be an image ID).
|
||||
func (cs *ImageService) TagImage(imageName, repository, tag string) (string, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// GetRepository returns a repository from the registry.
|
||||
func (cs *ImageService) GetRepository(context.Context, reference.Named, *types.AuthConfig) (distribution.Repository, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// ImageDiskUsage returns information about image data disk usage.
|
||||
func (cs *ImageService) ImageDiskUsage(ctx context.Context) ([]*types.ImageSummary, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// LayerDiskUsage returns the number of bytes used by layer stores
|
||||
// called from disk_usage.go
|
||||
func (cs *ImageService) LayerDiskUsage(ctx context.Context) (int64, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// ReleaseLayer releases a layer allowing it to be removed
|
||||
// called from delete.go Daemon.cleanupContainer(), and Daemon.containerExport()
|
||||
func (cs *ImageService) ReleaseLayer(rwlayer layer.RWLayer) error {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// CommitImage creates a new image from a commit config.
|
||||
func (cs *ImageService) CommitImage(c backend.CommitConfig) (image.ID, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// GetImage returns an image corresponding to the image referred to by refOrID.
|
||||
func (cs *ImageService) GetImage(refOrID string, platform *ocispec.Platform) (retImg *image.Image, retErr error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// CreateLayer creates a filesystem layer for a container.
|
||||
// called from create.go
|
||||
// TODO: accept an opt struct instead of container?
|
||||
func (cs *ImageService) CreateLayer(container *container.Container, initFunc layer.MountInit) (layer.RWLayer, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// DistributionServices return services controlling daemon image storage.
|
||||
func (cs *ImageService) DistributionServices() images.DistributionServices {
|
||||
func (i *ImageService) DistributionServices() images.DistributionServices {
|
||||
return images.DistributionServices{}
|
||||
}
|
||||
|
||||
// CountImages returns the number of images stored by ImageService
|
||||
// called from info.go
|
||||
func (cs *ImageService) CountImages() int {
|
||||
imgs, err := cs.client.ListImages(context.TODO())
|
||||
func (i *ImageService) CountImages() int {
|
||||
imgs, err := i.client.ListImages(context.TODO())
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
@ -334,27 +39,83 @@ func (cs *ImageService) CountImages() int {
|
|||
return len(imgs)
|
||||
}
|
||||
|
||||
// Children returns the children image.IDs for a parent image.
|
||||
// called from list.go to filter containers
|
||||
// TODO: refactor to expose an ancestry for image.ID?
|
||||
func (i *ImageService) Children(id image.ID) []image.ID {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// CreateLayer creates a filesystem layer for a container.
|
||||
// called from create.go
|
||||
// TODO: accept an opt struct instead of container?
|
||||
func (i *ImageService) CreateLayer(container *container.Container, initFunc layer.MountInit) (layer.RWLayer, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// GetLayerByID returns a layer by ID
|
||||
// called from daemon.go Daemon.restore(), and Daemon.containerExport().
|
||||
func (i *ImageService) GetLayerByID(cid string) (layer.RWLayer, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// LayerStoreStatus returns the status for each layer store
|
||||
// called from info.go
|
||||
func (cs *ImageService) LayerStoreStatus() [][2]string {
|
||||
func (i *ImageService) LayerStoreStatus() [][2]string {
|
||||
return [][2]string{}
|
||||
}
|
||||
|
||||
// GetContainerLayerSize returns the real size & virtual size of the container.
|
||||
func (cs *ImageService) GetContainerLayerSize(containerID string) (int64, int64) {
|
||||
// GetLayerMountID returns the mount ID for a layer
|
||||
// called from daemon.go Daemon.Shutdown(), and Daemon.Cleanup() (cleanup is actually continerCleanup)
|
||||
// TODO: needs to be refactored to Unmount (see callers), or removed and replaced with GetLayerByID
|
||||
func (i *ImageService) GetLayerMountID(cid string) (string, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// Cleanup resources before the process is shutdown.
|
||||
// called from daemon.go Daemon.Shutdown()
|
||||
func (i *ImageService) Cleanup() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GraphDriverName returns the name of the graph drvier
|
||||
// moved from Daemon.GraphDriverName, used by:
|
||||
// - newContainer
|
||||
// - to report an error in Daemon.Mount(container)
|
||||
func (i *ImageService) GraphDriverName() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// ReleaseLayer releases a layer allowing it to be removed
|
||||
// called from delete.go Daemon.cleanupContainer(), and Daemon.containerExport()
|
||||
func (i *ImageService) ReleaseLayer(rwlayer layer.RWLayer) error {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// LayerDiskUsage returns the number of bytes used by layer stores
|
||||
// called from disk_usage.go
|
||||
func (i *ImageService) LayerDiskUsage(ctx context.Context) (int64, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// ImageDiskUsage returns information about image data disk usage.
|
||||
func (i *ImageService) ImageDiskUsage(ctx context.Context) ([]*types.ImageSummary, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// UpdateConfig values
|
||||
//
|
||||
// called from reload.go
|
||||
func (cs *ImageService) UpdateConfig(maxDownloads, maxUploads int) {
|
||||
func (i *ImageService) UpdateConfig(maxDownloads, maxUploads int) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// Children returns the children image.IDs for a parent image.
|
||||
// called from list.go to filter containers
|
||||
// TODO: refactor to expose an ancestry for image.ID?
|
||||
func (cs *ImageService) Children(id image.ID) []image.ID {
|
||||
// GetLayerFolders returns the layer folders from an image RootFS.
|
||||
func (i *ImageService) GetLayerFolders(img *image.Image, rwLayer layer.RWLayer) ([]string, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// GetContainerLayerSize returns the real size & virtual size of the container.
|
||||
func (i *ImageService) GetContainerLayerSize(containerID string) (int64, int64) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
|
|
@ -2,12 +2,8 @@ package images // import "github.com/docker/docker/daemon/images"
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
|
@ -247,90 +243,6 @@ func (i *ImageService) Images(_ context.Context, opts types.ImageListOptions) ([
|
|||
return summaries, nil
|
||||
}
|
||||
|
||||
// SquashImage creates a new image with the diff of the specified image and the specified parent.
|
||||
// This new image contains only the layers from it's parent + 1 extra layer which contains the diff of all the layers in between.
|
||||
// The existing image(s) is not destroyed.
|
||||
// If no parent is specified, a new image with the diff of all the specified image's layers merged into a new layer that has no parents.
|
||||
func (i *ImageService) SquashImage(id, parent string) (string, error) {
|
||||
|
||||
var (
|
||||
img *image.Image
|
||||
err error
|
||||
)
|
||||
if img, err = i.imageStore.Get(image.ID(id)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var parentImg *image.Image
|
||||
var parentChainID layer.ChainID
|
||||
if len(parent) != 0 {
|
||||
parentImg, err = i.imageStore.Get(image.ID(parent))
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error getting specified parent layer")
|
||||
}
|
||||
parentChainID = parentImg.RootFS.ChainID()
|
||||
} else {
|
||||
rootFS := image.NewRootFS()
|
||||
parentImg = &image.Image{RootFS: rootFS}
|
||||
}
|
||||
l, err := i.layerStore.Get(img.RootFS.ChainID())
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error getting image layer")
|
||||
}
|
||||
defer i.layerStore.Release(l)
|
||||
|
||||
ts, err := l.TarStreamFrom(parentChainID)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "error getting tar stream to parent")
|
||||
}
|
||||
defer ts.Close()
|
||||
|
||||
newL, err := i.layerStore.Register(ts, parentChainID)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error registering layer")
|
||||
}
|
||||
defer i.layerStore.Release(newL)
|
||||
|
||||
newImage := *img
|
||||
newImage.RootFS = nil
|
||||
|
||||
rootFS := *parentImg.RootFS
|
||||
rootFS.DiffIDs = append(rootFS.DiffIDs, newL.DiffID())
|
||||
newImage.RootFS = &rootFS
|
||||
|
||||
for i, hi := range newImage.History {
|
||||
if i >= len(parentImg.History) {
|
||||
hi.EmptyLayer = true
|
||||
}
|
||||
newImage.History[i] = hi
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
var historyComment string
|
||||
if len(parent) > 0 {
|
||||
historyComment = fmt.Sprintf("merge %s to %s", id, parent)
|
||||
} else {
|
||||
historyComment = fmt.Sprintf("create new from %s", id)
|
||||
}
|
||||
|
||||
newImage.History = append(newImage.History, image.History{
|
||||
Created: now,
|
||||
Comment: historyComment,
|
||||
})
|
||||
newImage.Created = now
|
||||
|
||||
b, err := json.Marshal(&newImage)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error marshalling image config")
|
||||
}
|
||||
|
||||
newImgID, err := i.imageStore.Create(b)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error creating new image after squash")
|
||||
}
|
||||
return string(newImgID), nil
|
||||
}
|
||||
|
||||
func newImageSummary(image *image.Image, size int64) *types.ImageSummary {
|
||||
summary := &types.ImageSummary{
|
||||
ParentID: image.Parent.String(),
|
95
daemon/images/image_squash.go
Normal file
95
daemon/images/image_squash.go
Normal file
|
@ -0,0 +1,95 @@
|
|||
package images // import "github.com/docker/docker/daemon/images"
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// SquashImage creates a new image with the diff of the specified image and the specified parent.
|
||||
// This new image contains only the layers from it's parent + 1 extra layer which contains the diff of all the layers in between.
|
||||
// The existing image(s) is not destroyed.
|
||||
// If no parent is specified, a new image with the diff of all the specified image's layers merged into a new layer that has no parents.
|
||||
func (i *ImageService) SquashImage(id, parent string) (string, error) {
|
||||
|
||||
var (
|
||||
img *image.Image
|
||||
err error
|
||||
)
|
||||
if img, err = i.imageStore.Get(image.ID(id)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var parentImg *image.Image
|
||||
var parentChainID layer.ChainID
|
||||
if len(parent) != 0 {
|
||||
parentImg, err = i.imageStore.Get(image.ID(parent))
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error getting specified parent layer")
|
||||
}
|
||||
parentChainID = parentImg.RootFS.ChainID()
|
||||
} else {
|
||||
rootFS := image.NewRootFS()
|
||||
parentImg = &image.Image{RootFS: rootFS}
|
||||
}
|
||||
l, err := i.layerStore.Get(img.RootFS.ChainID())
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error getting image layer")
|
||||
}
|
||||
defer i.layerStore.Release(l)
|
||||
|
||||
ts, err := l.TarStreamFrom(parentChainID)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "error getting tar stream to parent")
|
||||
}
|
||||
defer ts.Close()
|
||||
|
||||
newL, err := i.layerStore.Register(ts, parentChainID)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error registering layer")
|
||||
}
|
||||
defer i.layerStore.Release(newL)
|
||||
|
||||
newImage := *img
|
||||
newImage.RootFS = nil
|
||||
|
||||
rootFS := *parentImg.RootFS
|
||||
rootFS.DiffIDs = append(rootFS.DiffIDs, newL.DiffID())
|
||||
newImage.RootFS = &rootFS
|
||||
|
||||
for i, hi := range newImage.History {
|
||||
if i >= len(parentImg.History) {
|
||||
hi.EmptyLayer = true
|
||||
}
|
||||
newImage.History[i] = hi
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
var historyComment string
|
||||
if len(parent) > 0 {
|
||||
historyComment = fmt.Sprintf("merge %s to %s", id, parent)
|
||||
} else {
|
||||
historyComment = fmt.Sprintf("create new from %s", id)
|
||||
}
|
||||
|
||||
newImage.History = append(newImage.History, image.History{
|
||||
Created: now,
|
||||
Comment: historyComment,
|
||||
})
|
||||
newImage.Created = now
|
||||
|
||||
b, err := json.Marshal(&newImage)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error marshalling image config")
|
||||
}
|
||||
|
||||
newImgID, err := i.imageStore.Create(b)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error creating new image after squash")
|
||||
}
|
||||
return string(newImgID), nil
|
||||
}
|
|
@ -24,10 +24,11 @@ import (
|
|||
)
|
||||
|
||||
type containerStore interface {
|
||||
// used by image delete
|
||||
// First is used by image delete
|
||||
First(container.StoreFilter) *container.Container
|
||||
// used by image prune, and image list
|
||||
// List is used by image prune, and image list
|
||||
List() []*container.Container
|
||||
// Get is used by CommitBuildStep
|
||||
// TODO: remove, only used for CommitBuildStep
|
||||
Get(string) *container.Container
|
||||
}
|
||||
|
@ -144,7 +145,7 @@ func (i *ImageService) CreateLayer(container *container.Container, initFunc laye
|
|||
}
|
||||
|
||||
// GetLayerByID returns a layer by ID
|
||||
// called from daemon.go Daemon.restore(), and Daemon.containerExport()
|
||||
// called from daemon.go Daemon.restore(), and Daemon.containerExport().
|
||||
func (i *ImageService) GetLayerByID(cid string) (layer.RWLayer, error) {
|
||||
return i.layerStore.GetRWLayer(cid)
|
||||
}
|
||||
|
@ -182,8 +183,8 @@ func (i *ImageService) GraphDriverName() string {
|
|||
// ReleaseLayer releases a layer allowing it to be removed
|
||||
// called from delete.go Daemon.cleanupContainer(), and Daemon.containerExport()
|
||||
func (i *ImageService) ReleaseLayer(rwlayer layer.RWLayer) error {
|
||||
metadata, err := i.layerStore.ReleaseRWLayer(rwlayer)
|
||||
layer.LogReleaseMetadata(metadata)
|
||||
metaData, err := i.layerStore.ReleaseRWLayer(rwlayer)
|
||||
layer.LogReleaseMetadata(metaData)
|
||||
if err != nil && !errors.Is(err, layer.ErrMountDoesNotExist) && !errors.Is(err, os.ErrNotExist) {
|
||||
return errors.Wrapf(err, "driver %q failed to remove root filesystem",
|
||||
i.layerStore.DriverName())
|
||||
|
|
Loading…
Reference in a new issue