/graph fix lin errors/warnings
Addresses #14756 Signed-off-by: Srini Brahmaroutu <srbrahma@us.ibm.com>
This commit is contained in:
parent
0f85fadb4e
commit
1d6e443119
21 changed files with 140 additions and 87 deletions
|
@ -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 = graph.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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ func (daemon *Daemon) imgDeleteHelper(name string, list *[]types.ImageDelete, fi
|
||||||
// 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 = graph.DefaultTag
|
||||||
}
|
}
|
||||||
|
|
||||||
if name == "" {
|
if name == "" {
|
||||||
|
|
|
@ -13,16 +13,19 @@ import (
|
||||||
"github.com/docker/docker/registry"
|
"github.com/docker/docker/registry"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdImageExport exports all images with the given tag. All versions
|
// ImageExportConfig holds list of names to be exported to a output stream.
|
||||||
|
// All images with the given tag and all versions
|
||||||
// containing the same tag are exported. The resulting output is an
|
// containing the same tag are exported. The resulting output is an
|
||||||
// uncompressed tar ball.
|
// uncompressed tar ball.
|
||||||
// name is the set of tags to export.
|
|
||||||
// out is the writer where the images are written to.
|
|
||||||
type ImageExportConfig struct {
|
type ImageExportConfig struct {
|
||||||
Names []string
|
// Names is the set of tags to export.
|
||||||
|
Names []string
|
||||||
|
// OutStream is the writer where the images are written to.
|
||||||
Outstream io.Writer
|
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 {
|
func (s *TagStore) ImageExport(imageExportConfig *ImageExportConfig) error {
|
||||||
|
|
||||||
// get image json
|
// get image json
|
||||||
|
@ -135,7 +138,7 @@ func (s *TagStore) exportImage(name, tempdir string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
imageInspectRaw, err := s.LookupRaw(n)
|
imageInspectRaw, err := s.lookupRaw(n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,6 +152,7 @@ func (graph *Graph) restore() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsNotExist detects whether an image exists by parsing the incoming error message.
|
||||||
// FIXME: Implement error subclass instead of looking at the error text
|
// FIXME: Implement error subclass instead of looking at the error text
|
||||||
// Note: This is the way golang implements os.IsNotExists on Plan9
|
// 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 {
|
||||||
|
@ -414,7 +415,7 @@ func (graph *Graph) ByParent() map[string][]*image.Image {
|
||||||
return byParent
|
return byParent
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the images and layers are in pulling chain, retain them.
|
// Retain keeps the images and layers that are in pulling chain so that they are not deleted.
|
||||||
// If not, they may be deleted by rmi with dangling condition.
|
// If not, they may be deleted by rmi with dangling condition.
|
||||||
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)
|
||||||
|
|
|
@ -16,10 +16,9 @@ import (
|
||||||
"github.com/docker/docker/pkg/system"
|
"github.com/docker/docker/pkg/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
// setupInitLayer populates a directory with mountpoints suitable
|
// SetupInitLayer populates a directory with mountpoints suitable
|
||||||
// for bind-mounting dockerinit into the container. The mountpoint is simply an
|
// for bind-mounting dockerinit into the container. The mountpoint is simply an
|
||||||
// empty file at /.dockerinit
|
// empty file at /.dockerinit
|
||||||
//
|
|
||||||
// This extra layer is used by all containers as the top-most ro layer. It protects
|
// This extra layer is used by all containers as the top-most ro layer. It protects
|
||||||
// the container from unwanted side-effects on the rw layer.
|
// the container from unwanted side-effects on the rw layer.
|
||||||
func SetupInitLayer(initLayer string) error {
|
func SetupInitLayer(initLayer string) error {
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
"github.com/docker/docker/pkg/archive"
|
"github.com/docker/docker/pkg/archive"
|
||||||
)
|
)
|
||||||
|
|
||||||
// setupInitLayer populates a directory with mountpoints suitable
|
// SetupInitLayer populates a directory with mountpoints suitable
|
||||||
// for bind-mounting dockerinit into the container. T
|
// for bind-mounting dockerinit into the container. T
|
||||||
func SetupInitLayer(initLayer string) error {
|
func SetupInitLayer(initLayer string) error {
|
||||||
return nil
|
return nil
|
||||||
|
@ -106,33 +106,32 @@ func (graph *Graph) storeImage(img *image.Image, layerData archive.ArchiveReader
|
||||||
|
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
return json.NewEncoder(f).Encode(img)
|
|
||||||
} else {
|
|
||||||
// We keep this functionality here so that we can still work with the
|
|
||||||
// VFS driver during development. This will not be used for actual running
|
|
||||||
// of Windows containers. Without this code, it would not be possible to
|
|
||||||
// docker pull using the VFS driver.
|
|
||||||
|
|
||||||
// Store the layer. If layerData is not nil, unpack it into the new layer
|
|
||||||
if layerData != nil {
|
|
||||||
if err := graph.disassembleAndApplyTarLayer(img, layerData, root); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := graph.saveSize(root, int(img.Size)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
f, err := os.OpenFile(jsonPath(root), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
return json.NewEncoder(f).Encode(img)
|
return json.NewEncoder(f).Encode(img)
|
||||||
}
|
}
|
||||||
|
// We keep this functionality here so that we can still work with the
|
||||||
|
// VFS driver during development. This will not be used for actual running
|
||||||
|
// of Windows containers. Without this code, it would not be possible to
|
||||||
|
// docker pull using the VFS driver.
|
||||||
|
|
||||||
|
// Store the layer. If layerData is not nil, unpack it into the new layer
|
||||||
|
if layerData != nil {
|
||||||
|
if err := graph.disassembleAndApplyTarLayer(img, layerData, root); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := graph.saveSize(root, int(img.Size)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.OpenFile(jsonPath(root), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
return json.NewEncoder(f).Encode(img)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TarLayer returns a tar archive of the image's filesystem layer.
|
// TarLayer returns a tar archive of the image's filesystem layer.
|
||||||
|
@ -152,15 +151,14 @@ func (graph *Graph) TarLayer(img *image.Image) (arch archive.Archive, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
return wd.Export(img.ID, wd.LayerIdsToPaths(ids))
|
return wd.Export(img.ID, wd.LayerIdsToPaths(ids))
|
||||||
} else {
|
|
||||||
// We keep this functionality here so that we can still work with the VFS
|
|
||||||
// driver during development. VFS is not supported (and just will not work)
|
|
||||||
// for Windows containers.
|
|
||||||
rdr, err := graph.assembleTarLayer(img)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Debugf("[graph] TarLayer with traditional differ: %s", img.ID)
|
|
||||||
return graph.driver.Diff(img.ID, img.Parent)
|
|
||||||
}
|
|
||||||
return rdr, nil
|
|
||||||
}
|
}
|
||||||
|
// We keep this functionality here so that we can still work with the VFS
|
||||||
|
// driver during development. VFS is not supported (and just will not work)
|
||||||
|
// for Windows containers.
|
||||||
|
rdr, err := graph.assembleTarLayer(img)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Debugf("[graph] TarLayer with traditional differ: %s", img.ID)
|
||||||
|
return graph.driver.Diff(img.ID, img.Parent)
|
||||||
|
}
|
||||||
|
return rdr, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,7 @@ 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.
|
||||||
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 {
|
||||||
|
@ -101,6 +102,7 @@ func (s *TagStore) History(name string) ([]*types.ImageHistory, error) {
|
||||||
return history, err
|
return history, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetParent returns the parent 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
|
||||||
|
@ -108,6 +110,7 @@ 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.
|
||||||
func (graph *Graph) GetParentsSize(img *image.Image, size int64) int64 {
|
func (graph *Graph) GetParentsSize(img *image.Image, size int64) int64 {
|
||||||
parentImage, err := graph.GetParent(img)
|
parentImage, err := graph.GetParent(img)
|
||||||
if err != nil || parentImage == nil {
|
if err != nil || parentImage == nil {
|
||||||
|
|
|
@ -13,13 +13,21 @@ import (
|
||||||
"github.com/docker/docker/utils"
|
"github.com/docker/docker/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ImageImportConfig holds configuration to import a image.
|
||||||
type ImageImportConfig struct {
|
type ImageImportConfig struct {
|
||||||
Changes []string
|
// Changes are the container changes written to top layer.
|
||||||
InConfig io.ReadCloser
|
Changes []string
|
||||||
OutStream io.Writer
|
// InConfig is the input stream containers layered data.
|
||||||
|
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
|
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 {
|
func (s *TagStore) Import(src string, repo string, tag string, imageImportConfig *ImageImportConfig) error {
|
||||||
var (
|
var (
|
||||||
sf = streamformatter.NewJSONStreamFormatter()
|
sf = streamformatter.NewJSONStreamFormatter()
|
||||||
|
|
|
@ -18,18 +18,24 @@ var acceptedImageFilterTags = map[string]struct{}{
|
||||||
"label": {},
|
"label": {},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ImagesConfig defines the criteria to obtain a list of images.
|
||||||
type ImagesConfig struct {
|
type ImagesConfig struct {
|
||||||
|
// Filters is supported list of filters used to get list of images.
|
||||||
Filters string
|
Filters string
|
||||||
Filter string
|
// Filter the list of images by name.
|
||||||
All bool
|
Filter string
|
||||||
|
// All inditest that all the images will be returned in the list, if set to true.
|
||||||
|
All bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type ByCreated []*types.Image
|
// byCreated is a temporary type used to sort list of images on their field 'Created'.
|
||||||
|
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.
|
||||||
func (s *TagStore) Images(config *ImagesConfig) ([]*types.Image, error) {
|
func (s *TagStore) Images(config *ImagesConfig) ([]*types.Image, error) {
|
||||||
var (
|
var (
|
||||||
allImages map[string]*image.Image
|
allImages map[string]*image.Image
|
||||||
|
@ -144,7 +150,7 @@ func (s *TagStore) Images(config *ImagesConfig) ([]*types.Image, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Sort(sort.Reverse(ByCreated(images)))
|
sort.Sort(sort.Reverse(byCreated(images)))
|
||||||
|
|
||||||
return images, nil
|
return images, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ import (
|
||||||
"github.com/docker/docker/pkg/chrootarchive"
|
"github.com/docker/docker/pkg/chrootarchive"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Loads a set of images into the repository. This is the complementary of ImageExport.
|
// Load uploads a set of images into the repository. This is the complementary of ImageExport.
|
||||||
// The input stream is an uncompressed tar ball containing images and metadata.
|
// The input stream is an uncompressed tar ball containing images and metadata.
|
||||||
func (s *TagStore) Load(inTar io.ReadCloser, outStream io.Writer) error {
|
func (s *TagStore) Load(inTar io.ReadCloser, outStream io.Writer) error {
|
||||||
tmpImageDir, err := ioutil.TempDir("", "docker-import-")
|
tmpImageDir, err := ioutil.TempDir("", "docker-import-")
|
||||||
|
@ -84,7 +84,7 @@ func (s *TagStore) recursiveLoad(address, tmpImageDir string) error {
|
||||||
if _, err := s.LookupImage(address); err != nil {
|
if _, err := s.LookupImage(address); err != nil {
|
||||||
logrus.Debugf("Loading %s", address)
|
logrus.Debugf("Loading %s", address)
|
||||||
|
|
||||||
imageJson, err := ioutil.ReadFile(filepath.Join(tmpImageDir, "repo", address, "json"))
|
imageJSON, err := ioutil.ReadFile(filepath.Join(tmpImageDir, "repo", address, "json"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Debugf("Error reading json: %v", err)
|
logrus.Debugf("Error reading json: %v", err)
|
||||||
return err
|
return err
|
||||||
|
@ -95,7 +95,7 @@ func (s *TagStore) recursiveLoad(address, tmpImageDir string) error {
|
||||||
logrus.Debugf("Error reading embedded tar: %v", err)
|
logrus.Debugf("Error reading embedded tar: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
img, err := image.NewImgJSON(imageJson)
|
img, err := image.NewImgJSON(imageJSON)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Debugf("Error unmarshalling json: %v", err)
|
logrus.Debugf("Error unmarshalling json: %v", err)
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -7,6 +7,8 @@ import (
|
||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Load method is implemented here for non-linux and non-windows platforms and
|
||||||
|
// may return an error indicating that image load is not supported on other platforms.
|
||||||
func (s *TagStore) Load(inTar io.ReadCloser, outStream io.Writer) error {
|
func (s *TagStore) Load(inTar io.ReadCloser, outStream io.Writer) error {
|
||||||
return fmt.Errorf("Load is not supported on this platform")
|
return fmt.Errorf("Load is not supported on this platform")
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,12 +11,17 @@ import (
|
||||||
"github.com/docker/docker/utils"
|
"github.com/docker/docker/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 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 map[string][]string
|
MetaHeaders map[string][]string
|
||||||
AuthConfig *cliconfig.AuthConfig
|
// AuthConfig holds authentication information for authorizing with the registry.
|
||||||
OutStream io.Writer
|
AuthConfig *cliconfig.AuthConfig
|
||||||
|
// OutStream is the output writer for showing the status of the pull operation.
|
||||||
|
OutStream io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Puller is an interface to define Pull behavior.
|
||||||
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.
|
||||||
|
@ -25,6 +30,7 @@ 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.
|
||||||
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:
|
||||||
|
@ -47,6 +53,7 @@ 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.
|
||||||
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()
|
||||||
|
|
||||||
|
@ -126,7 +133,8 @@ func (s *TagStore) Pull(image string, tag string, imagePullConfig *ImagePullConf
|
||||||
return lastErr
|
return lastErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func WriteStatus(requestedTag string, out io.Writer, sf *streamformatter.StreamFormatter, layersDownloaded bool) {
|
// writeStatus shows status of the pull command.
|
||||||
|
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))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -80,9 +80,9 @@ func (p *v1Puller) pullRepository(askedTag string) error {
|
||||||
if askedTag == "" {
|
if askedTag == "" {
|
||||||
tagsList, err = p.session.GetRemoteTags(repoData.Endpoints, p.repoInfo.RemoteName)
|
tagsList, err = p.session.GetRemoteTags(repoData.Endpoints, p.repoInfo.RemoteName)
|
||||||
} else {
|
} else {
|
||||||
var tagId string
|
var tagID string
|
||||||
tagId, err = p.session.GetRemoteTag(repoData.Endpoints, p.repoInfo.RemoteName, askedTag)
|
tagID, err = p.session.GetRemoteTag(repoData.Endpoints, p.repoInfo.RemoteName, askedTag)
|
||||||
tagsList[askedTag] = tagId
|
tagsList[askedTag] = tagID
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == registry.ErrRepoNotFound && askedTag != "" {
|
if err == registry.ErrRepoNotFound && askedTag != "" {
|
||||||
|
@ -222,7 +222,7 @@ func (p *v1Puller) pullRepository(askedTag string) error {
|
||||||
if len(askedTag) > 0 {
|
if len(askedTag) > 0 {
|
||||||
requestedTag = utils.ImageReference(p.repoInfo.LocalName, askedTag)
|
requestedTag = utils.ImageReference(p.repoInfo.LocalName, askedTag)
|
||||||
}
|
}
|
||||||
WriteStatus(requestedTag, out, p.sf, layersDownloaded)
|
writeStatus(requestedTag, out, p.sf, layersDownloaded)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,7 @@ func (p *v2Puller) pullV2Repository(tag string) (err error) {
|
||||||
layersDownloaded = layersDownloaded || pulledNew
|
layersDownloaded = layersDownloaded || pulledNew
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteStatus(taggedName, p.config.OutStream, p.sf, layersDownloaded)
|
writeStatus(taggedName, p.config.OutStream, p.sf, layersDownloaded)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,13 +10,19 @@ import (
|
||||||
"github.com/docker/docker/registry"
|
"github.com/docker/docker/registry"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 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 map[string][]string
|
MetaHeaders map[string][]string
|
||||||
AuthConfig *cliconfig.AuthConfig
|
// AuthConfig holds authentication information for authorizing with the registry.
|
||||||
Tag string
|
AuthConfig *cliconfig.AuthConfig
|
||||||
OutStream io.Writer
|
// 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 string
|
||||||
|
// OutStream is the output writer for showing the status of the push operation.
|
||||||
|
OutStream io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pusher is an interface to define Push behavior.
|
||||||
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.
|
||||||
|
@ -25,6 +31,7 @@ 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.
|
||||||
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:
|
||||||
|
@ -51,6 +58,8 @@ func (s *TagStore) NewPusher(endpoint registry.APIEndpoint, localRepo Repository
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Allow to interrupt current push when new push of same image is done.
|
// FIXME: Allow to interrupt current push when new push of same image is done.
|
||||||
|
|
||||||
|
// Push a image to the repo.
|
||||||
func (s *TagStore) Push(localName string, imagePushConfig *ImagePushConfig) error {
|
func (s *TagStore) Push(localName string, imagePushConfig *ImagePushConfig) error {
|
||||||
var sf = streamformatter.NewJSONStreamFormatter()
|
var sf = streamformatter.NewJSONStreamFormatter()
|
||||||
|
|
||||||
|
|
|
@ -87,12 +87,12 @@ func (p *v2Pusher) pushV2Repository(tag string) error {
|
||||||
func (p *v2Pusher) pushV2Tag(tag string) error {
|
func (p *v2Pusher) pushV2Tag(tag string) error {
|
||||||
logrus.Debugf("Pushing repository: %s:%s", p.repo.Name(), tag)
|
logrus.Debugf("Pushing repository: %s:%s", p.repo.Name(), tag)
|
||||||
|
|
||||||
layerId, exists := p.localRepo[tag]
|
layerID, exists := p.localRepo[tag]
|
||||||
if !exists {
|
if !exists {
|
||||||
return fmt.Errorf("tag does not exist: %s", tag)
|
return fmt.Errorf("tag does not exist: %s", tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
layer, err := p.graph.Get(layerId)
|
layer, err := p.graph.Get(layerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ func (dcs dumbCredentialStore) Basic(*url.URL) (string, string) {
|
||||||
return dcs.auth.Username, dcs.auth.Password
|
return dcs.auth.Username, dcs.auth.Password
|
||||||
}
|
}
|
||||||
|
|
||||||
// v2 only
|
// NewV2Repository creates a v2 only repository.
|
||||||
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,7 +10,7 @@ import (
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
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 {
|
||||||
return nil, fmt.Errorf("No such image %s", name)
|
return nil, fmt.Errorf("No such image %s", name)
|
||||||
|
|
|
@ -24,8 +24,10 @@ import (
|
||||||
"github.com/docker/libtrust"
|
"github.com/docker/libtrust"
|
||||||
)
|
)
|
||||||
|
|
||||||
const DEFAULTTAG = "latest"
|
// DefaultTag defines the default tag used when performing images related actions and no tag string is specified
|
||||||
|
const DefaultTag = "latest"
|
||||||
|
|
||||||
|
// TagStore contains information to push and pull to the repo.
|
||||||
type TagStore struct {
|
type TagStore struct {
|
||||||
path string
|
path string
|
||||||
graph *Graph
|
graph *Graph
|
||||||
|
@ -41,16 +43,17 @@ type TagStore struct {
|
||||||
trustService *trust.TrustStore
|
trustService *trust.TrustStore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Repository maps image id to image tag.
|
||||||
type Repository map[string]string
|
type Repository map[string]string
|
||||||
|
|
||||||
// update Repository mapping with content of u
|
// Update updates repository mapping with content of repository 'u'.
|
||||||
func (r Repository) Update(u Repository) {
|
func (r Repository) Update(u Repository) {
|
||||||
for k, v := range u {
|
for k, v := range u {
|
||||||
r[k] = v
|
r[k] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// return true if the contents of u Repository, are wholly contained in r Repository
|
// Contains returns true if the contents of u Repository, are wholly contained in r Repository.
|
||||||
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
|
||||||
|
@ -61,6 +64,7 @@ func (r Repository) Contains(u Repository) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TagStoreConfig holds tag store configuration.
|
||||||
type TagStoreConfig struct {
|
type TagStoreConfig struct {
|
||||||
Graph *Graph
|
Graph *Graph
|
||||||
Key libtrust.PrivateKey
|
Key libtrust.PrivateKey
|
||||||
|
@ -69,6 +73,7 @@ type TagStoreConfig struct {
|
||||||
Trust *trust.TrustStore
|
Trust *trust.TrustStore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewTagStore creates a tag store to specified path.
|
||||||
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 {
|
||||||
|
@ -121,12 +126,13 @@ func (store *TagStore) reload() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LookupImage returns the image from the store.
|
||||||
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 = DefaultTag
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
|
@ -152,7 +158,7 @@ func (store *TagStore) LookupImage(name string) (*image.Image, error) {
|
||||||
return img, nil
|
return img, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return 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 image.
|
||||||
// Eg. {"43b5f19b10584": {"base:latest", "base:v1"}}
|
// Eg. {"43b5f19b10584": {"base:latest", "base:v1"}}
|
||||||
func (store *TagStore) ByID() map[string][]string {
|
func (store *TagStore) ByID() map[string][]string {
|
||||||
store.Lock()
|
store.Lock()
|
||||||
|
@ -172,6 +178,7 @@ func (store *TagStore) ByID() map[string][]string {
|
||||||
return byID
|
return byID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ImageName returns name of the image.
|
||||||
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]
|
||||||
|
@ -179,6 +186,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.
|
||||||
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 {
|
||||||
|
@ -199,6 +207,7 @@ func (store *TagStore) DeleteAll(id string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete removes a repo identified by a given name from the store
|
||||||
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()
|
||||||
|
@ -231,10 +240,13 @@ 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.
|
||||||
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.
|
||||||
|
// 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()
|
||||||
|
@ -319,6 +331,7 @@ func (store *TagStore) SetDigest(repoName, digest, imageName string) error {
|
||||||
return store.save()
|
return store.save()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get returns a repo from the store.
|
||||||
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()
|
||||||
|
@ -332,6 +345,7 @@ 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.
|
||||||
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)
|
||||||
|
|
||||||
|
@ -361,6 +375,7 @@ func (store *TagStore) GetImage(repoName, refOrID string) (*image.Image, error)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRepoRefs returns list of repos.
|
||||||
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)
|
||||||
|
@ -375,7 +390,7 @@ func (store *TagStore) GetRepoRefs() map[string][]string {
|
||||||
return reporefs
|
return reporefs
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the name of a repository
|
// validateRepoName validates the name of a repository.
|
||||||
func validateRepoName(name string) error {
|
func validateRepoName(name string) error {
|
||||||
if name == "" {
|
if name == "" {
|
||||||
return fmt.Errorf("Repository name can't be empty")
|
return fmt.Errorf("Repository name can't be empty")
|
||||||
|
|
|
@ -119,17 +119,17 @@ func TestLookupImage(t *testing.T) {
|
||||||
testOfficialImageName + ":" + testOfficialImageID,
|
testOfficialImageName + ":" + testOfficialImageID,
|
||||||
testOfficialImageName + ":" + testOfficialImageIDShort,
|
testOfficialImageName + ":" + testOfficialImageIDShort,
|
||||||
testOfficialImageName,
|
testOfficialImageName,
|
||||||
testOfficialImageName + ":" + DEFAULTTAG,
|
testOfficialImageName + ":" + DefaultTag,
|
||||||
"docker.io/" + testOfficialImageName,
|
"docker.io/" + testOfficialImageName,
|
||||||
"docker.io/" + testOfficialImageName + ":" + DEFAULTTAG,
|
"docker.io/" + testOfficialImageName + ":" + DefaultTag,
|
||||||
"index.docker.io/" + testOfficialImageName,
|
"index.docker.io/" + testOfficialImageName,
|
||||||
"index.docker.io/" + testOfficialImageName + ":" + DEFAULTTAG,
|
"index.docker.io/" + testOfficialImageName + ":" + DefaultTag,
|
||||||
"library/" + testOfficialImageName,
|
"library/" + testOfficialImageName,
|
||||||
"library/" + testOfficialImageName + ":" + DEFAULTTAG,
|
"library/" + testOfficialImageName + ":" + DefaultTag,
|
||||||
"docker.io/library/" + testOfficialImageName,
|
"docker.io/library/" + testOfficialImageName,
|
||||||
"docker.io/library/" + testOfficialImageName + ":" + DEFAULTTAG,
|
"docker.io/library/" + testOfficialImageName + ":" + DefaultTag,
|
||||||
"index.docker.io/library/" + testOfficialImageName,
|
"index.docker.io/library/" + testOfficialImageName,
|
||||||
"index.docker.io/library/" + testOfficialImageName + ":" + DEFAULTTAG,
|
"index.docker.io/library/" + testOfficialImageName + ":" + DefaultTag,
|
||||||
}
|
}
|
||||||
|
|
||||||
privateLookups := []string{
|
privateLookups := []string{
|
||||||
|
@ -138,7 +138,7 @@ func TestLookupImage(t *testing.T) {
|
||||||
testPrivateImageName + ":" + testPrivateImageID,
|
testPrivateImageName + ":" + testPrivateImageID,
|
||||||
testPrivateImageName + ":" + testPrivateImageIDShort,
|
testPrivateImageName + ":" + testPrivateImageIDShort,
|
||||||
testPrivateImageName,
|
testPrivateImageName,
|
||||||
testPrivateImageName + ":" + DEFAULTTAG,
|
testPrivateImageName + ":" + DefaultTag,
|
||||||
}
|
}
|
||||||
|
|
||||||
invalidLookups := []string{
|
invalidLookups := []string{
|
||||||
|
|
|
@ -25,6 +25,7 @@ packages=(
|
||||||
daemon/network
|
daemon/network
|
||||||
docker
|
docker
|
||||||
dockerinit
|
dockerinit
|
||||||
|
graph
|
||||||
image
|
image
|
||||||
integration-cli
|
integration-cli
|
||||||
pkg/chrootarchive
|
pkg/chrootarchive
|
||||||
|
|
Loading…
Reference in a new issue