Check standalone header when pinging a registry server. Standalone has to be true to use basic auth (in addition to previous requirements)

This commit is contained in:
shin- 2014-01-02 17:51:42 +01:00
parent cea40c552b
commit 79e0ed25db

View File

@ -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())
} }
@ -677,13 +689,19 @@ 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://") {
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) utils.Debugf("Endpoint %s is eligible for private registry auth. Enabling decorator.", indexEndpoint)
dec := utils.NewHTTPAuthDecorator(authConfig.Username, authConfig.Password) dec := utils.NewHTTPAuthDecorator(authConfig.Username, authConfig.Password)
factory.AddDecorator(dec) factory.AddDecorator(dec)
} }
}
r.reqFactory = factory r.reqFactory = factory
return r, nil return r, nil