Example #1
0
// Resolves a repository name to a endpoint + name
func ResolveRepositoryName(reposName string) (string, string, error) {
	if strings.Contains(reposName, "://") {
		// It cannot contain a scheme!
		return "", "", ErrInvalidRepositoryName
	}
	nameParts := strings.SplitN(reposName, "/", 2)
	if !strings.Contains(nameParts[0], ".") && !strings.Contains(nameParts[0], ":") &&
		nameParts[0] != "localhost" {
		// This is a Docker Index repos (ex: samalba/hipache or ubuntu)
		err := validateRepositoryName(reposName)
		return auth.IndexServerAddress(), reposName, err
	}
	if len(nameParts) < 2 {
		// There is a dot in repos name (and no registry address)
		// Is it a Registry address without repos name?
		return "", "", ErrInvalidRepositoryName
	}
	hostname := nameParts[0]
	reposName = nameParts[1]
	if strings.Contains(hostname, "index.docker.io") {
		return "", "", fmt.Errorf("Invalid repository name, try \"%s\" instead", reposName)
	}
	if err := validateRepositoryName(reposName); err != nil {
		return "", "", err
	}
	endpoint, err := ExpandAndVerifyRegistryUrl(hostname)
	if err != nil {
		return "", "", err
	}
	return endpoint, reposName, err
}
Example #2
0
func NewRegistry(authConfig *auth.AuthConfig, factory *utils.HTTPRequestFactory, indexEndpoint string) (r *Registry, err error) {
	httpTransport := &http.Transport{
		DisableKeepAlives: true,
		Proxy:             http.ProxyFromEnvironment,
	}

	r = &Registry{
		authConfig: authConfig,
		client: &http.Client{
			Transport: httpTransport,
		},
		indexEndpoint: indexEndpoint,
	}
	r.client.Jar, err = cookiejar.New(nil)
	if err != nil {
		return nil, err
	}

	// If we're working with a standalone private registry over HTTPS, send Basic Auth headers
	// alongside our requests.
	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)
			dec := utils.NewHTTPAuthDecorator(authConfig.Username, authConfig.Password)
			factory.AddDecorator(dec)
		}
	}

	r.reqFactory = factory
	return r, nil
}
Example #3
0
func (r *Registry) SearchRepositories(term string) (*SearchResults, error) {
	utils.Debugf("Index server: %s", r.indexEndpoint)
	u := auth.IndexServerAddress() + "search?q=" + url.QueryEscape(term)
	req, err := r.reqFactory.NewRequest("GET", u, nil)
	if err != nil {
		return nil, err
	}
	if r.authConfig != nil && len(r.authConfig.Username) > 0 {
		req.SetBasicAuth(r.authConfig.Username, r.authConfig.Password)
	}
	req.Header.Set("X-Docker-Token", "true")
	res, err := r.client.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()
	if res.StatusCode != 200 {
		return nil, utils.NewHTTPRequestError(fmt.Sprintf("Unexepected status code %d", res.StatusCode), res)
	}
	rawData, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}
	result := new(SearchResults)
	err = json.Unmarshal(rawData, result)
	return result, err
}
Example #4
0
func TestResolveRepositoryName(t *testing.T) {
	_, _, err := ResolveRepositoryName("https://github.com/Nerdness/docker")
	assertEqual(t, err, ErrInvalidRepositoryName, "Expected error invalid repo name")
	ep, repo, err := ResolveRepositoryName("fooo/bar")
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, ep, auth.IndexServerAddress(), "Expected endpoint to be index server address")
	assertEqual(t, repo, "fooo/bar", "Expected resolved repo to be foo/bar")

	u := makeURL("")[7:]
	ep, repo, err = ResolveRepositoryName(u + "/private/moonbase")
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, ep, "http://"+u+"/v1/", "Expected endpoint to be "+u)
	assertEqual(t, repo, "private/moonbase", "Expected endpoint to be private/moonbase")
}
Example #5
0
func pingRegistryEndpoint(endpoint string) (bool, error) {
	if endpoint == auth.IndexServerAddress() {
		// Skip the check, we now this one is valid
		// (and we never want to fallback to http in case of error)
		return false, nil
	}
	httpDial := func(proto string, addr string) (net.Conn, error) {
		// Set the connect timeout to 5 seconds
		conn, err := net.DialTimeout(proto, addr, time.Duration(5)*time.Second)
		if err != nil {
			return nil, err
		}
		// Set the recv timeout to 10 seconds
		conn.SetDeadline(time.Now().Add(time.Duration(10) * time.Second))
		return conn, nil
	}
	httpTransport := &http.Transport{Dial: httpDial}
	client := &http.Client{Transport: httpTransport}
	resp, err := client.Get(endpoint + "_ping")
	if err != nil {
		return false, err
	}
	defer resp.Body.Close()

	if resp.Header.Get("X-Docker-Registry-Version") == "" {
		return false, errors.New("This does not look like a Registry server (\"X-Docker-Registry-Version\" header not found in the response)")
	}

	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
}