浏览代码

Merge pull request #3431 from shin-/ping_standalone_check

Check standalone header when pinging a registry server.
Michael Crosby 11 年之前
父节点
当前提交
1d0aeae339
共有 2 个文件被更改,包括 32 次插入13 次删除
  1. 30 12
      registry/registry.go
  2. 2 1
      registry/registry_test.go

+ 30 - 12
registry/registry.go

@@ -25,11 +25,11 @@ var (
 	ErrLoginRequired         = errors.New("Authentication is required.")
 	ErrLoginRequired         = errors.New("Authentication is required.")
 )
 )
 
 
-func pingRegistryEndpoint(endpoint string) error {
+func pingRegistryEndpoint(endpoint string) (bool, error) {
 	if endpoint == auth.IndexServerAddress() {
 	if endpoint == auth.IndexServerAddress() {
 		// Skip the check, we now this one is valid
 		// Skip the check, we now this one is valid
 		// (and we never want to fallback to http in case of error)
 		// (and we never want to fallback to http in case of error)
-		return nil
+		return false, nil
 	}
 	}
 	httpDial := func(proto string, addr string) (net.Conn, error) {
 	httpDial := func(proto string, addr string) (net.Conn, error) {
 		// Set the connect timeout to 5 seconds
 		// Set the connect timeout to 5 seconds
@@ -45,14 +45,26 @@ func pingRegistryEndpoint(endpoint string) error {
 	client := &http.Client{Transport: httpTransport}
 	client := &http.Client{Transport: httpTransport}
 	resp, err := client.Get(endpoint + "_ping")
 	resp, err := client.Get(endpoint + "_ping")
 	if err != nil {
 	if err != nil {
-		return err
+		return false, err
 	}
 	}
 	defer resp.Body.Close()
 	defer resp.Body.Close()
 
 
 	if resp.Header.Get("X-Docker-Registry-Version") == "" {
 	if resp.Header.Get("X-Docker-Registry-Version") == "" {
-		return errors.New("This does not look like a Registry server (\"X-Docker-Registry-Version\" header not found in the response)")
+		return false, errors.New("This does not look like a Registry server (\"X-Docker-Registry-Version\" header not found in the response)")
 	}
 	}
-	return nil
+
+	standalone := resp.Header.Get("X-Docker-Registry-Standalone")
+	utils.Debugf("Registry standalone header: '%s'", standalone)
+	// If the header is absent, we assume true for compatibility with earlier
+	// versions of the registry
+	if standalone == "" {
+		return true, nil
+	// Accepted values are "true" (case-insensitive) and "1".
+	} else if strings.EqualFold(standalone, "true") || standalone == "1" {
+		return true, nil
+	}
+	// Otherwise, not standalone
+	return false, nil
 }
 }
 
 
 func validateRepositoryName(repositoryName string) error {
 func validateRepositoryName(repositoryName string) error {
@@ -122,16 +134,16 @@ func ExpandAndVerifyRegistryUrl(hostname string) (string, error) {
 			// there is no path given. Expand with default path
 			// there is no path given. Expand with default path
 			hostname = hostname + "/v1/"
 			hostname = hostname + "/v1/"
 		}
 		}
-		if err := pingRegistryEndpoint(hostname); err != nil {
+		if _, err := pingRegistryEndpoint(hostname); err != nil {
 			return "", errors.New("Invalid Registry endpoint: " + err.Error())
 			return "", errors.New("Invalid Registry endpoint: " + err.Error())
 		}
 		}
 		return hostname, nil
 		return hostname, nil
 	}
 	}
 	endpoint := fmt.Sprintf("https://%s/v1/", hostname)
 	endpoint := fmt.Sprintf("https://%s/v1/", hostname)
-	if err := pingRegistryEndpoint(endpoint); err != nil {
+	if _, err := pingRegistryEndpoint(endpoint); err != nil {
 		utils.Debugf("Registry %s does not work (%s), falling back to http", endpoint, err)
 		utils.Debugf("Registry %s does not work (%s), falling back to http", endpoint, err)
 		endpoint = fmt.Sprintf("http://%s/v1/", hostname)
 		endpoint = fmt.Sprintf("http://%s/v1/", hostname)
-		if err = pingRegistryEndpoint(endpoint); err != nil {
+		if _, err = pingRegistryEndpoint(endpoint); err != nil {
 			//TODO: triggering highland build can be done there without "failing"
 			//TODO: triggering highland build can be done there without "failing"
 			return "", errors.New("Invalid Registry endpoint: " + err.Error())
 			return "", errors.New("Invalid Registry endpoint: " + err.Error())
 		}
 		}
@@ -682,12 +694,18 @@ func NewRegistry(authConfig *auth.AuthConfig, factory *utils.HTTPRequestFactory,
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	// If we're working with a private registry over HTTPS, send Basic Auth headers
+	// If we're working with a standalone private registry over HTTPS, send Basic Auth headers
 	// alongside our requests.
 	// alongside our requests.
 	if indexEndpoint != auth.IndexServerAddress() && strings.HasPrefix(indexEndpoint, "https://") {
 	if indexEndpoint != auth.IndexServerAddress() && strings.HasPrefix(indexEndpoint, "https://") {
-		utils.Debugf("Endpoint %s is eligible for private registry auth. Enabling decorator.", indexEndpoint)
-		dec := utils.NewHTTPAuthDecorator(authConfig.Username, authConfig.Password)
-		factory.AddDecorator(dec)
+		standalone, err := pingRegistryEndpoint(indexEndpoint)
+		if err != nil {
+			return nil, err
+		}
+		if standalone {
+			utils.Debugf("Endpoint %s is eligible for private registry auth. Enabling decorator.", indexEndpoint)
+			dec := utils.NewHTTPAuthDecorator(authConfig.Username, authConfig.Password)
+			factory.AddDecorator(dec)
+		}
 	}
 	}
 
 
 	r.reqFactory = factory
 	r.reqFactory = factory

+ 2 - 1
registry/registry_test.go

@@ -23,10 +23,11 @@ func spawnTestRegistry(t *testing.T) *Registry {
 }
 }
 
 
 func TestPingRegistryEndpoint(t *testing.T) {
 func TestPingRegistryEndpoint(t *testing.T) {
-	err := pingRegistryEndpoint(makeURL("/v1/"))
+	standalone, err := pingRegistryEndpoint(makeURL("/v1/"))
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
+	assertEqual(t, standalone, true, "Expected standalone to be true (default)")
 }
 }
 
 
 func TestGetRemoteHistory(t *testing.T) {
 func TestGetRemoteHistory(t *testing.T) {