@@ -29,6 +29,7 @@ import (
2929 "strconv"
3030 "strings"
3131 "testing"
32+ "time"
3233
3334 "github.com/containerd/containerd/remotes"
3435 digest "github.com/opencontainers/go-digest"
@@ -192,6 +193,93 @@ func TestBadTokenResolver(t *testing.T) {
192193 }
193194}
194195
196+ func TestHostFailureFallbackResolver (t * testing.T ) {
197+ sf := func (h http.Handler ) (string , ResolverOptions , func ()) {
198+ s := httptest .NewServer (h )
199+ base := s .URL [7 :] // strip "http://"
200+
201+ options := ResolverOptions {}
202+ createHost := func (host string ) RegistryHost {
203+ return RegistryHost {
204+ Client : & http.Client {
205+ // Set the timeout so we timeout waiting for the non-responsive HTTP server
206+ Timeout : 500 * time .Millisecond ,
207+ },
208+ Host : host ,
209+ Scheme : "http" ,
210+ Path : "/v2" ,
211+ Capabilities : HostCapabilityPull | HostCapabilityResolve | HostCapabilityPush ,
212+ }
213+ }
214+
215+ // Create an unstarted HTTP server. We use this to generate a random port.
216+ notRunning := httptest .NewUnstartedServer (nil )
217+ notRunningBase := notRunning .Listener .Addr ().String ()
218+
219+ // Override hosts with two hosts
220+ options .Hosts = func (host string ) ([]RegistryHost , error ) {
221+ return []RegistryHost {
222+ createHost (notRunningBase ), // This host IS running, but with a non-responsive HTTP server
223+ createHost (base ), // This host IS running
224+ }, nil
225+ }
226+
227+ return base , options , s .Close
228+ }
229+
230+ runBasicTest (t , "testname" , sf )
231+ }
232+
233+ func TestHostTLSFailureFallbackResolver (t * testing.T ) {
234+ sf := func (h http.Handler ) (string , ResolverOptions , func ()) {
235+ // Start up two servers
236+ server := httptest .NewServer (h )
237+ httpBase := server .URL [7 :] // strip "http://"
238+
239+ tlsServer := httptest .NewUnstartedServer (h )
240+ tlsServer .StartTLS ()
241+ httpsBase := tlsServer .URL [8 :] // strip "https://"
242+
243+ capool := x509 .NewCertPool ()
244+ cert , _ := x509 .ParseCertificate (tlsServer .TLS .Certificates [0 ].Certificate [0 ])
245+ capool .AddCert (cert )
246+
247+ client := & http.Client {
248+ Transport : & http.Transport {
249+ TLSClientConfig : & tls.Config {
250+ RootCAs : capool ,
251+ },
252+ },
253+ }
254+
255+ options := ResolverOptions {}
256+ createHost := func (host string ) RegistryHost {
257+ return RegistryHost {
258+ Client : client ,
259+ Host : host ,
260+ Scheme : "https" ,
261+ Path : "/v2" ,
262+ Capabilities : HostCapabilityPull | HostCapabilityResolve | HostCapabilityPush ,
263+ }
264+ }
265+
266+ // Override hosts with two hosts
267+ options .Hosts = func (host string ) ([]RegistryHost , error ) {
268+ return []RegistryHost {
269+ createHost (httpBase ), // This host is serving plain HTTP
270+ createHost (httpsBase ), // This host is serving TLS
271+ }, nil
272+ }
273+
274+ return httpBase , options , func () {
275+ server .Close ()
276+ tlsServer .Close ()
277+ }
278+ }
279+
280+ runBasicTest (t , "testname" , sf )
281+ }
282+
195283func withTokenServer (th http.Handler , creds func (string ) (string , string , error )) func (h http.Handler ) (string , ResolverOptions , func ()) {
196284 return func (h http.Handler ) (string , ResolverOptions , func ()) {
197285 s := httptest .NewUnstartedServer (th )
0 commit comments