55 "crypto/x509"
66 "encoding/json"
77 "fmt"
8+ "io/ioutil"
89 "net"
910 "net/http"
1011 "net/url"
@@ -19,6 +20,7 @@ import (
1920 ecr "github.com/awslabs/amazon-ecr-credential-helper/ecr-login"
2021 ecrapi "github.com/awslabs/amazon-ecr-credential-helper/ecr-login/api"
2122 "github.com/concourse/retryhttp"
23+ "github.com/docker/distribution"
2224 "github.com/docker/distribution/digest"
2325 _ "github.com/docker/distribution/manifest/schema1"
2426 _ "github.com/docker/distribution/manifest/schema2"
@@ -112,7 +114,7 @@ func main() {
112114 json .NewEncoder (os .Stdout ).Encode (response )
113115}
114116
115- func fetchDigest (client * http.Client , manifestURL , repository , tag string ) (string , bool ) {
117+ func headDigest (client * http.Client , manifestURL , repository , tag string ) (string , bool ) {
116118 manifestRequest , err := http .NewRequest ("HEAD" , manifestURL , nil )
117119 fatalIf ("failed to build manifest request" , err )
118120 manifestRequest .Header .Add ("Accept" , "application/vnd.docker.distribution.manifest.v2+json" )
@@ -122,6 +124,7 @@ func fetchDigest(client *http.Client, manifestURL, repository, tag string) (stri
122124 fatalIf ("failed to fetch manifest" , err )
123125
124126 defer manifestResponse .Body .Close ()
127+
125128 if manifestResponse .StatusCode == http .StatusNotFound {
126129 return "" , false
127130 }
@@ -132,12 +135,42 @@ func fetchDigest(client *http.Client, manifestURL, repository, tag string) (stri
132135
133136 digest := manifestResponse .Header .Get ("Docker-Content-Digest" )
134137 if digest == "" {
135- fatal ( "no digest header returned" )
138+ return fetchDigest ( client , manifestURL , repository , tag )
136139 }
137140
138141 return digest , true
139142}
140143
144+ func fetchDigest (client * http.Client , manifestURL , repository , tag string ) (string , bool ) {
145+ manifestRequest , err := http .NewRequest ("GET" , manifestURL , nil )
146+ fatalIf ("failed to build manifest request" , err )
147+ manifestRequest .Header .Add ("Accept" , "application/vnd.docker.distribution.manifest.v2+json" )
148+ manifestRequest .Header .Add ("Accept" , "application/json" )
149+
150+ manifestResponse , err := client .Do (manifestRequest )
151+ fatalIf ("failed to fetch manifest" , err )
152+
153+ defer manifestResponse .Body .Close ()
154+
155+ if manifestResponse .StatusCode == http .StatusNotFound {
156+ return "" , false
157+ }
158+
159+ if manifestResponse .StatusCode != http .StatusOK {
160+ fatal (fmt .Sprintf ("failed to fetch digest for image '%s:%s': %s\n does the image exist?" , repository , tag , manifestResponse .Status ))
161+ }
162+
163+ ctHeader := manifestResponse .Header .Get ("Content-Type" )
164+
165+ bytes , err := ioutil .ReadAll (manifestResponse .Body )
166+ fatalIf ("failed to read response body" , err )
167+
168+ _ , desc , err := distribution .UnmarshalManifest (ctHeader , bytes )
169+ fatalIf ("failed to unmarshal manifest" , err )
170+
171+ return string (desc .Digest ), true
172+ }
173+
141174func makeTransport (logger lager.Logger , request CheckRequest , registryHost string , repository string ) (http.RoundTripper , string ) {
142175 // for non self-signed registries, caCertPool must be nil in order to use the system certs
143176 var caCertPool * x509.CertPool
0 commit comments