github.com/endophage/docker@v1.4.2-0.20161027011718-242853499895/plugin/distribution/push.go (about) 1 package distribution 2 3 import ( 4 "crypto/sha256" 5 "io" 6 "net/http" 7 8 "github.com/Sirupsen/logrus" 9 "github.com/docker/distribution" 10 "github.com/docker/distribution/digest" 11 "github.com/docker/distribution/manifest/schema2" 12 "github.com/docker/docker/api/types" 13 dockerdist "github.com/docker/docker/distribution" 14 "github.com/docker/docker/reference" 15 "github.com/docker/docker/registry" 16 "golang.org/x/net/context" 17 ) 18 19 // Push pushes a plugin to a registry. 20 func Push(name string, rs registry.Service, metaHeader http.Header, authConfig *types.AuthConfig, config io.ReadCloser, layers io.ReadCloser) (digest.Digest, error) { 21 ref, err := reference.ParseNamed(name) 22 if err != nil { 23 return "", err 24 } 25 26 repoInfo, err := rs.ResolveRepository(ref) 27 if err != nil { 28 return "", err 29 } 30 31 if err := dockerdist.ValidateRepoName(repoInfo.Name()); err != nil { 32 return "", err 33 } 34 35 endpoints, err := rs.LookupPushEndpoints(repoInfo.Hostname()) 36 if err != nil { 37 return "", err 38 } 39 40 var confirmedV2 bool 41 var repository distribution.Repository 42 for _, endpoint := range endpoints { 43 if confirmedV2 && endpoint.Version == registry.APIVersion1 { 44 logrus.Debugf("Skipping v1 endpoint %s because v2 registry was detected", endpoint.URL) 45 continue 46 } 47 repository, confirmedV2, err = dockerdist.NewV2Repository(context.Background(), repoInfo, endpoint, metaHeader, authConfig, "push", "pull") 48 if err != nil { 49 return "", err 50 } 51 if !confirmedV2 { 52 return "", ErrUnsupportedRegistry 53 } 54 logrus.Debugf("Trying to push %s to %s %s", repoInfo.Name(), endpoint.URL, endpoint.Version) 55 // This means that we found an endpoint. and we are ready to push 56 break 57 } 58 59 // Returns a reference to the repository's blob service. 60 blobs := repository.Blobs(context.Background()) 61 62 // Descriptor = {mediaType, size, digest} 63 var descs []distribution.Descriptor 64 65 for i, f := range []io.ReadCloser{config, layers} { 66 bw, err := blobs.Create(context.Background()) 67 if err != nil { 68 logrus.Debugf("Error in blobs.Create: %v", err) 69 return "", err 70 } 71 h := sha256.New() 72 r := io.TeeReader(f, h) 73 _, err = io.Copy(bw, r) 74 if err != nil { 75 f.Close() 76 logrus.Debugf("Error in io.Copy: %v", err) 77 return "", err 78 } 79 f.Close() 80 mt := schema2.MediaTypeLayer 81 if i == 0 { 82 mt = schema2.MediaTypePluginConfig 83 } 84 // Commit completes the write process to the BlobService. 85 // The descriptor arg to Commit is called the "provisional" descriptor and 86 // used for validation. 87 // The returned descriptor should be the one used. Its called the "Canonical" 88 // descriptor. 89 desc, err := bw.Commit(context.Background(), distribution.Descriptor{ 90 MediaType: mt, 91 // XXX: What about the Size? 92 Digest: digest.NewDigest("sha256", h), 93 }) 94 if err != nil { 95 logrus.Debugf("Error in bw.Commit: %v", err) 96 return "", err 97 } 98 // The canonical descriptor is set the mediatype again, just in case. 99 // Don't touch the digest or the size here. 100 desc.MediaType = mt 101 logrus.Debugf("pushed blob: %s %s", desc.MediaType, desc.Digest) 102 descs = append(descs, desc) 103 } 104 105 // XXX: schema2.Versioned needs a MediaType as well. 106 // "application/vnd.docker.distribution.manifest.v2+json" 107 m, err := schema2.FromStruct(schema2.Manifest{Versioned: schema2.SchemaVersion, Config: descs[0], Layers: descs[1:]}) 108 if err != nil { 109 logrus.Debugf("error in schema2.FromStruct: %v", err) 110 return "", err 111 } 112 113 msv, err := repository.Manifests(context.Background()) 114 if err != nil { 115 logrus.Debugf("error in repository.Manifests: %v", err) 116 return "", err 117 } 118 119 _, pl, err := m.Payload() 120 if err != nil { 121 logrus.Debugf("error in m.Payload: %v", err) 122 return "", err 123 } 124 125 logrus.Debugf("Pushed manifest: %s", pl) 126 127 tag := DefaultTag 128 if tagged, ok := ref.(reference.NamedTagged); ok { 129 tag = tagged.Tag() 130 } 131 132 return msv.Put(context.Background(), m, distribution.WithTag(tag)) 133 }