/graph fix lin errors/warnings

Addresses #14756
Signed-off-by: Srini Brahmaroutu <srbrahma@us.ibm.com>
This commit is contained in:
Srini Brahmaroutu 2015-07-21 16:21:45 +00:00 committed by Srini Brahmaroutu
parent 0f85fadb4e
commit 1d6e443119
21 changed files with 140 additions and 87 deletions

View File

@ -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)
} }

View File

@ -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 == "" {

View File

@ -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 is the set of tags to export.
Names []string 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
} }

View File

@ -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)

View File

@ -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 {

View File

@ -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
@ -107,7 +107,7 @@ func (graph *Graph) storeImage(img *image.Image, layerData archive.ArchiveReader
defer f.Close() defer f.Close()
return json.NewEncoder(f).Encode(img) return json.NewEncoder(f).Encode(img)
} else { }
// We keep this functionality here so that we can still work with the // 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 // VFS driver during development. This will not be used for actual running
// of Windows containers. Without this code, it would not be possible to // of Windows containers. Without this code, it would not be possible to
@ -132,7 +132,6 @@ func (graph *Graph) storeImage(img *image.Image, layerData archive.ArchiveReader
defer f.Close() defer f.Close()
return json.NewEncoder(f).Encode(img) 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,7 +151,7 @@ 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 // 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) // driver during development. VFS is not supported (and just will not work)
// for Windows containers. // for Windows containers.
@ -162,5 +161,4 @@ func (graph *Graph) TarLayer(img *image.Image) (arch archive.Archive, err error)
return graph.driver.Diff(img.ID, img.Parent) return graph.driver.Diff(img.ID, img.Parent)
} }
return rdr, nil return rdr, nil
}
} }

View File

@ -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 {

View File

@ -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 are the container changes written to top layer.
Changes []string Changes []string
// InConfig is the input stream containers layered data.
InConfig io.ReadCloser InConfig io.ReadCloser
// OutStream is the output stream where the image is written.
OutStream io.Writer 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()

View File

@ -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 the list of images by name.
Filter string Filter string
// All inditest that all the images will be returned in the list, if set to true.
All bool 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
} }

View File

@ -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

View File

@ -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")
} }

View File

@ -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 holds authentication information for authorizing with the registry.
AuthConfig *cliconfig.AuthConfig AuthConfig *cliconfig.AuthConfig
// 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.
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 {

View File

@ -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
} }

View File

@ -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
} }

View File

@ -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 holds authentication information for authorizing 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 string Tag string
// 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.
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()

View File

@ -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
} }

View File

@ -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()

View File

@ -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)

View File

@ -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")

View File

@ -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{

View File

@ -25,6 +25,7 @@ packages=(
daemon/network daemon/network
docker docker
dockerinit dockerinit
graph
image image
integration-cli integration-cli
pkg/chrootarchive pkg/chrootarchive