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