예제 #1
0
파일: registry.go 프로젝트: JioCloud/docker
func (r *Registry) GetRepositoryData(remote string) (*RepositoryData, error) {
	utils.Debugf("Pulling repository %s from %s\r\n", remote, auth.IndexServerAddress())
	repositoryTarget := auth.IndexServerAddress() + "/repositories/" + remote + "/images"

	req, err := http.NewRequest("GET", repositoryTarget, 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 == 401 {
		return nil, fmt.Errorf("Please login first (HTTP code %d)", res.StatusCode)
	}
	// TODO: Right now we're ignoring checksums in the response body.
	// In the future, we need to use them to check image validity.
	if res.StatusCode != 200 {
		return nil, fmt.Errorf("HTTP code: %d", res.StatusCode)
	}

	var tokens []string
	if res.Header.Get("X-Docker-Token") != "" {
		tokens = res.Header["X-Docker-Token"]
	}

	var endpoints []string
	if res.Header.Get("X-Docker-Endpoints") != "" {
		endpoints = res.Header["X-Docker-Endpoints"]
	} else {
		return nil, fmt.Errorf("Index response didn't contain any endpoints")
	}

	checksumsJson, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}
	remoteChecksums := []*ImgData{}
	if err := json.Unmarshal(checksumsJson, &remoteChecksums); err != nil {
		return nil, err
	}

	// Forge a better object from the retrieved data
	imgsData := make(map[string]*ImgData)
	for _, elem := range remoteChecksums {
		imgsData[elem.Id] = elem
	}

	return &RepositoryData{
		ImgList:   imgsData,
		Endpoints: endpoints,
		Tokens:    tokens,
	}, nil
}
예제 #2
0
파일: commands.go 프로젝트: nvdnkpr/docker
func (cli *DockerCli) checkIfLogged(action string) error {
	// If condition AND the login failed
	if cli.configFile.Configs[auth.IndexServerAddress()].Username == "" {
		if err := cli.CmdLogin(""); err != nil {
			return err
		}
		if cli.configFile.Configs[auth.IndexServerAddress()].Username == "" {
			return fmt.Errorf("Please login prior to %s. ('docker login')", action)
		}
	}
	return nil
}
예제 #3
0
파일: commands.go 프로젝트: jianingy/docker
func (cli *DockerCli) CmdPush(args ...string) error {
	cmd := Subcmd("push", "NAME", "Push an image or a repository to the registry")
	if err := cmd.Parse(args); err != nil {
		return nil
	}
	name := cmd.Arg(0)

	if name == "" {
		cmd.Usage()
		return nil
	}

	cli.LoadConfigFile()

	// If we're not using a custom registry, we know the restrictions
	// applied to repository names and can warn the user in advance.
	// Custom repositories can have different rules, and we must also
	// allow pushing by image ID.
	if len(strings.SplitN(name, "/", 2)) == 1 {
		username := cli.configFile.Configs[auth.IndexServerAddress()].Username
		if username == "" {
			username = "******"
		}
		return fmt.Errorf("Impossible to push a \"root\" repository. Please rename your repository in <user>/<repo> (ex: %s/%s)", username, name)
	}

	v := url.Values{}
	push := func() error {
		buf, err := json.Marshal(cli.configFile.Configs[auth.IndexServerAddress()])
		if err != nil {
			return err
		}

		return cli.stream("POST", "/images/"+name+"/push?"+v.Encode(), bytes.NewBuffer(buf), cli.out)
	}

	if err := push(); err != nil {
		if err.Error() == "Authentication is required." {
			fmt.Fprintln(cli.out, "\nPlease login prior to push:")
			if err := cli.CmdLogin(""); err != nil {
				return err
			}
			return push()
		}
		return err
	}
	return nil
}
예제 #4
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
}
예제 #5
0
파일: registry.go 프로젝트: sjbalaji/docker
func UrlScheme() string {
	u, err := url.Parse(auth.IndexServerAddress())
	if err != nil {
		return "https"
	}
	return u.Scheme
}
예제 #6
0
파일: server.go 프로젝트: silpion/docker
func (srv *Server) DockerInfo() *APIInfo {
	images, _ := srv.runtime.graph.Map()
	var imgcount int
	if images == nil {
		imgcount = 0
	} else {
		imgcount = len(images)
	}
	lxcVersion := ""
	if output, err := exec.Command("lxc-version").CombinedOutput(); err == nil {
		outputStr := string(output)
		if len(strings.SplitN(outputStr, ":", 2)) == 2 {
			lxcVersion = strings.TrimSpace(strings.SplitN(string(output), ":", 2)[1])
		}
	}
	kernelVersion := "<unknown>"
	if kv, err := utils.GetKernelVersion(); err == nil {
		kernelVersion = kv.String()
	}

	return &APIInfo{
		Containers:         len(srv.runtime.List()),
		Images:             imgcount,
		MemoryLimit:        srv.runtime.capabilities.MemoryLimit,
		SwapLimit:          srv.runtime.capabilities.SwapLimit,
		IPv4Forwarding:     !srv.runtime.capabilities.IPv4ForwardingDisabled,
		Debug:              os.Getenv("DEBUG") != "",
		NFd:                utils.GetTotalUsedFds(),
		NGoroutines:        runtime.NumGoroutine(),
		LXCVersion:         lxcVersion,
		NEventsListener:    len(srv.events),
		KernelVersion:      kernelVersion,
		IndexServerAddress: auth.IndexServerAddress(),
	}
}
예제 #7
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
}
예제 #8
0
func (cli *DockerCli) CmdPush(args ...string) error {
	cmd := Subcmd("push", "NAME", "Push an image or a repository to the registry")
	if err := cmd.Parse(args); err != nil {
		return nil
	}
	name := cmd.Arg(0)

	if name == "" {
		cmd.Usage()
		return nil
	}

	if err := cli.checkIfLogged("push"); err != nil {
		return err
	}

	// If we're not using a custom registry, we know the restrictions
	// applied to repository names and can warn the user in advance.
	// Custom repositories can have different rules, and we must also
	// allow pushing by image ID.
	if len(strings.SplitN(name, "/", 2)) == 1 {
		return fmt.Errorf("Impossible to push a \"root\" repository. Please rename your repository in <user>/<repo> (ex: %s/%s)", cli.configFile.Configs[auth.IndexServerAddress()].Username, name)
	}

	buf, err := json.Marshal(cli.configFile.Configs[auth.IndexServerAddress()])
	if err != nil {
		return err
	}

	v := url.Values{}
	if err := cli.stream("POST", "/images/"+name+"/push?"+v.Encode(), bytes.NewBuffer(buf), cli.out); err != nil {
		return err
	}
	return nil
}
예제 #9
0
func pingRegistryEndpoint(endpoint string) 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 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 err
	}
	defer resp.Body.Close()

	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 nil
}
예제 #10
0
파일: registry.go 프로젝트: rmoorman/docker
func (r *Registry) getImagesInRepository(repository string, authConfig *auth.AuthConfig) ([]map[string]string, error) {
	u := auth.IndexServerAddress() + "/repositories/" + repository + "/images"
	req, err := http.NewRequest("GET", u, nil)
	if err != nil {
		return nil, err
	}
	if authConfig != nil && len(authConfig.Username) > 0 {
		req.SetBasicAuth(authConfig.Username, authConfig.Password)
	}
	res, err := r.client.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	// Repository doesn't exist yet
	if res.StatusCode == 404 {
		return nil, nil
	}

	jsonData, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}

	imageList := []map[string]string{}
	if err := json.Unmarshal(jsonData, &imageList); err != nil {
		utils.Debugf("Body: %s (%s)\n", res.Body, u)
		return nil, err
	}

	return imageList, nil
}
예제 #11
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 private registry over HTTPS, send Basic Auth headers
	// alongside our requests.
	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)
	}

	r.reqFactory = factory
	return r, nil
}
예제 #12
0
파일: server.go 프로젝트: silpion/docker
func (srv *Server) ImagePull(localName string, tag string, out io.Writer, sf *utils.StreamFormatter, authConfig *auth.AuthConfig, metaHeaders map[string][]string, parallel bool) error {
	r, err := registry.NewRegistry(srv.runtime.root, authConfig, srv.HTTPRequestFactory(metaHeaders))
	if err != nil {
		return err
	}
	if err := srv.poolAdd("pull", localName+":"+tag); err != nil {
		return err
	}
	defer srv.poolRemove("pull", localName+":"+tag)

	// Resolve the Repository name from fqn to endpoint + name
	endpoint, remoteName, err := registry.ResolveRepositoryName(localName)
	if err != nil {
		return err
	}

	if endpoint == auth.IndexServerAddress() {
		// If pull "index.docker.io/foo/bar", it's stored locally under "foo/bar"
		localName = remoteName
	}

	out = utils.NewWriteFlusher(out)
	err = srv.pullRepository(r, out, localName, remoteName, tag, endpoint, sf, parallel)
	if err == registry.ErrLoginRequired {
		return err
	}
	if err != nil {
		if err := srv.pullImage(r, out, remoteName, endpoint, nil, sf); err != nil {
			return err
		}
		return nil
	}

	return nil
}
예제 #13
0
func pingRegistryEndpoint(endpoint string) 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 nil
	}
	resp, err := http.Get(endpoint + "_ping")
	if err != nil {
		return err
	}
	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 nil
}
예제 #14
0
func TestResolveRepositoryName(t *testing.T) {
	_, _, err := ResolveRepositoryName("https://github.com/dotcloud/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")
}
예제 #15
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
}
예제 #16
0
func (r *Registry) SearchRepositories(term string) (*SearchResults, error) {
	u := auth.IndexServerAddress() + "search?q=" + url.QueryEscape(term)
	req, err := r.reqFactory.NewRequest("GET", u, nil)
	if err != nil {
		return nil, err
	}
	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
}
예제 #17
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 := fmt.Sprintf("https://%s/v1/", hostname)
	if err := pingRegistryEndpoint(endpoint); err != nil {
		utils.Debugf("Registry %s does not work (%s), falling back to http", endpoint, err)
		endpoint = fmt.Sprintf("http://%s/v1/", hostname)
		if err = pingRegistryEndpoint(endpoint); err != nil {
			//TODO: triggering highland build can be done there without "failing"
			return "", "", errors.New("Invalid Registry endpoint: " + err.Error())
		}
	}
	err := validateRepositoryName(reposName)
	return endpoint, reposName, err
}
예제 #18
0
파일: registry.go 프로젝트: rmoorman/docker
func (r *Registry) PushImageJsonIndex(remote string, imgList []*ImgData, validate bool) (*RepositoryData, error) {
	imgListJson, err := json.Marshal(imgList)
	if err != nil {
		return nil, err
	}
	var suffix string
	if validate {
		suffix = "images"
	}
	req, err := http.NewRequest("PUT", auth.IndexServerAddress()+"/repositories/"+remote+"/"+suffix, bytes.NewReader(imgListJson))
	if err != nil {
		return nil, err
	}
	req.SetBasicAuth(r.authConfig.Username, r.authConfig.Password)
	req.ContentLength = int64(len(imgListJson))
	req.Header.Set("X-Docker-Token", "true")

	res, err := r.client.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	// Redirect if necessary
	for res.StatusCode >= 300 && res.StatusCode < 400 {
		utils.Debugf("Redirected to %s\n", res.Header.Get("Location"))
		req, err = http.NewRequest("PUT", res.Header.Get("Location"), bytes.NewReader(imgListJson))
		if err != nil {
			return nil, err
		}
		req.SetBasicAuth(r.authConfig.Username, r.authConfig.Password)
		req.ContentLength = int64(len(imgListJson))
		req.Header.Set("X-Docker-Token", "true")

		res, err = r.client.Do(req)
		if err != nil {
			return nil, err
		}
		defer res.Body.Close()
	}

	var tokens, endpoints []string
	if !validate {
		if res.StatusCode != 200 && res.StatusCode != 201 {
			errBody, err := ioutil.ReadAll(res.Body)
			if err != nil {
				return nil, err
			}
			return nil, fmt.Errorf("Error: Status %d trying to push repository %s: %s", res.StatusCode, remote, errBody)
		}
		if res.Header.Get("X-Docker-Token") != "" {
			tokens = res.Header["X-Docker-Token"]
			utils.Debugf("Auth token: %v", tokens)
		} else {
			return nil, fmt.Errorf("Index response didn't contain an access token")
		}

		if res.Header.Get("X-Docker-Endpoints") != "" {
			endpoints = res.Header["X-Docker-Endpoints"]
		} else {
			return nil, fmt.Errorf("Index response didn't contain any endpoints")
		}
	}
	if validate {
		if res.StatusCode != 204 {
			if errBody, err := ioutil.ReadAll(res.Body); err != nil {
				return nil, err
			} else {
				return nil, fmt.Errorf("Error: Status %d trying to push checksums %s: %s", res.StatusCode, remote, errBody)
			}
		}
	}

	return &RepositoryData{
		Tokens:    tokens,
		Endpoints: endpoints,
	}, nil
}
예제 #19
0
파일: server.go 프로젝트: brunoqc/docker
func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, remote, askedTag string, sf *utils.StreamFormatter) error {
	out.Write(sf.FormatStatus("Pulling repository %s from %s", remote, auth.IndexServerAddress()))
	repoData, err := r.GetRepositoryData(remote)
	if err != nil {
		return err
	}

	utils.Debugf("Updating checksums")
	// Reload the json file to make sure not to overwrite faster sums
	if err := srv.runtime.graph.UpdateChecksums(repoData.ImgList); err != nil {
		return err
	}

	utils.Debugf("Retrieving the tag list")
	tagsList, err := r.GetRemoteTags(repoData.Endpoints, remote, repoData.Tokens)
	if err != nil {
		return err
	}
	utils.Debugf("Registering tags")
	// If not specific tag have been asked, take all
	if askedTag == "" {
		for tag, id := range tagsList {
			repoData.ImgList[id].Tag = tag
		}
	} else {
		// Otherwise, check that the tag exists and use only that one
		id, exists := tagsList[askedTag]
		if !exists {
			return fmt.Errorf("Tag %s not found in repositoy %s", askedTag, remote)
		}
		repoData.ImgList[id].Tag = askedTag
	}

	for _, img := range repoData.ImgList {
		if askedTag != "" && img.Tag != askedTag {
			utils.Debugf("(%s) does not match %s (id: %s), skipping", img.Tag, askedTag, img.ID)
			continue
		}
		out.Write(sf.FormatStatus("Pulling image %s (%s) from %s", img.ID, img.Tag, remote))
		success := false
		for _, ep := range repoData.Endpoints {
			if err := srv.pullImage(r, out, img.ID, "https://"+ep+"/v1", repoData.Tokens, sf); err != nil {
				out.Write(sf.FormatStatus("Error while retrieving image for tag: %s (%s); checking next endpoint", askedTag, err))
				continue
			}
			success = true
			break
		}
		if !success {
			return fmt.Errorf("Could not find repository on any of the indexed registries.")
		}
	}
	for tag, id := range tagsList {
		if askedTag != "" && tag != askedTag {
			continue
		}
		if err := srv.runtime.repositories.Set(remote, tag, id, true); err != nil {
			return err
		}
	}
	if err := srv.runtime.repositories.Save(); err != nil {
		return err
	}

	return nil
}
예제 #20
0
파일: commands.go 프로젝트: eliasp/docker
func (cli *DockerCli) CmdPush(args ...string) error {
	cmd := Subcmd("push", "NAME", "Push an image or a repository to the registry")
	if err := cmd.Parse(args); err != nil {
		return nil
	}
	name := cmd.Arg(0)

	if name == "" {
		cmd.Usage()
		return nil
	}

	cli.LoadConfigFile()

	// Resolve the Repository name from fqn to endpoint + name
	endpoint, _, err := registry.ResolveRepositoryName(name)
	if err != nil {
		return err
	}
	// Resolve the Auth config relevant for this server
	authConfig := cli.configFile.ResolveAuthConfig(endpoint)
	// If we're not using a custom registry, we know the restrictions
	// applied to repository names and can warn the user in advance.
	// Custom repositories can have different rules, and we must also
	// allow pushing by image ID.
	if len(strings.SplitN(name, "/", 2)) == 1 {
		username := cli.configFile.Configs[auth.IndexServerAddress()].Username
		if username == "" {
			username = "******"
		}
		return fmt.Errorf("Impossible to push a \"root\" repository. Please rename your repository in <user>/<repo> (ex: %s/%s)", username, name)
	}

	v := url.Values{}
	push := func(authConfig auth.AuthConfig) error {
		buf, err := json.Marshal(authConfig)
		if err != nil {
			return err
		}
		registryAuthHeader := []string{
			base64.URLEncoding.EncodeToString(buf),
		}

		return cli.stream("POST", "/images/"+name+"/push?"+v.Encode(), nil, cli.out, map[string][]string{
			"X-Registry-Auth": registryAuthHeader,
		})
	}

	if err := push(authConfig); err != nil {
		if err.Error() == registry.ErrLoginRequired.Error() {
			fmt.Fprintln(cli.out, "\nPlease login prior to push:")
			if err := cli.CmdLogin(endpoint); err != nil {
				return err
			}
			authConfig := cli.configFile.ResolveAuthConfig(endpoint)
			return push(authConfig)
		}
		return err
	}
	return nil
}
예제 #21
0
파일: commands.go 프로젝트: eliasp/docker
// 'docker login': login / register a user to registry service.
func (cli *DockerCli) CmdLogin(args ...string) error {
	cmd := Subcmd("login", "[OPTIONS] [SERVER]", "Register or Login to a docker registry server, if no server is specified \""+auth.IndexServerAddress()+"\" is the default.")

	var username, password, email string

	cmd.StringVar(&username, "u", "", "username")
	cmd.StringVar(&password, "p", "", "password")
	cmd.StringVar(&email, "e", "", "email")
	err := cmd.Parse(args)
	if err != nil {
		return nil
	}
	serverAddress := auth.IndexServerAddress()
	if len(cmd.Args()) > 0 {
		serverAddress, err = registry.ExpandAndVerifyRegistryUrl(cmd.Arg(0))
		if err != nil {
			return err
		}
		fmt.Fprintf(cli.out, "Login against server at %s\n", serverAddress)
	}

	promptDefault := func(prompt string, configDefault string) {
		if configDefault == "" {
			fmt.Fprintf(cli.out, "%s: ", prompt)
		} else {
			fmt.Fprintf(cli.out, "%s (%s): ", prompt, configDefault)
		}
	}

	readInput := func(in io.Reader, out io.Writer) string {
		reader := bufio.NewReader(in)
		line, _, err := reader.ReadLine()
		if err != nil {
			fmt.Fprintln(out, err.Error())
			os.Exit(1)
		}
		return string(line)
	}

	cli.LoadConfigFile()
	authconfig, ok := cli.configFile.Configs[auth.IndexServerAddress()]
	if !ok {
		authconfig = auth.AuthConfig{}
	}

	if username == "" {
		promptDefault("Username", authconfig.Username)
		username = readInput(cli.in, cli.out)
		if username == "" {
			username = authconfig.Username
		}
	}
	if username != authconfig.Username {
		if password == "" {
			oldState, _ := term.SaveState(cli.terminalFd)
			fmt.Fprintf(cli.out, "Password: "******"\n")

			term.RestoreTerminal(cli.terminalFd, oldState)
			if password == "" {
				return fmt.Errorf("Error : Password Required")
			}
		}

		if email == "" {
			promptDefault("Email", authconfig.Email)
			email = readInput(cli.in, cli.out)
			if email == "" {
				email = authconfig.Email
			}
		}
	} else {
		password = authconfig.Password
		email = authconfig.Email
	}
	authconfig.Username = username
	authconfig.Password = password
	authconfig.Email = email
	authconfig.ServerAddress = serverAddress
	cli.configFile.Configs[serverAddress] = authconfig

	body, statusCode, err := cli.call("POST", "/auth", cli.configFile.Configs[serverAddress])
	if statusCode == 401 {
		delete(cli.configFile.Configs, serverAddress)
		auth.SaveConfig(cli.configFile)
		return err
	}
	if err != nil {
		return err
	}

	var out2 APIAuth
	err = json.Unmarshal(body, &out2)
	if err != nil {
		cli.configFile, _ = auth.LoadConfig(os.Getenv("HOME"))
		return err
	}
	auth.SaveConfig(cli.configFile)
	if out2.Status != "" {
		fmt.Fprintf(cli.out, "%s\n", out2.Status)
	}
	return nil
}
예제 #22
0
파일: server.go 프로젝트: sjbalaji/docker
func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, local, remote, askedTag, registryEp string, sf *utils.StreamFormatter) error {
	out.Write(sf.FormatStatus("Pulling repository %s from %s", local, auth.IndexServerAddress()))

	var repoData *registry.RepositoryData
	var err error
	if registryEp == "" {
		repoData, err = r.GetRepositoryData(remote)
		if err != nil {
			return err
		}

		utils.Debugf("Updating checksums")
		// Reload the json file to make sure not to overwrite faster sums
		if err := srv.runtime.graph.UpdateChecksums(repoData.ImgList); err != nil {
			return err
		}
	} else {
		repoData = &registry.RepositoryData{
			Tokens:    []string{},
			ImgList:   make(map[string]*registry.ImgData),
			Endpoints: []string{registryEp},
		}
	}

	utils.Debugf("Retrieving the tag list")
	tagsList, err := r.GetRemoteTags(repoData.Endpoints, remote, repoData.Tokens)
	if err != nil {
		utils.Debugf("%v", err)
		return err
	}

	if registryEp != "" {
		for tag, id := range tagsList {
			repoData.ImgList[id] = &registry.ImgData{
				ID:       id,
				Tag:      tag,
				Checksum: "",
			}
		}
	}

	utils.Debugf("Registering tags")
	// If no tag has been specified, pull them all
	if askedTag == "" {
		for tag, id := range tagsList {
			repoData.ImgList[id].Tag = tag
		}
	} else {
		// Otherwise, check that the tag exists and use only that one
		id, exists := tagsList[askedTag]
		if !exists {
			return fmt.Errorf("Tag %s not found in repositoy %s", askedTag, local)
		}
		repoData.ImgList[id].Tag = askedTag
	}

	for _, img := range repoData.ImgList {
		if askedTag != "" && img.Tag != askedTag {
			utils.Debugf("(%s) does not match %s (id: %s), skipping", img.Tag, askedTag, img.ID)
			continue
		}
		out.Write(sf.FormatStatus("Pulling image %s (%s) from %s", img.ID, img.Tag, remote))
		success := false
		for _, ep := range repoData.Endpoints {
			if !(strings.HasPrefix(ep, "http://") || strings.HasPrefix(ep, "https://")) {
				ep = fmt.Sprintf("%s://%s", registry.UrlScheme(), ep)
			}
			if err := srv.pullImage(r, out, img.ID, ep+"/v1", repoData.Tokens, sf); err != nil {
				out.Write(sf.FormatStatus("Error while retrieving image for tag: %s (%s); checking next endpoint", askedTag, err))
				continue
			}
			success = true
			break
		}
		if !success {
			return fmt.Errorf("Could not find repository on any of the indexed registries.")
		}
	}
	for tag, id := range tagsList {
		if askedTag != "" && tag != askedTag {
			continue
		}
		if err := srv.runtime.repositories.Set(local, tag, id, true); err != nil {
			return err
		}
	}
	if err := srv.runtime.repositories.Save(); err != nil {
		return err
	}

	return nil
}
예제 #23
0
파일: commands.go 프로젝트: nvdnkpr/docker
// 'docker login': login / register a user to registry service.
func (cli *DockerCli) CmdLogin(args ...string) error {
	var readStringOnRawTerminal = func(stdin io.Reader, stdout io.Writer, echo bool) string {
		char := make([]byte, 1)
		buffer := make([]byte, 64)
		var i = 0
		for i < len(buffer) {
			n, err := stdin.Read(char)
			if n > 0 {
				if char[0] == '\r' || char[0] == '\n' {
					stdout.Write([]byte{'\r', '\n'})
					break
				} else if char[0] == 127 || char[0] == '\b' {
					if i > 0 {
						if echo {
							stdout.Write([]byte{'\b', ' ', '\b'})
						}
						i--
					}
				} else if !unicode.IsSpace(rune(char[0])) &&
					!unicode.IsControl(rune(char[0])) {
					if echo {
						stdout.Write(char)
					}
					buffer[i] = char[0]
					i++
				}
			}
			if err != nil {
				if err != io.EOF {
					fmt.Fprintf(stdout, "Read error: %v\r\n", err)
				}
				break
			}
		}
		return string(buffer[:i])
	}
	var readAndEchoString = func(stdin io.Reader, stdout io.Writer) string {
		return readStringOnRawTerminal(stdin, stdout, true)
	}
	var readString = func(stdin io.Reader, stdout io.Writer) string {
		return readStringOnRawTerminal(stdin, stdout, false)
	}

	cmd := Subcmd("login", "[OPTIONS]", "Register or Login to the docker registry server")
	flUsername := cmd.String("u", "", "username")
	flPassword := cmd.String("p", "", "password")
	flEmail := cmd.String("e", "", "email")
	err := cmd.Parse(args)
	if err != nil {
		return nil
	}

	var oldState *term.State
	if *flUsername == "" || *flPassword == "" || *flEmail == "" {
		oldState, err = term.SetRawTerminal(cli.terminalFd)
		if err != nil {
			return err
		}
		defer term.RestoreTerminal(cli.terminalFd, oldState)
	}

	var (
		username string
		password string
		email    string
	)

	var promptDefault = func(prompt string, configDefault string) {
		if configDefault == "" {
			fmt.Fprintf(cli.out, "%s: ", prompt)
		} else {
			fmt.Fprintf(cli.out, "%s (%s): ", prompt, configDefault)
		}
	}

	authconfig, ok := cli.configFile.Configs[auth.IndexServerAddress()]
	if !ok {
		authconfig = auth.AuthConfig{}
	}

	if *flUsername == "" {
		promptDefault("Username", authconfig.Username)
		username = readAndEchoString(cli.in, cli.out)
		if username == "" {
			username = authconfig.Username
		}
	} else {
		username = *flUsername
	}
	if username != authconfig.Username {
		if *flPassword == "" {
			fmt.Fprintf(cli.out, "Password: "******"" {
				return fmt.Errorf("Error : Password Required")
			}
		} else {
			password = *flPassword
		}

		if *flEmail == "" {
			promptDefault("Email", authconfig.Email)
			email = readAndEchoString(cli.in, cli.out)
			if email == "" {
				email = authconfig.Email
			}
		} else {
			email = *flEmail
		}
	} else {
		password = authconfig.Password
		email = authconfig.Email
	}
	if oldState != nil {
		term.RestoreTerminal(cli.terminalFd, oldState)
	}
	authconfig.Username = username
	authconfig.Password = password
	authconfig.Email = email
	cli.configFile.Configs[auth.IndexServerAddress()] = authconfig

	body, statusCode, err := cli.call("POST", "/auth", cli.configFile.Configs[auth.IndexServerAddress()])
	if statusCode == 401 {
		delete(cli.configFile.Configs, auth.IndexServerAddress())
		auth.SaveConfig(cli.configFile)
		return err
	}
	if err != nil {
		return err
	}

	var out2 APIAuth
	err = json.Unmarshal(body, &out2)
	if err != nil {
		cli.configFile, _ = auth.LoadConfig(os.Getenv("HOME"))
		return err
	}
	auth.SaveConfig(cli.configFile)
	if out2.Status != "" {
		fmt.Fprintf(cli.out, "%s\n", out2.Status)
	}
	return nil
}