Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
registry: getting Endpoint ironned out
Signed-off-by: Vincent Batts <vbatts@redhat.com>
- Loading branch information
Showing
8 changed files
with
181 additions
and
107 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
package registry | ||
|
||
import ( | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
"io/ioutil" | ||
"net/http" | ||
"net/url" | ||
"strings" | ||
|
||
"github.com/docker/docker/pkg/log" | ||
) | ||
|
||
// scans string for api version in the URL path. returns the trimmed hostname, if version found, string and API version. | ||
func scanForApiVersion(hostname string) (string, APIVersion) { | ||
var ( | ||
chunks []string | ||
apiVersionStr string | ||
) | ||
if strings.HasSuffix(hostname, "/") { | ||
chunks = strings.Split(hostname[:len(hostname)-1], "/") | ||
apiVersionStr = chunks[len(chunks)-1] | ||
} else { | ||
chunks = strings.Split(hostname, "/") | ||
apiVersionStr = chunks[len(chunks)-1] | ||
} | ||
for k, v := range apiVersions { | ||
if apiVersionStr == v { | ||
hostname = strings.Join(chunks[:len(chunks)-1], "/") | ||
return hostname, k | ||
} | ||
} | ||
return hostname, DefaultAPIVersion | ||
} | ||
|
||
func NewEndpoint(hostname string) (*Endpoint, error) { | ||
var ( | ||
endpoint Endpoint | ||
trimmedHostname string | ||
err error | ||
) | ||
if !strings.HasPrefix(hostname, "http") { | ||
hostname = "https://" + hostname | ||
} | ||
trimmedHostname, endpoint.Version = scanForApiVersion(hostname) | ||
endpoint.URL, err = url.Parse(trimmedHostname) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
endpoint.URL.Scheme = "https" | ||
if _, err := endpoint.Ping(); err != nil { | ||
log.Debugf("Registry %s does not work (%s), falling back to http", endpoint, err) | ||
// TODO: Check if http fallback is enabled | ||
endpoint.URL.Scheme = "http" | ||
if _, err = endpoint.Ping(); err != nil { | ||
return nil, errors.New("Invalid Registry endpoint: " + err.Error()) | ||
} | ||
} | ||
|
||
return &endpoint, nil | ||
} | ||
|
||
type Endpoint struct { | ||
URL *url.URL | ||
Version APIVersion | ||
} | ||
|
||
// Get the formated URL for the root of this registry Endpoint | ||
func (e Endpoint) String() string { | ||
return fmt.Sprintf("%s/v%d/", e.URL.String(), e.Version) | ||
} | ||
|
||
func (e Endpoint) VersionString(version APIVersion) string { | ||
return fmt.Sprintf("%s/v%d/", e.URL.String(), version) | ||
} | ||
|
||
func (e Endpoint) Ping() (RegistryInfo, error) { | ||
if e.String() == IndexServerAddress() { | ||
// Skip the check, we now this one is valid | ||
// (and we never want to fallback to http in case of error) | ||
return RegistryInfo{Standalone: false}, nil | ||
} | ||
|
||
req, err := http.NewRequest("GET", e.String()+"_ping", nil) | ||
if err != nil { | ||
return RegistryInfo{Standalone: false}, err | ||
} | ||
|
||
resp, _, err := doRequest(req, nil, ConnectTimeout) | ||
if err != nil { | ||
return RegistryInfo{Standalone: false}, err | ||
} | ||
|
||
defer resp.Body.Close() | ||
|
||
jsonString, err := ioutil.ReadAll(resp.Body) | ||
if err != nil { | ||
return RegistryInfo{Standalone: false}, fmt.Errorf("Error while reading the http response: %s", err) | ||
} | ||
|
||
// If the header is absent, we assume true for compatibility with earlier | ||
// versions of the registry. default to true | ||
info := RegistryInfo{ | ||
Standalone: true, | ||
} | ||
if err := json.Unmarshal(jsonString, &info); err != nil { | ||
log.Debugf("Error unmarshalling the _ping RegistryInfo: %s", err) | ||
// don't stop here. Just assume sane defaults | ||
} | ||
if hdr := resp.Header.Get("X-Docker-Registry-Version"); hdr != "" { | ||
log.Debugf("Registry version header: '%s'", hdr) | ||
info.Version = hdr | ||
} | ||
log.Debugf("RegistryInfo.Version: %q", info.Version) | ||
|
||
standalone := resp.Header.Get("X-Docker-Registry-Standalone") | ||
log.Debugf("Registry standalone header: '%s'", standalone) | ||
// Accepted values are "true" (case-insensitive) and "1". | ||
if strings.EqualFold(standalone, "true") || standalone == "1" { | ||
info.Standalone = true | ||
} else if len(standalone) > 0 { | ||
// there is a header set, and it is not "true" or "1", so assume fails | ||
info.Standalone = false | ||
} | ||
log.Debugf("RegistryInfo.Standalone: %q", info.Standalone) | ||
return info, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.