github.com/crquan/docker@v1.8.1/graph/push.go (about) 1 package graph 2 3 import ( 4 "fmt" 5 "io" 6 7 "github.com/Sirupsen/logrus" 8 "github.com/docker/docker/cliconfig" 9 "github.com/docker/docker/pkg/streamformatter" 10 "github.com/docker/docker/registry" 11 ) 12 13 type ImagePushConfig struct { 14 MetaHeaders map[string][]string 15 AuthConfig *cliconfig.AuthConfig 16 Tag string 17 OutStream io.Writer 18 } 19 20 type Pusher interface { 21 // Push tries to push the image configured at the creation of Pusher. 22 // Push returns an error if any, as well as a boolean that determines whether to retry Push on the next configured endpoint. 23 // 24 // TODO(tiborvass): have Push() take a reference to repository + tag, so that the pusher itself is repository-agnostic. 25 Push() (fallback bool, err error) 26 } 27 28 func (s *TagStore) NewPusher(endpoint registry.APIEndpoint, localRepo Repository, repoInfo *registry.RepositoryInfo, imagePushConfig *ImagePushConfig, sf *streamformatter.StreamFormatter) (Pusher, error) { 29 switch endpoint.Version { 30 case registry.APIVersion2: 31 return &v2Pusher{ 32 TagStore: s, 33 endpoint: endpoint, 34 localRepo: localRepo, 35 repoInfo: repoInfo, 36 config: imagePushConfig, 37 sf: sf, 38 }, nil 39 case registry.APIVersion1: 40 return &v1Pusher{ 41 TagStore: s, 42 endpoint: endpoint, 43 localRepo: localRepo, 44 repoInfo: repoInfo, 45 config: imagePushConfig, 46 sf: sf, 47 }, nil 48 } 49 return nil, fmt.Errorf("unknown version %d for registry %s", endpoint.Version, endpoint.URL) 50 } 51 52 // FIXME: Allow to interrupt current push when new push of same image is done. 53 func (s *TagStore) Push(localName string, imagePushConfig *ImagePushConfig) error { 54 var sf = streamformatter.NewJSONStreamFormatter() 55 56 // Resolve the Repository name from fqn to RepositoryInfo 57 repoInfo, err := s.registryService.ResolveRepository(localName) 58 if err != nil { 59 return err 60 } 61 62 endpoints, err := s.registryService.LookupPushEndpoints(repoInfo.CanonicalName) 63 if err != nil { 64 return err 65 } 66 67 reposLen := 1 68 if imagePushConfig.Tag == "" { 69 reposLen = len(s.Repositories[repoInfo.LocalName]) 70 } 71 72 imagePushConfig.OutStream.Write(sf.FormatStatus("", "The push refers to a repository [%s] (len: %d)", repoInfo.CanonicalName, reposLen)) 73 74 // If it fails, try to get the repository 75 localRepo, exists := s.Repositories[repoInfo.LocalName] 76 if !exists { 77 return fmt.Errorf("Repository does not exist: %s", repoInfo.LocalName) 78 } 79 80 var lastErr error 81 for _, endpoint := range endpoints { 82 logrus.Debugf("Trying to push %s to %s %s", repoInfo.CanonicalName, endpoint.URL, endpoint.Version) 83 84 pusher, err := s.NewPusher(endpoint, localRepo, repoInfo, imagePushConfig, sf) 85 if err != nil { 86 lastErr = err 87 continue 88 } 89 if fallback, err := pusher.Push(); err != nil { 90 if fallback { 91 lastErr = err 92 continue 93 } 94 logrus.Debugf("Not continuing with error: %v", err) 95 return err 96 97 } 98 99 s.eventsService.Log("push", repoInfo.LocalName, "") 100 return nil 101 } 102 103 if lastErr == nil { 104 lastErr = fmt.Errorf("no endpoints found for %s", repoInfo.CanonicalName) 105 } 106 return lastErr 107 }