mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Documentation improvements and code cleanups for graph package
Expand the godoc documentation for the graph package. Centralize DefaultTag in the graphs/tag package instead of defining it twice. Remove some unnecessary "config" structs that are only used to pass a few parameters to a function. Simplify the GetParentsSize function - there's no reason for it to take an accumulator argument. Unexport some functions that aren't needed outside the package. Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
This commit is contained in:
parent
2ae174e491
commit
d4836cd7ec
19 changed files with 168 additions and 161 deletions
|
@ -526,7 +526,7 @@ func rewriteDockerfileFrom(dockerfileName string, translator func(string, regist
|
||||||
// Replace the line with a resolved "FROM repo@digest"
|
// Replace the line with a resolved "FROM repo@digest"
|
||||||
repo, tag := parsers.ParseRepositoryTag(matches[1])
|
repo, tag := parsers.ParseRepositoryTag(matches[1])
|
||||||
if tag == "" {
|
if tag == "" {
|
||||||
tag = tags.DEFAULTTAG
|
tag = tags.DefaultTag
|
||||||
}
|
}
|
||||||
ref := registry.ParseReference(tag)
|
ref := registry.ParseReference(tag)
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ func (cli *DockerCli) pullImageCustomOut(image string, out io.Writer) error {
|
||||||
repos, tag := parsers.ParseRepositoryTag(image)
|
repos, tag := parsers.ParseRepositoryTag(image)
|
||||||
// pull only the image tagged 'latest' if no tag was specified
|
// pull only the image tagged 'latest' if no tag was specified
|
||||||
if tag == "" {
|
if tag == "" {
|
||||||
tag = tags.DEFAULTTAG
|
tag = tags.DefaultTag
|
||||||
}
|
}
|
||||||
v.Set("fromImage", repos)
|
v.Set("fromImage", repos)
|
||||||
v.Set("tag", tag)
|
v.Set("tag", tag)
|
||||||
|
@ -96,7 +96,7 @@ func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runc
|
||||||
|
|
||||||
repo, tag := parsers.ParseRepositoryTag(config.Image)
|
repo, tag := parsers.ParseRepositoryTag(config.Image)
|
||||||
if tag == "" {
|
if tag == "" {
|
||||||
tag = tags.DEFAULTTAG
|
tag = tags.DefaultTag
|
||||||
}
|
}
|
||||||
|
|
||||||
ref := registry.ParseReference(tag)
|
ref := registry.ParseReference(tag)
|
||||||
|
|
|
@ -25,7 +25,7 @@ func (cli *DockerCli) CmdPull(args ...string) error {
|
||||||
|
|
||||||
taglessRemote, tag := parsers.ParseRepositoryTag(remote)
|
taglessRemote, tag := parsers.ParseRepositoryTag(remote)
|
||||||
if tag == "" && !*allTags {
|
if tag == "" && !*allTags {
|
||||||
tag = tags.DEFAULTTAG
|
tag = tags.DefaultTag
|
||||||
fmt.Fprintf(cli.out, "Using default tag: %s\n", tag)
|
fmt.Fprintf(cli.out, "Using default tag: %s\n", tag)
|
||||||
} else if tag != "" && *allTags {
|
} else if tag != "" && *allTags {
|
||||||
return fmt.Errorf("tag can't be used with --all-tags/-a")
|
return fmt.Errorf("tag can't be used with --all-tags/-a")
|
||||||
|
|
|
@ -364,14 +364,8 @@ func (s *Server) getImagesJSON(version version.Version, w http.ResponseWriter, r
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
imagesConfig := graph.ImagesConfig{
|
// FIXME: The filter parameter could just be a match filter
|
||||||
Filters: r.Form.Get("filters"),
|
images, err := s.daemon.Repositories().Images(r.Form.Get("filters"), r.Form.Get("filter"), boolValue(r, "all"))
|
||||||
// FIXME this parameter could just be a match filter
|
|
||||||
Filter: r.Form.Get("filter"),
|
|
||||||
All: boolValue(r, "all"),
|
|
||||||
}
|
|
||||||
|
|
||||||
images, err := s.daemon.Repositories().Images(&imagesConfig)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -785,23 +779,17 @@ func (s *Server) postImagesCreate(version version.Version, w http.ResponseWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
src := r.Form.Get("fromSrc")
|
src := r.Form.Get("fromSrc")
|
||||||
imageImportConfig := &graph.ImageImportConfig{
|
|
||||||
Changes: r.Form["changes"],
|
|
||||||
InConfig: r.Body,
|
|
||||||
OutStream: output,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 'err' MUST NOT be defined within this block, we need any error
|
// 'err' MUST NOT be defined within this block, we need any error
|
||||||
// generated from the download to be available to the output
|
// generated from the download to be available to the output
|
||||||
// stream processing below
|
// stream processing below
|
||||||
var newConfig *runconfig.Config
|
var newConfig *runconfig.Config
|
||||||
newConfig, err = builder.BuildFromConfig(s.daemon, &runconfig.Config{}, imageImportConfig.Changes)
|
newConfig, err = builder.BuildFromConfig(s.daemon, &runconfig.Config{}, r.Form["changes"])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
imageImportConfig.ContainerConfig = newConfig
|
|
||||||
|
|
||||||
err = s.daemon.Repositories().Import(src, repo, tag, imageImportConfig)
|
err = s.daemon.Repositories().Import(src, repo, tag, r.Body, output, newConfig)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !output.Flushed() {
|
if !output.Flushed() {
|
||||||
|
@ -909,14 +897,14 @@ func (s *Server) getImagesGet(version version.Version, w http.ResponseWriter, r
|
||||||
w.Header().Set("Content-Type", "application/x-tar")
|
w.Header().Set("Content-Type", "application/x-tar")
|
||||||
|
|
||||||
output := ioutils.NewWriteFlusher(w)
|
output := ioutils.NewWriteFlusher(w)
|
||||||
imageExportConfig := &graph.ImageExportConfig{Outstream: output}
|
var names []string
|
||||||
if name, ok := vars["name"]; ok {
|
if name, ok := vars["name"]; ok {
|
||||||
imageExportConfig.Names = []string{name}
|
names = []string{name}
|
||||||
} else {
|
} else {
|
||||||
imageExportConfig.Names = r.Form["names"]
|
names = r.Form["names"]
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.daemon.Repositories().ImageExport(imageExportConfig); err != nil {
|
if err := s.daemon.Repositories().ImageExport(names, output); err != nil {
|
||||||
if !output.Flushed() {
|
if !output.Flushed() {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/docker/graph"
|
"github.com/docker/docker/graph/tags"
|
||||||
"github.com/docker/docker/image"
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/pkg/parsers"
|
"github.com/docker/docker/pkg/parsers"
|
||||||
"github.com/docker/docker/runconfig"
|
"github.com/docker/docker/runconfig"
|
||||||
|
@ -27,7 +27,7 @@ func (daemon *Daemon) ContainerCreate(name string, config *runconfig.Config, hos
|
||||||
if daemon.Graph().IsNotExist(err, config.Image) {
|
if daemon.Graph().IsNotExist(err, config.Image) {
|
||||||
_, tag := parsers.ParseRepositoryTag(config.Image)
|
_, tag := parsers.ParseRepositoryTag(config.Image)
|
||||||
if tag == "" {
|
if tag == "" {
|
||||||
tag = graph.DefaultTag
|
tag = tags.DefaultTag
|
||||||
}
|
}
|
||||||
return "", warnings, fmt.Errorf("No such image: %s (tag: %s)", config.Image, tag)
|
return "", warnings, fmt.Errorf("No such image: %s (tag: %s)", config.Image, tag)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/graph"
|
"github.com/docker/docker/graph/tags"
|
||||||
"github.com/docker/docker/image"
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/pkg/parsers"
|
"github.com/docker/docker/pkg/parsers"
|
||||||
"github.com/docker/docker/pkg/stringid"
|
"github.com/docker/docker/pkg/stringid"
|
||||||
|
@ -27,16 +27,13 @@ func (daemon *Daemon) ImageDelete(name string, force, noprune bool) ([]types.Ima
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) imgDeleteHelper(name string, list *[]types.ImageDelete, first, force, noprune bool) error {
|
func (daemon *Daemon) imgDeleteHelper(name string, list *[]types.ImageDelete, first, force, noprune bool) error {
|
||||||
var (
|
var repoName, tag string
|
||||||
repoName, tag string
|
|
||||||
tags = []string{}
|
|
||||||
)
|
|
||||||
repoAndTags := make(map[string][]string)
|
repoAndTags := make(map[string][]string)
|
||||||
|
|
||||||
// FIXME: please respect DRY and centralize repo+tag parsing in a single central place! -- shykes
|
// FIXME: please respect DRY and centralize repo+tag parsing in a single central place! -- shykes
|
||||||
repoName, tag = parsers.ParseRepositoryTag(name)
|
repoName, tag = parsers.ParseRepositoryTag(name)
|
||||||
if tag == "" {
|
if tag == "" {
|
||||||
tag = graph.DefaultTag
|
tag = tags.DefaultTag
|
||||||
}
|
}
|
||||||
|
|
||||||
if name == "" {
|
if name == "" {
|
||||||
|
@ -111,7 +108,7 @@ func (daemon *Daemon) imgDeleteHelper(name string, list *[]types.ImageDelete, fi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tags = daemon.Repositories().ByID()[img.ID]
|
tags := daemon.Repositories().ByID()[img.ID]
|
||||||
if (len(tags) <= 1 && repoName == "") || len(tags) == 0 {
|
if (len(tags) <= 1 && repoName == "") || len(tags) == 0 {
|
||||||
if len(byParents[img.ID]) == 0 {
|
if len(byParents[img.ID]) == 0 {
|
||||||
if err := daemon.Repositories().DeleteAll(img.ID); err != nil {
|
if err := daemon.Repositories().DeleteAll(img.ID); err != nil {
|
||||||
|
|
|
@ -13,21 +13,12 @@ import (
|
||||||
"github.com/docker/docker/registry"
|
"github.com/docker/docker/registry"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ImageExportConfig holds list of names to be exported to a output stream.
|
// ImageExport exports list of images to a output stream specified in the
|
||||||
// All images with the given tag and all versions
|
// config. The exported images are archived into a tar when written to the
|
||||||
// containing the same tag are exported. The resulting output is an
|
// output stream. All images with the given tag and all versions containing the
|
||||||
// uncompressed tar ball.
|
// same tag are exported. names is the set of tags to export, and outStream
|
||||||
type ImageExportConfig struct {
|
// is the writer which the images are written to.
|
||||||
// Names is the set of tags to export.
|
func (s *TagStore) ImageExport(names []string, outStream io.Writer) error {
|
||||||
Names []string
|
|
||||||
// OutStream is the writer where the images are written to.
|
|
||||||
Outstream io.Writer
|
|
||||||
}
|
|
||||||
|
|
||||||
// ImageExport exports list of images to a output stream specified in the config.
|
|
||||||
// The exported images are archived into a tar when written to the output stream.
|
|
||||||
func (s *TagStore) ImageExport(imageExportConfig *ImageExportConfig) error {
|
|
||||||
|
|
||||||
// get image json
|
// get image json
|
||||||
tempdir, err := ioutil.TempDir("", "docker-export-")
|
tempdir, err := ioutil.TempDir("", "docker-export-")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -44,7 +35,7 @@ func (s *TagStore) ImageExport(imageExportConfig *ImageExportConfig) error {
|
||||||
repo[tag] = id
|
repo[tag] = id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, name := range imageExportConfig.Names {
|
for _, name := range names {
|
||||||
name = registry.NormalizeLocalName(name)
|
name = registry.NormalizeLocalName(name)
|
||||||
logrus.Debugf("Serializing %s", name)
|
logrus.Debugf("Serializing %s", name)
|
||||||
rootRepo := s.Repositories[name]
|
rootRepo := s.Repositories[name]
|
||||||
|
@ -107,7 +98,7 @@ func (s *TagStore) ImageExport(imageExportConfig *ImageExportConfig) error {
|
||||||
}
|
}
|
||||||
defer fs.Close()
|
defer fs.Close()
|
||||||
|
|
||||||
if _, err := io.Copy(imageExportConfig.Outstream, fs); err != nil {
|
if _, err := io.Copy(outStream, fs); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
logrus.Debugf("End export image")
|
logrus.Debugf("End export image")
|
||||||
|
|
|
@ -152,10 +152,11 @@ func (graph *Graph) restore() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsNotExist detects whether an image exists by parsing the incoming error message.
|
// IsNotExist detects whether an image exists by parsing the incoming error
|
||||||
// FIXME: Implement error subclass instead of looking at the error text
|
// message.
|
||||||
// Note: This is the way golang implements os.IsNotExists on Plan9
|
|
||||||
func (graph *Graph) IsNotExist(err error, id string) bool {
|
func (graph *Graph) IsNotExist(err error, id string) bool {
|
||||||
|
// FIXME: Implement error subclass instead of looking at the error text
|
||||||
|
// Note: This is the way golang implements os.IsNotExists on Plan9
|
||||||
return err != nil && (strings.Contains(strings.ToLower(err.Error()), "does not exist") || strings.Contains(strings.ToLower(err.Error()), "no such")) && strings.Contains(err.Error(), id)
|
return err != nil && (strings.Contains(strings.ToLower(err.Error()), "does not exist") || strings.Contains(strings.ToLower(err.Error()), "no such")) && strings.Contains(err.Error(), id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -415,13 +416,13 @@ func (graph *Graph) ByParent() map[string][]*image.Image {
|
||||||
return byParent
|
return byParent
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retain keeps the images and layers that are in pulling chain so that they are not deleted.
|
// Retain keeps the images and layers that are in the pulling chain so that
|
||||||
// If not, they may be deleted by rmi with dangling condition.
|
// they are not deleted. If not retained, they may be deleted by rmi.
|
||||||
func (graph *Graph) Retain(sessionID string, layerIDs ...string) {
|
func (graph *Graph) Retain(sessionID string, layerIDs ...string) {
|
||||||
graph.retained.Add(sessionID, layerIDs)
|
graph.retained.Add(sessionID, layerIDs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release removes the referenced image id from the provided set of layers.
|
// Release removes the referenced image ID from the provided set of layers.
|
||||||
func (graph *Graph) Release(sessionID string, layerIDs ...string) {
|
func (graph *Graph) Release(sessionID string, layerIDs ...string) {
|
||||||
graph.retained.Delete(sessionID, layerIDs)
|
graph.retained.Delete(sessionID, layerIDs)
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,8 @@ func (graph *Graph) CheckDepth(img *image.Image) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// History returns a list of ImageHistory for the specified image name by walking the image lineage.
|
// History returns a slice of ImageHistory structures for the specified image
|
||||||
|
// name by walking the image lineage.
|
||||||
func (s *TagStore) History(name string) ([]*types.ImageHistory, error) {
|
func (s *TagStore) History(name string) ([]*types.ImageHistory, error) {
|
||||||
foundImage, err := s.LookupImage(name)
|
foundImage, err := s.LookupImage(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -102,7 +103,7 @@ func (s *TagStore) History(name string) ([]*types.ImageHistory, error) {
|
||||||
return history, err
|
return history, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetParent returns the parent image.
|
// GetParent returns the parent image for the specified image.
|
||||||
func (graph *Graph) GetParent(img *image.Image) (*image.Image, error) {
|
func (graph *Graph) GetParent(img *image.Image) (*image.Image, error) {
|
||||||
if img.Parent == "" {
|
if img.Parent == "" {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -110,12 +111,12 @@ func (graph *Graph) GetParent(img *image.Image) (*image.Image, error) {
|
||||||
return graph.Get(img.Parent)
|
return graph.Get(img.Parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetParentsSize returns the size of the parent.
|
// GetParentsSize returns the combined size of all parent images. If there is
|
||||||
func (graph *Graph) GetParentsSize(img *image.Image, size int64) int64 {
|
// no parent image or it's unavailable, it returns 0.
|
||||||
|
func (graph *Graph) GetParentsSize(img *image.Image) int64 {
|
||||||
parentImage, err := graph.GetParent(img)
|
parentImage, err := graph.GetParent(img)
|
||||||
if err != nil || parentImage == nil {
|
if err != nil || parentImage == nil {
|
||||||
return size
|
return 0
|
||||||
}
|
}
|
||||||
size += parentImage.Size
|
return parentImage.Size + graph.GetParentsSize(parentImage)
|
||||||
return graph.GetParentsSize(parentImage, size)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,22 +13,11 @@ import (
|
||||||
"github.com/docker/docker/utils"
|
"github.com/docker/docker/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ImageImportConfig holds configuration to import a image.
|
// Import imports an image, getting the archived layer data either from
|
||||||
type ImageImportConfig struct {
|
// inConfig (if src is "-"), or from a URI specified in src. Progress output is
|
||||||
// Changes are the container changes written to top layer.
|
// written to outStream. Repository and tag names can optionally be given in
|
||||||
Changes []string
|
// the repo and tag arguments, respectively.
|
||||||
// InConfig is the input stream containers layered data.
|
func (s *TagStore) Import(src string, repo string, tag string, inConfig io.ReadCloser, outStream io.Writer, containerConfig *runconfig.Config) error {
|
||||||
InConfig io.ReadCloser
|
|
||||||
// OutStream is the output stream where the image is written.
|
|
||||||
OutStream io.Writer
|
|
||||||
// ContainerConfig is the configuration of commit container.
|
|
||||||
ContainerConfig *runconfig.Config
|
|
||||||
}
|
|
||||||
|
|
||||||
// Import allows to download image from a archive.
|
|
||||||
// If the src is a URL, the content is downloaded from the archive. If the source is '-' then the imageImportConfig.InConfig
|
|
||||||
// reader will be used to load the image. Once all the layers required are loaded locally, image is then tagged using the tag specified.
|
|
||||||
func (s *TagStore) Import(src string, repo string, tag string, imageImportConfig *ImageImportConfig) error {
|
|
||||||
var (
|
var (
|
||||||
sf = streamformatter.NewJSONStreamFormatter()
|
sf = streamformatter.NewJSONStreamFormatter()
|
||||||
archive archive.ArchiveReader
|
archive archive.ArchiveReader
|
||||||
|
@ -36,7 +25,7 @@ func (s *TagStore) Import(src string, repo string, tag string, imageImportConfig
|
||||||
)
|
)
|
||||||
|
|
||||||
if src == "-" {
|
if src == "-" {
|
||||||
archive = imageImportConfig.InConfig
|
archive = inConfig
|
||||||
} else {
|
} else {
|
||||||
u, err := url.Parse(src)
|
u, err := url.Parse(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -47,14 +36,14 @@ func (s *TagStore) Import(src string, repo string, tag string, imageImportConfig
|
||||||
u.Host = src
|
u.Host = src
|
||||||
u.Path = ""
|
u.Path = ""
|
||||||
}
|
}
|
||||||
imageImportConfig.OutStream.Write(sf.FormatStatus("", "Downloading from %s", u))
|
outStream.Write(sf.FormatStatus("", "Downloading from %s", u))
|
||||||
resp, err = httputils.Download(u.String())
|
resp, err = httputils.Download(u.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
progressReader := progressreader.New(progressreader.Config{
|
progressReader := progressreader.New(progressreader.Config{
|
||||||
In: resp.Body,
|
In: resp.Body,
|
||||||
Out: imageImportConfig.OutStream,
|
Out: outStream,
|
||||||
Formatter: sf,
|
Formatter: sf,
|
||||||
Size: int(resp.ContentLength),
|
Size: int(resp.ContentLength),
|
||||||
NewLines: true,
|
NewLines: true,
|
||||||
|
@ -65,7 +54,7 @@ func (s *TagStore) Import(src string, repo string, tag string, imageImportConfig
|
||||||
archive = progressReader
|
archive = progressReader
|
||||||
}
|
}
|
||||||
|
|
||||||
img, err := s.graph.Create(archive, "", "", "Imported from "+src, "", nil, imageImportConfig.ContainerConfig)
|
img, err := s.graph.Create(archive, "", "", "Imported from "+src, "", nil, containerConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -75,7 +64,7 @@ func (s *TagStore) Import(src string, repo string, tag string, imageImportConfig
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
imageImportConfig.OutStream.Write(sf.FormatStatus("", img.ID))
|
outStream.Write(sf.FormatStatus("", img.ID))
|
||||||
logID := img.ID
|
logID := img.ID
|
||||||
if tag != "" {
|
if tag != "" {
|
||||||
logID = utils.ImageReference(logID, tag)
|
logID = utils.ImageReference(logID, tag)
|
||||||
|
|
|
@ -18,25 +18,20 @@ var acceptedImageFilterTags = map[string]struct{}{
|
||||||
"label": {},
|
"label": {},
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImagesConfig defines the criteria to obtain a list of images.
|
// byCreated is a temporary type used to sort a list of images by creation
|
||||||
type ImagesConfig struct {
|
// time.
|
||||||
// Filters is supported list of filters used to get list of images.
|
|
||||||
Filters string
|
|
||||||
// Filter the list of images by name.
|
|
||||||
Filter string
|
|
||||||
// All inditest that all the images will be returned in the list, if set to true.
|
|
||||||
All bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// byCreated is a temporary type used to sort list of images on their field 'Created'.
|
|
||||||
type byCreated []*types.Image
|
type byCreated []*types.Image
|
||||||
|
|
||||||
func (r byCreated) Len() int { return len(r) }
|
func (r byCreated) Len() int { return len(r) }
|
||||||
func (r byCreated) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
|
func (r byCreated) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
|
||||||
func (r byCreated) Less(i, j int) bool { return r[i].Created < r[j].Created }
|
func (r byCreated) Less(i, j int) bool { return r[i].Created < r[j].Created }
|
||||||
|
|
||||||
// Images provide list of images based on selection criteria.
|
// Images returns a filtered list of images. filterArgs is a JSON-encoded set
|
||||||
func (s *TagStore) Images(config *ImagesConfig) ([]*types.Image, error) {
|
// of filter arguments which will be interpreted by pkg/parsers/filters.
|
||||||
|
// filter is a shell glob string applied to repository names. The argument
|
||||||
|
// named all controls whether all images in the graph are filtered, or just
|
||||||
|
// the heads.
|
||||||
|
func (s *TagStore) Images(filterArgs, filter string, all bool) ([]*types.Image, error) {
|
||||||
var (
|
var (
|
||||||
allImages map[string]*image.Image
|
allImages map[string]*image.Image
|
||||||
err error
|
err error
|
||||||
|
@ -44,7 +39,7 @@ func (s *TagStore) Images(config *ImagesConfig) ([]*types.Image, error) {
|
||||||
filtLabel = false
|
filtLabel = false
|
||||||
)
|
)
|
||||||
|
|
||||||
imageFilters, err := filters.FromParam(config.Filters)
|
imageFilters, err := filters.FromParam(filterArgs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -64,7 +59,7 @@ func (s *TagStore) Images(config *ImagesConfig) ([]*types.Image, error) {
|
||||||
|
|
||||||
_, filtLabel = imageFilters["label"]
|
_, filtLabel = imageFilters["label"]
|
||||||
|
|
||||||
if config.All && filtTagged {
|
if all && filtTagged {
|
||||||
allImages = s.graph.Map()
|
allImages = s.graph.Map()
|
||||||
} else {
|
} else {
|
||||||
allImages = s.graph.Heads()
|
allImages = s.graph.Heads()
|
||||||
|
@ -73,8 +68,8 @@ func (s *TagStore) Images(config *ImagesConfig) ([]*types.Image, error) {
|
||||||
lookup := make(map[string]*types.Image)
|
lookup := make(map[string]*types.Image)
|
||||||
s.Lock()
|
s.Lock()
|
||||||
for repoName, repository := range s.Repositories {
|
for repoName, repository := range s.Repositories {
|
||||||
if config.Filter != "" {
|
if filter != "" {
|
||||||
if match, _ := path.Match(config.Filter, repoName); !match {
|
if match, _ := path.Match(filter, repoName); !match {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,7 +101,7 @@ func (s *TagStore) Images(config *ImagesConfig) ([]*types.Image, error) {
|
||||||
newImage.ID = image.ID
|
newImage.ID = image.ID
|
||||||
newImage.Created = int(image.Created.Unix())
|
newImage.Created = int(image.Created.Unix())
|
||||||
newImage.Size = int(image.Size)
|
newImage.Size = int(image.Size)
|
||||||
newImage.VirtualSize = int(s.graph.GetParentsSize(image, 0) + image.Size)
|
newImage.VirtualSize = int(s.graph.GetParentsSize(image) + image.Size)
|
||||||
newImage.Labels = image.ContainerConfig.Labels
|
newImage.Labels = image.ContainerConfig.Labels
|
||||||
|
|
||||||
if utils.DigestReference(ref) {
|
if utils.DigestReference(ref) {
|
||||||
|
@ -131,7 +126,7 @@ func (s *TagStore) Images(config *ImagesConfig) ([]*types.Image, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display images which aren't part of a repository/tag
|
// Display images which aren't part of a repository/tag
|
||||||
if config.Filter == "" || filtLabel {
|
if filter == "" || filtLabel {
|
||||||
for _, image := range allImages {
|
for _, image := range allImages {
|
||||||
if !imageFilters.MatchKVList("label", image.ContainerConfig.Labels) {
|
if !imageFilters.MatchKVList("label", image.ContainerConfig.Labels) {
|
||||||
continue
|
continue
|
||||||
|
@ -143,7 +138,7 @@ func (s *TagStore) Images(config *ImagesConfig) ([]*types.Image, error) {
|
||||||
newImage.ID = image.ID
|
newImage.ID = image.ID
|
||||||
newImage.Created = int(image.Created.Unix())
|
newImage.Created = int(image.Created.Unix())
|
||||||
newImage.Size = int(image.Size)
|
newImage.Size = int(image.Size)
|
||||||
newImage.VirtualSize = int(s.graph.GetParentsSize(image, 0) + image.Size)
|
newImage.VirtualSize = int(s.graph.GetParentsSize(image) + image.Size)
|
||||||
newImage.Labels = image.ContainerConfig.Labels
|
newImage.Labels = image.ContainerConfig.Labels
|
||||||
|
|
||||||
images = append(images, newImage)
|
images = append(images, newImage)
|
||||||
|
|
|
@ -71,7 +71,7 @@ func (s *TagStore) Load(inTar io.ReadCloser, outStream io.Writer) error {
|
||||||
|
|
||||||
for imageName, tagMap := range repositories {
|
for imageName, tagMap := range repositories {
|
||||||
for tag, address := range tagMap {
|
for tag, address := range tagMap {
|
||||||
if err := s.SetLoad(imageName, tag, address, true, outStream); err != nil {
|
if err := s.setLoad(imageName, tag, address, true, outStream); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,15 +13,18 @@ import (
|
||||||
|
|
||||||
// ImagePullConfig stores pull configuration.
|
// ImagePullConfig stores pull configuration.
|
||||||
type ImagePullConfig struct {
|
type ImagePullConfig struct {
|
||||||
// MetaHeaders store meta data about the image (DockerHeaders with prefix X-Meta- in the request).
|
// MetaHeaders stores HTTP headers with metadata about the image
|
||||||
|
// (DockerHeaders with prefix X-Meta- in the request).
|
||||||
MetaHeaders map[string][]string
|
MetaHeaders map[string][]string
|
||||||
// AuthConfig holds authentication information for authorizing with the registry.
|
// AuthConfig holds authentication credentials for authenticating with
|
||||||
|
// the registry.
|
||||||
AuthConfig *cliconfig.AuthConfig
|
AuthConfig *cliconfig.AuthConfig
|
||||||
// OutStream is the output writer for showing the status of the pull operation.
|
// OutStream is the output writer for showing the status of the pull
|
||||||
|
// operation.
|
||||||
OutStream io.Writer
|
OutStream io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
// Puller is an interface to define Pull behavior.
|
// Puller is an interface that abstracts pulling for different API versions.
|
||||||
type Puller interface {
|
type Puller interface {
|
||||||
// Pull tries to pull the image referenced by `tag`
|
// Pull tries to pull the image referenced by `tag`
|
||||||
// Pull returns an error if any, as well as a boolean that determines whether to retry Pull on the next configured endpoint.
|
// Pull returns an error if any, as well as a boolean that determines whether to retry Pull on the next configured endpoint.
|
||||||
|
@ -30,7 +33,11 @@ type Puller interface {
|
||||||
Pull(tag string) (fallback bool, err error)
|
Pull(tag string) (fallback bool, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPuller returns a new instance of an implementation conforming to Puller interface.
|
// NewPuller returns a Puller interface that will pull from either a v1 or v2
|
||||||
|
// registry. The endpoint argument contains a Version field that determines
|
||||||
|
// whether a v1 or v2 puller will be created. The other parameters are passed
|
||||||
|
// through to the underlying puller implementation for use during the actual
|
||||||
|
// pull operation.
|
||||||
func NewPuller(s *TagStore, endpoint registry.APIEndpoint, repoInfo *registry.RepositoryInfo, imagePullConfig *ImagePullConfig, sf *streamformatter.StreamFormatter) (Puller, error) {
|
func NewPuller(s *TagStore, endpoint registry.APIEndpoint, repoInfo *registry.RepositoryInfo, imagePullConfig *ImagePullConfig, sf *streamformatter.StreamFormatter) (Puller, error) {
|
||||||
switch endpoint.Version {
|
switch endpoint.Version {
|
||||||
case registry.APIVersion2:
|
case registry.APIVersion2:
|
||||||
|
@ -53,7 +60,8 @@ func NewPuller(s *TagStore, endpoint registry.APIEndpoint, repoInfo *registry.Re
|
||||||
return nil, fmt.Errorf("unknown version %d for registry %s", endpoint.Version, endpoint.URL)
|
return nil, fmt.Errorf("unknown version %d for registry %s", endpoint.Version, endpoint.URL)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pull downloads a image with specified name and tag from the repo.
|
// Pull initiates a pull operation. image is the repository name to pull, and
|
||||||
|
// tag may be either empty, or indicate a specific tag to pull.
|
||||||
func (s *TagStore) Pull(image string, tag string, imagePullConfig *ImagePullConfig) error {
|
func (s *TagStore) Pull(image string, tag string, imagePullConfig *ImagePullConfig) error {
|
||||||
var sf = streamformatter.NewJSONStreamFormatter()
|
var sf = streamformatter.NewJSONStreamFormatter()
|
||||||
|
|
||||||
|
@ -133,7 +141,10 @@ func (s *TagStore) Pull(image string, tag string, imagePullConfig *ImagePullConf
|
||||||
return lastErr
|
return lastErr
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeStatus shows status of the pull command.
|
// writeStatus writes a status message to out. If layersDownloaded is true, the
|
||||||
|
// status message indicates that a newer image was downloaded. Otherwise, it
|
||||||
|
// indicates that the image is up to date. requestedTag is the tag the message
|
||||||
|
// will refer to.
|
||||||
func writeStatus(requestedTag string, out io.Writer, sf *streamformatter.StreamFormatter, layersDownloaded bool) {
|
func writeStatus(requestedTag string, out io.Writer, sf *streamformatter.StreamFormatter, layersDownloaded bool) {
|
||||||
if layersDownloaded {
|
if layersDownloaded {
|
||||||
out.Write(sf.FormatStatus("", "Status: Downloaded newer image for %s", requestedTag))
|
out.Write(sf.FormatStatus("", "Status: Downloaded newer image for %s", requestedTag))
|
||||||
|
|
|
@ -12,17 +12,21 @@ import (
|
||||||
|
|
||||||
// ImagePushConfig stores push configuration.
|
// ImagePushConfig stores push configuration.
|
||||||
type ImagePushConfig struct {
|
type ImagePushConfig struct {
|
||||||
// MetaHeaders store meta data about the image (DockerHeaders with prefix X-Meta- in the request).
|
// MetaHeaders store HTTP headers with metadata about the image
|
||||||
|
// (DockerHeaders with prefix X-Meta- in the request).
|
||||||
MetaHeaders map[string][]string
|
MetaHeaders map[string][]string
|
||||||
// AuthConfig holds authentication information for authorizing with the registry.
|
// AuthConfig holds authentication credentials for authenticating with
|
||||||
|
// the registry.
|
||||||
AuthConfig *cliconfig.AuthConfig
|
AuthConfig *cliconfig.AuthConfig
|
||||||
// Tag is the specific variant of the image to be pushed, this tag used when image is pushed. If no tag is provided, all tags will be pushed.
|
// Tag is the specific variant of the image to be pushed.
|
||||||
|
// If no tag is provided, all tags will be pushed.
|
||||||
Tag string
|
Tag string
|
||||||
// OutStream is the output writer for showing the status of the push operation.
|
// OutStream is the output writer for showing the status of the push
|
||||||
|
// operation.
|
||||||
OutStream io.Writer
|
OutStream io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pusher is an interface to define Push behavior.
|
// Pusher is an interface that abstracts pushing for different API versions.
|
||||||
type Pusher interface {
|
type Pusher interface {
|
||||||
// Push tries to push the image configured at the creation of Pusher.
|
// Push tries to push the image configured at the creation of Pusher.
|
||||||
// Push returns an error if any, as well as a boolean that determines whether to retry Push on the next configured endpoint.
|
// Push returns an error if any, as well as a boolean that determines whether to retry Push on the next configured endpoint.
|
||||||
|
@ -31,7 +35,11 @@ type Pusher interface {
|
||||||
Push() (fallback bool, err error)
|
Push() (fallback bool, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPusher returns a new instance of an implementation conforming to Pusher interface.
|
// NewPusher creates a new Pusher interface that will push to either a v1 or v2
|
||||||
|
// registry. The endpoint argument contains a Version field that determines
|
||||||
|
// whether a v1 or v2 pusher will be created. The other parameters are passed
|
||||||
|
// through to the underlying pusher implementation for use during the actual
|
||||||
|
// push operation.
|
||||||
func (s *TagStore) NewPusher(endpoint registry.APIEndpoint, localRepo Repository, repoInfo *registry.RepositoryInfo, imagePushConfig *ImagePushConfig, sf *streamformatter.StreamFormatter) (Pusher, error) {
|
func (s *TagStore) NewPusher(endpoint registry.APIEndpoint, localRepo Repository, repoInfo *registry.RepositoryInfo, imagePushConfig *ImagePushConfig, sf *streamformatter.StreamFormatter) (Pusher, error) {
|
||||||
switch endpoint.Version {
|
switch endpoint.Version {
|
||||||
case registry.APIVersion2:
|
case registry.APIVersion2:
|
||||||
|
@ -57,10 +65,10 @@ func (s *TagStore) NewPusher(endpoint registry.APIEndpoint, localRepo Repository
|
||||||
return nil, fmt.Errorf("unknown version %d for registry %s", endpoint.Version, endpoint.URL)
|
return nil, fmt.Errorf("unknown version %d for registry %s", endpoint.Version, endpoint.URL)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Allow to interrupt current push when new push of same image is done.
|
// Push initiates a push operation on the repository named localName.
|
||||||
|
|
||||||
// Push a image to the repo.
|
|
||||||
func (s *TagStore) Push(localName string, imagePushConfig *ImagePushConfig) error {
|
func (s *TagStore) Push(localName string, imagePushConfig *ImagePushConfig) error {
|
||||||
|
// FIXME: Allow to interrupt current push when new push of same image is done.
|
||||||
|
|
||||||
var sf = streamformatter.NewJSONStreamFormatter()
|
var sf = streamformatter.NewJSONStreamFormatter()
|
||||||
|
|
||||||
// Resolve the Repository name from fqn to RepositoryInfo
|
// Resolve the Repository name from fqn to RepositoryInfo
|
||||||
|
|
|
@ -27,7 +27,9 @@ func (dcs dumbCredentialStore) Basic(*url.URL) (string, string) {
|
||||||
return dcs.auth.Username, dcs.auth.Password
|
return dcs.auth.Username, dcs.auth.Password
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewV2Repository creates a v2 only repository.
|
// NewV2Repository returns a repository (v2 only). It creates a HTTP transport
|
||||||
|
// providing timeout settings and authentication support, and also verifies the
|
||||||
|
// remote API version.
|
||||||
func NewV2Repository(repoInfo *registry.RepositoryInfo, endpoint registry.APIEndpoint, metaHeaders http.Header, authConfig *cliconfig.AuthConfig) (distribution.Repository, error) {
|
func NewV2Repository(repoInfo *registry.RepositoryInfo, endpoint registry.APIEndpoint, metaHeaders http.Header, authConfig *cliconfig.AuthConfig) (distribution.Repository, error) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@ import (
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// lookupRaw looks up an image by name in a TagStore and returns the raw JSON
|
||||||
|
// describing the image.
|
||||||
func (s *TagStore) lookupRaw(name string) ([]byte, error) {
|
func (s *TagStore) lookupRaw(name string) ([]byte, error) {
|
||||||
image, err := s.LookupImage(name)
|
image, err := s.LookupImage(name)
|
||||||
if err != nil || image == nil {
|
if err != nil || image == nil {
|
||||||
|
@ -24,7 +26,8 @@ func (s *TagStore) lookupRaw(name string) ([]byte, error) {
|
||||||
return imageInspectRaw, nil
|
return imageInspectRaw, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lookup return an image encoded in JSON
|
// Lookup looks up an image by name in a TagStore and returns it as an
|
||||||
|
// ImageInspect structure.
|
||||||
func (s *TagStore) Lookup(name string) (*types.ImageInspect, error) {
|
func (s *TagStore) Lookup(name string) (*types.ImageInspect, error) {
|
||||||
image, err := s.LookupImage(name)
|
image, err := s.LookupImage(name)
|
||||||
if err != nil || image == nil {
|
if err != nil || image == nil {
|
||||||
|
@ -44,7 +47,7 @@ func (s *TagStore) Lookup(name string) (*types.ImageInspect, error) {
|
||||||
Architecture: image.Architecture,
|
Architecture: image.Architecture,
|
||||||
Os: image.OS,
|
Os: image.OS,
|
||||||
Size: image.Size,
|
Size: image.Size,
|
||||||
VirtualSize: s.graph.GetParentsSize(image, 0) + image.Size,
|
VirtualSize: s.graph.GetParentsSize(image) + image.Size,
|
||||||
}
|
}
|
||||||
|
|
||||||
imageInspect.GraphDriver.Name = s.graph.driver.String()
|
imageInspect.GraphDriver.Name = s.graph.driver.String()
|
||||||
|
|
|
@ -24,13 +24,13 @@ import (
|
||||||
"github.com/docker/libtrust"
|
"github.com/docker/libtrust"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DefaultTag defines the default tag used when performing images related actions and no tag string is specified
|
// TagStore manages repositories. It encompasses the Graph used for versioned
|
||||||
const DefaultTag = "latest"
|
// storage, as well as various services involved in pushing and pulling
|
||||||
|
// repositories.
|
||||||
// TagStore contains information to push and pull to the repo.
|
|
||||||
type TagStore struct {
|
type TagStore struct {
|
||||||
path string
|
path string
|
||||||
graph *Graph
|
graph *Graph
|
||||||
|
// Repositories is a map of repositories, indexed by name.
|
||||||
Repositories map[string]Repository
|
Repositories map[string]Repository
|
||||||
trustKey libtrust.PrivateKey
|
trustKey libtrust.PrivateKey
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
|
@ -43,7 +43,7 @@ type TagStore struct {
|
||||||
trustService *trust.TrustStore
|
trustService *trust.TrustStore
|
||||||
}
|
}
|
||||||
|
|
||||||
// Repository maps image id to image tag.
|
// Repository maps tags to image IDs.
|
||||||
type Repository map[string]string
|
type Repository map[string]string
|
||||||
|
|
||||||
// Update updates repository mapping with content of repository 'u'.
|
// Update updates repository mapping with content of repository 'u'.
|
||||||
|
@ -53,7 +53,8 @@ func (r Repository) Update(u Repository) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Contains returns true if the contents of u Repository, are wholly contained in r Repository.
|
// Contains returns true if the contents of Repository u are wholly contained
|
||||||
|
// in Repository r.
|
||||||
func (r Repository) Contains(u Repository) bool {
|
func (r Repository) Contains(u Repository) bool {
|
||||||
for k, v := range u {
|
for k, v := range u {
|
||||||
// if u's key is not present in r OR u's key is present, but not the same value
|
// if u's key is not present in r OR u's key is present, but not the same value
|
||||||
|
@ -64,16 +65,23 @@ func (r Repository) Contains(u Repository) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// TagStoreConfig holds tag store configuration.
|
// TagStoreConfig provides parameters for a new TagStore.
|
||||||
type TagStoreConfig struct {
|
type TagStoreConfig struct {
|
||||||
Graph *Graph
|
// Graph is the versioned image store
|
||||||
Key libtrust.PrivateKey
|
Graph *Graph
|
||||||
|
// Key is the private key to use for signing manifests.
|
||||||
|
Key libtrust.PrivateKey
|
||||||
|
// Registry is the registry service to use for TLS configuration and
|
||||||
|
// endpoint lookup.
|
||||||
Registry *registry.Service
|
Registry *registry.Service
|
||||||
Events *events.Events
|
// Events is the events service to use for logging.
|
||||||
Trust *trust.TrustStore
|
Events *events.Events
|
||||||
|
// Trust is the trust service to use for push and pull operations.
|
||||||
|
Trust *trust.TrustStore
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTagStore creates a tag store to specified path.
|
// NewTagStore creates a new TagStore at specified path, using the parameters
|
||||||
|
// and services provided in cfg.
|
||||||
func NewTagStore(path string, cfg *TagStoreConfig) (*TagStore, error) {
|
func NewTagStore(path string, cfg *TagStoreConfig) (*TagStore, error) {
|
||||||
abspath, err := filepath.Abs(path)
|
abspath, err := filepath.Abs(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -126,13 +134,15 @@ func (store *TagStore) reload() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LookupImage returns the image from the store.
|
// LookupImage returns pointer to an Image struct corresponding to the given
|
||||||
|
// name. The name can include an optional tag; otherwise the default tag will
|
||||||
|
// be used.
|
||||||
func (store *TagStore) LookupImage(name string) (*image.Image, error) {
|
func (store *TagStore) LookupImage(name string) (*image.Image, error) {
|
||||||
// FIXME: standardize on returning nil when the image doesn't exist, and err for everything else
|
// FIXME: standardize on returning nil when the image doesn't exist, and err for everything else
|
||||||
// (so we can pass all errors here)
|
// (so we can pass all errors here)
|
||||||
repoName, ref := parsers.ParseRepositoryTag(name)
|
repoName, ref := parsers.ParseRepositoryTag(name)
|
||||||
if ref == "" {
|
if ref == "" {
|
||||||
ref = DefaultTag
|
ref = tags.DefaultTag
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
|
@ -158,8 +168,8 @@ func (store *TagStore) LookupImage(name string) (*image.Image, error) {
|
||||||
return img, nil
|
return img, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ByID returns a reverse-lookup table of all the names which refer to each image.
|
// ByID returns a reverse-lookup table of all the names which refer to each
|
||||||
// Eg. {"43b5f19b10584": {"base:latest", "base:v1"}}
|
// image - e.g. {"43b5f19b10584": {"base:latest", "base:v1"}}
|
||||||
func (store *TagStore) ByID() map[string][]string {
|
func (store *TagStore) ByID() map[string][]string {
|
||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
|
@ -178,7 +188,7 @@ func (store *TagStore) ByID() map[string][]string {
|
||||||
return byID
|
return byID
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImageName returns name of the image.
|
// ImageName returns name of an image, given the image's ID.
|
||||||
func (store *TagStore) ImageName(id string) string {
|
func (store *TagStore) ImageName(id string) string {
|
||||||
if names, exists := store.ByID()[id]; exists && len(names) > 0 {
|
if names, exists := store.ByID()[id]; exists && len(names) > 0 {
|
||||||
return names[0]
|
return names[0]
|
||||||
|
@ -186,7 +196,7 @@ func (store *TagStore) ImageName(id string) string {
|
||||||
return stringid.TruncateID(id)
|
return stringid.TruncateID(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteAll removes images identified by a specific id from the store.
|
// DeleteAll removes images identified by a specific ID from the store.
|
||||||
func (store *TagStore) DeleteAll(id string) error {
|
func (store *TagStore) DeleteAll(id string) error {
|
||||||
names, exists := store.ByID()[id]
|
names, exists := store.ByID()[id]
|
||||||
if !exists || len(names) == 0 {
|
if !exists || len(names) == 0 {
|
||||||
|
@ -207,7 +217,9 @@ func (store *TagStore) DeleteAll(id string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete removes a repo identified by a given name from the store
|
// Delete deletes a repository or a specific tag. If ref is empty, the entire
|
||||||
|
// repository named repoName will be deleted; otherwise only the tag named by
|
||||||
|
// ref will be deleted.
|
||||||
func (store *TagStore) Delete(repoName, ref string) (bool, error) {
|
func (store *TagStore) Delete(repoName, ref string) (bool, error) {
|
||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
|
@ -240,14 +252,16 @@ func (store *TagStore) Delete(repoName, ref string) (bool, error) {
|
||||||
return deleted, store.save()
|
return deleted, store.save()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tag adds a new tag to an existing image.
|
// Tag creates a tag in the repository reponame, pointing to the image named
|
||||||
|
// imageName. If force is true, an existing tag with the same name may be
|
||||||
|
// overwritten.
|
||||||
func (store *TagStore) Tag(repoName, tag, imageName string, force bool) error {
|
func (store *TagStore) Tag(repoName, tag, imageName string, force bool) error {
|
||||||
return store.SetLoad(repoName, tag, imageName, force, nil)
|
return store.setLoad(repoName, tag, imageName, force, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetLoad stores the image to the store.
|
// setLoad stores the image to the store.
|
||||||
// If the imageName is already in the repo then a '-f' flag should be used to replace existing image.
|
// If the imageName is already in the repo then a '-f' flag should be used to replace existing image.
|
||||||
func (store *TagStore) SetLoad(repoName, tag, imageName string, force bool, out io.Writer) error {
|
func (store *TagStore) setLoad(repoName, tag, imageName string, force bool, out io.Writer) error {
|
||||||
img, err := store.LookupImage(imageName)
|
img, err := store.LookupImage(imageName)
|
||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
|
@ -255,7 +269,7 @@ func (store *TagStore) SetLoad(repoName, tag, imageName string, force bool, out
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if tag == "" {
|
if tag == "" {
|
||||||
tag = tags.DEFAULTTAG
|
tag = tags.DefaultTag
|
||||||
}
|
}
|
||||||
if err := validateRepoName(repoName); err != nil {
|
if err := validateRepoName(repoName); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -331,7 +345,7 @@ func (store *TagStore) SetDigest(repoName, digest, imageName string) error {
|
||||||
return store.save()
|
return store.save()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns a repo from the store.
|
// Get returns the Repository tag/image map for a given repository.
|
||||||
func (store *TagStore) Get(repoName string) (Repository, error) {
|
func (store *TagStore) Get(repoName string) (Repository, error) {
|
||||||
store.Lock()
|
store.Lock()
|
||||||
defer store.Unlock()
|
defer store.Unlock()
|
||||||
|
@ -345,7 +359,8 @@ func (store *TagStore) Get(repoName string) (Repository, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetImage returns an image from a given repo from the store.
|
// GetImage returns a pointer to an Image structure describing the image
|
||||||
|
// referred to by refOrID inside repository repoName.
|
||||||
func (store *TagStore) GetImage(repoName, refOrID string) (*image.Image, error) {
|
func (store *TagStore) GetImage(repoName, refOrID string) (*image.Image, error) {
|
||||||
repo, err := store.Get(repoName)
|
repo, err := store.Get(repoName)
|
||||||
|
|
||||||
|
@ -375,7 +390,8 @@ func (store *TagStore) GetImage(repoName, refOrID string) (*image.Image, error)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRepoRefs returns list of repos.
|
// GetRepoRefs returns a map with image IDs as keys, and slices listing
|
||||||
|
// repo/tag references as the values. It covers all repositories.
|
||||||
func (store *TagStore) GetRepoRefs() map[string][]string {
|
func (store *TagStore) GetRepoRefs() map[string][]string {
|
||||||
store.Lock()
|
store.Lock()
|
||||||
reporefs := make(map[string][]string)
|
reporefs := make(map[string][]string)
|
||||||
|
|
|
@ -6,8 +6,12 @@ import (
|
||||||
"github.com/docker/distribution/registry/api/v2"
|
"github.com/docker/distribution/registry/api/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
const DEFAULTTAG = "latest"
|
// DefaultTag is the default tag for the case where no explicit tag is
|
||||||
|
// specified.
|
||||||
|
const DefaultTag = "latest"
|
||||||
|
|
||||||
|
// ErrTagInvalidFormat is an error type used when the tag name has invalid
|
||||||
|
// characters or is longer than allowed.
|
||||||
type ErrTagInvalidFormat struct {
|
type ErrTagInvalidFormat struct {
|
||||||
name string
|
name string
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/docker/docker/daemon/events"
|
"github.com/docker/docker/daemon/events"
|
||||||
"github.com/docker/docker/daemon/graphdriver"
|
"github.com/docker/docker/daemon/graphdriver"
|
||||||
_ "github.com/docker/docker/daemon/graphdriver/vfs" // import the vfs driver so it is used in the tests
|
_ "github.com/docker/docker/daemon/graphdriver/vfs" // import the vfs driver so it is used in the tests
|
||||||
|
"github.com/docker/docker/graph/tags"
|
||||||
"github.com/docker/docker/image"
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/trust"
|
"github.com/docker/docker/trust"
|
||||||
"github.com/docker/docker/utils"
|
"github.com/docker/docker/utils"
|
||||||
|
@ -119,17 +120,17 @@ func TestLookupImage(t *testing.T) {
|
||||||
testOfficialImageName + ":" + testOfficialImageID,
|
testOfficialImageName + ":" + testOfficialImageID,
|
||||||
testOfficialImageName + ":" + testOfficialImageIDShort,
|
testOfficialImageName + ":" + testOfficialImageIDShort,
|
||||||
testOfficialImageName,
|
testOfficialImageName,
|
||||||
testOfficialImageName + ":" + DefaultTag,
|
testOfficialImageName + ":" + tags.DefaultTag,
|
||||||
"docker.io/" + testOfficialImageName,
|
"docker.io/" + testOfficialImageName,
|
||||||
"docker.io/" + testOfficialImageName + ":" + DefaultTag,
|
"docker.io/" + testOfficialImageName + ":" + tags.DefaultTag,
|
||||||
"index.docker.io/" + testOfficialImageName,
|
"index.docker.io/" + testOfficialImageName,
|
||||||
"index.docker.io/" + testOfficialImageName + ":" + DefaultTag,
|
"index.docker.io/" + testOfficialImageName + ":" + tags.DefaultTag,
|
||||||
"library/" + testOfficialImageName,
|
"library/" + testOfficialImageName,
|
||||||
"library/" + testOfficialImageName + ":" + DefaultTag,
|
"library/" + testOfficialImageName + ":" + tags.DefaultTag,
|
||||||
"docker.io/library/" + testOfficialImageName,
|
"docker.io/library/" + testOfficialImageName,
|
||||||
"docker.io/library/" + testOfficialImageName + ":" + DefaultTag,
|
"docker.io/library/" + testOfficialImageName + ":" + tags.DefaultTag,
|
||||||
"index.docker.io/library/" + testOfficialImageName,
|
"index.docker.io/library/" + testOfficialImageName,
|
||||||
"index.docker.io/library/" + testOfficialImageName + ":" + DefaultTag,
|
"index.docker.io/library/" + testOfficialImageName + ":" + tags.DefaultTag,
|
||||||
}
|
}
|
||||||
|
|
||||||
privateLookups := []string{
|
privateLookups := []string{
|
||||||
|
@ -138,7 +139,7 @@ func TestLookupImage(t *testing.T) {
|
||||||
testPrivateImageName + ":" + testPrivateImageID,
|
testPrivateImageName + ":" + testPrivateImageID,
|
||||||
testPrivateImageName + ":" + testPrivateImageIDShort,
|
testPrivateImageName + ":" + testPrivateImageIDShort,
|
||||||
testPrivateImageName,
|
testPrivateImageName,
|
||||||
testPrivateImageName + ":" + DefaultTag,
|
testPrivateImageName + ":" + tags.DefaultTag,
|
||||||
}
|
}
|
||||||
|
|
||||||
invalidLookups := []string{
|
invalidLookups := []string{
|
||||||
|
|
Loading…
Add table
Reference in a new issue