graph/push.go
6856a6b1
 package graph
 
 import (
 	"fmt"
 	"io"
 
6f4d8470
 	"github.com/Sirupsen/logrus"
bb9da6ba
 	"github.com/docker/docker/cliconfig"
0cd6c05d
 	"github.com/docker/docker/pkg/streamformatter"
6856a6b1
 	"github.com/docker/docker/registry"
 )
 
d456401f
 type ImagePushConfig struct {
 	MetaHeaders map[string][]string
bb9da6ba
 	AuthConfig  *cliconfig.AuthConfig
d456401f
 	Tag         string
 	OutStream   io.Writer
 }
 
19515a7a
 type Pusher interface {
 	// 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.
 	//
 	// TODO(tiborvass): have Push() take a reference to repository + tag, so that the pusher itself is repository-agnostic.
 	Push() (fallback bool, err error)
6856a6b1
 }
 
19515a7a
 func (s *TagStore) NewPusher(endpoint registry.APIEndpoint, localRepo Repository, repoInfo *registry.RepositoryInfo, imagePushConfig *ImagePushConfig, sf *streamformatter.StreamFormatter) (Pusher, error) {
 	switch endpoint.Version {
 	case registry.APIVersion2:
 		return &v2Pusher{
810d3b26
 			TagStore:   s,
 			endpoint:   endpoint,
 			localRepo:  localRepo,
 			repoInfo:   repoInfo,
 			config:     imagePushConfig,
 			sf:         sf,
 			layersSeen: make(map[string]bool),
19515a7a
 		}, nil
 	case registry.APIVersion1:
 		return &v1Pusher{
 			TagStore:  s,
 			endpoint:  endpoint,
 			localRepo: localRepo,
 			repoInfo:  repoInfo,
 			config:    imagePushConfig,
 			sf:        sf,
 		}, nil
 	}
 	return nil, fmt.Errorf("unknown version %d for registry %s", endpoint.Version, endpoint.URL)
629815b4
 }
 
6856a6b1
 // FIXME: Allow to interrupt current push when new push of same image is done.
d456401f
 func (s *TagStore) Push(localName string, imagePushConfig *ImagePushConfig) error {
19515a7a
 	var sf = streamformatter.NewJSONStreamFormatter()
6856a6b1
 
568f86eb
 	// Resolve the Repository name from fqn to RepositoryInfo
03d3d79b
 	repoInfo, err := s.registryService.ResolveRepository(localName)
568f86eb
 	if err != nil {
c79b9bab
 		return err
568f86eb
 	}
 
29ea36a8
 	endpoints, err := s.registryService.LookupPushEndpoints(repoInfo.CanonicalName)
db2d875b
 	if err != nil {
c79b9bab
 		return err
6856a6b1
 	}
 
db2d875b
 	reposLen := 1
d456401f
 	if imagePushConfig.Tag == "" {
db2d875b
 		reposLen = len(s.Repositories[repoInfo.LocalName])
750b41ce
 	}
d456401f
 
 	imagePushConfig.OutStream.Write(sf.FormatStatus("", "The push refers to a repository [%s] (len: %d)", repoInfo.CanonicalName, reposLen))
 
db2d875b
 	// If it fails, try to get the repository
 	localRepo, exists := s.Repositories[repoInfo.LocalName]
 	if !exists {
c79b9bab
 		return fmt.Errorf("Repository does not exist: %s", repoInfo.LocalName)
db2d875b
 	}
d172f125
 
19515a7a
 	var lastErr error
 	for _, endpoint := range endpoints {
 		logrus.Debugf("Trying to push %s to %s %s", repoInfo.CanonicalName, endpoint.URL, endpoint.Version)
 
 		pusher, err := s.NewPusher(endpoint, localRepo, repoInfo, imagePushConfig, sf)
 		if err != nil {
 			lastErr = err
 			continue
d172f125
 		}
19515a7a
 		if fallback, err := pusher.Push(); err != nil {
 			if fallback {
 				lastErr = err
 				continue
 			}
 			logrus.Debugf("Not continuing with error: %v", err)
 			return err
d172f125
 
 		}
 
19515a7a
 		s.eventsService.Log("push", repoInfo.LocalName, "")
 		return nil
6856a6b1
 	}
db2d875b
 
19515a7a
 	if lastErr == nil {
 		lastErr = fmt.Errorf("no endpoints found for %s", repoInfo.CanonicalName)
 	}
 	return lastErr
6856a6b1
 }