Exemple #1
0
// Creates an image from Pull or from Import
func postImagesCreate(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
	if err := parseForm(r); err != nil {
		return err
	}

	var (
		image = r.Form.Get("fromImage")
		repo  = r.Form.Get("repo")
		tag   = r.Form.Get("tag")
		job   *engine.Job
	)
	authEncoded := r.Header.Get("X-Registry-Auth")
	authConfig := &registry.AuthConfig{}
	if authEncoded != "" {
		authJson := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
		if err := json.NewDecoder(authJson).Decode(authConfig); err != nil {
			// for a pull it is not an error if no auth was given
			// to increase compatibility with the existing api it is defaulting to be empty
			authConfig = &registry.AuthConfig{}
		}
	}
	if image != "" { //pull
		if tag == "" {
			image, tag = utils.ParseRepositoryTag(image)
		}
		metaHeaders := map[string][]string{}
		for k, v := range r.Header {
			if strings.HasPrefix(k, "X-Meta-") {
				metaHeaders[k] = v
			}
		}
		job = eng.Job("pull", image, tag)
		job.SetenvBool("parallel", version.GreaterThan("1.3"))
		job.SetenvJson("metaHeaders", metaHeaders)
		job.SetenvJson("authConfig", authConfig)
	} else { //import
		if tag == "" {
			repo, tag = utils.ParseRepositoryTag(repo)
		}
		job = eng.Job("import", r.Form.Get("fromSrc"), repo, tag)
		job.Stdin.Add(r.Body)
	}

	if version.GreaterThan("1.0") {
		job.SetenvBool("json", true)
		streamJSON(job, w, true)
	} else {
		job.Stdout.Add(utils.NewWriteFlusher(w))
	}
	if err := job.Run(); err != nil {
		if !job.Stdout.Used() {
			return err
		}
		sf := utils.NewStreamFormatter(version.GreaterThan("1.0"))
		w.Write(sf.FormatError(err))
	}

	return nil
}
Exemple #2
0
func (b *buildFile) CmdFrom(name string) error {
	image, err := b.runtime.repositories.LookupImage(name)
	if err != nil {
		if b.runtime.graph.IsNotExist(err) {
			remote, tag := utils.ParseRepositoryTag(name)
			if err := b.srv.ImagePull(remote, tag, b.outOld, b.sf, b.authConfig, nil, true); err != nil {
				return err
			}
			image, err = b.runtime.repositories.LookupImage(name)
			if err != nil {
				return err
			}
		} else {
			return err
		}
	}
	b.image = image.ID
	b.config = &Config{}
	if image.Config != nil {
		b.config = image.Config
	}
	if b.config.Env == nil || len(b.config.Env) == 0 {
		b.config.Env = append(b.config.Env, "HOME=/", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin")
	}
	return nil
}
Exemple #3
0
func (c *ImageService) Pull(image string) error {
	name, tag := utils.ParseRepositoryTag(image)
	if len(tag) == 0 {
		tag = DEFAULTTAG
	}
	return c.PullTag(name, tag)
}
Exemple #4
0
func (cli *DockerCli) CmdPull(args ...string) error {
	cmd := Subcmd("pull", "NAME", "Pull an image or a repository from the registry")
	tag := cmd.String("t", "", "Download tagged image in repository")
	if err := cmd.Parse(args); err != nil {
		return nil
	}

	if cmd.NArg() != 1 {
		cmd.Usage()
		return nil
	}

	remote, parsedTag := utils.ParseRepositoryTag(cmd.Arg(0))
	if *tag == "" {
		*tag = parsedTag
	}

	v := url.Values{}
	v.Set("fromImage", remote)
	v.Set("tag", *tag)

	if err := cli.stream("POST", "/images/create?"+v.Encode(), nil, cli.out); err != nil {
		return err
	}

	return nil
}
Exemple #5
0
func (srv *Server) ContainerCreate(config *Config) (string, error) {

	if config.Memory != 0 && config.Memory < 524288 {
		return "", fmt.Errorf("Memory limit must be given in bytes (minimum 524288 bytes)")
	}

	if config.Memory > 0 && !srv.runtime.capabilities.MemoryLimit {
		config.Memory = 0
	}

	if config.Memory > 0 && !srv.runtime.capabilities.SwapLimit {
		config.MemorySwap = -1
	}
	container, err := srv.runtime.Create(config)
	if err != nil {
		if srv.runtime.graph.IsNotExist(err) {

			_, tag := utils.ParseRepositoryTag(config.Image)
			if tag == "" {
				tag = DEFAULTTAG
			}

			return "", fmt.Errorf("No such image: %s (tag: %s)", config.Image, tag)
		}
		return "", err
	}
	srv.LogEvent("create", container.ShortID(), srv.runtime.repositories.ImageName(container.Image))
	return container.ShortID(), nil
}
Exemple #6
0
func (b *buildFile) CmdFrom(name string) error {
	image, err := b.runtime.Repositories().LookupImage(name)
	if err != nil {
		if b.runtime.Graph().IsNotExist(err) {
			remote, tag := utils.ParseRepositoryTag(name)
			pullRegistryAuth := b.authConfig
			if len(b.configFile.Configs) > 0 {
				// The request came with a full auth config file, we prefer to use that
				endpoint, _, err := registry.ResolveRepositoryName(remote)
				if err != nil {
					return err
				}
				resolvedAuth := b.configFile.ResolveAuthConfig(endpoint)
				pullRegistryAuth = &resolvedAuth
			}
			job := b.srv.Eng.Job("pull", remote, tag)
			job.SetenvBool("json", b.sf.Json())
			job.SetenvBool("parallel", true)
			job.SetenvJson("authConfig", pullRegistryAuth)
			job.Stdout.Add(b.outOld)
			if err := job.Run(); err != nil {
				return err
			}
			image, err = b.runtime.Repositories().LookupImage(name)
			if err != nil {
				return err
			}
		} else {
			return err
		}
	}
	b.image = image.ID
	b.config = &runconfig.Config{}
	if image.Config != nil {
		b.config = image.Config
	}
	if b.config.Env == nil || len(b.config.Env) == 0 {
		b.config.Env = append(b.config.Env, "HOME=/", "PATH="+runtime.DefaultPathEnv)
	}
	// Process ONBUILD triggers if they exist
	if nTriggers := len(b.config.OnBuild); nTriggers != 0 {
		fmt.Fprintf(b.errStream, "# Executing %d build triggers\n", nTriggers)
	}
	for n, step := range b.config.OnBuild {
		splitStep := strings.Split(step, " ")
		stepInstruction := strings.ToUpper(strings.Trim(splitStep[0], " "))
		switch stepInstruction {
		case "ONBUILD":
			return fmt.Errorf("Source image contains forbidden chained `ONBUILD ONBUILD` trigger: %s", step)
		case "MAINTAINER", "FROM":
			return fmt.Errorf("Source image contains forbidden %s trigger: %s", stepInstruction, step)
		}
		if err := b.BuildStep(fmt.Sprintf("onbuild-%d", n), step); err != nil {
			return err
		}
	}
	b.config.OnBuild = []string{}
	return nil
}
Exemple #7
0
func (cli *DockerCli) CmdPull(args ...string) error {
	cmd := Subcmd("pull", "NAME", "Pull an image or a repository from the registry")
	tag := cmd.String("t", "", "Download tagged image in repository")
	if err := cmd.Parse(args); err != nil {
		return nil
	}

	if cmd.NArg() != 1 {
		cmd.Usage()
		return nil
	}

	remote, parsedTag := utils.ParseRepositoryTag(cmd.Arg(0))
	if *tag == "" {
		*tag = parsedTag
	}

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

	cli.LoadConfigFile()

	// Resolve the Auth config relevant for this server
	authConfig := cli.configFile.ResolveAuthConfig(endpoint)
	v := url.Values{}
	v.Set("fromImage", remote)
	v.Set("tag", *tag)

	pull := 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/create?"+v.Encode(), nil, cli.out, map[string][]string{
			"X-Registry-Auth": registryAuthHeader,
		})
	}

	if err := pull(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 pull(authConfig)
		}
		return err
	}

	return nil
}
Exemple #8
0
func (b *buildFile) CmdFrom(name string) error {
	image, err := b.runtime.repositories.LookupImage(name)
	if err != nil {
		if b.runtime.graph.IsNotExist(err) {
			remote, tag := utils.ParseRepositoryTag(name)
			pullRegistryAuth := b.authConfig
			if len(b.configFile.Configs) > 0 {
				// The request came with a full auth config file, we prefer to use that
				endpoint, _, err := registry.ResolveRepositoryName(remote)
				if err != nil {
					return err
				}
				resolvedAuth := b.configFile.ResolveAuthConfig(endpoint)
				pullRegistryAuth = &resolvedAuth
			}
			job := b.srv.Eng.Job("pull", remote, tag)
			job.SetenvBool("json", b.sf.Json())
			job.SetenvBool("parallel", true)
			job.SetenvJson("authConfig", pullRegistryAuth)
			job.Stdout.Add(b.outOld)
			if err := job.Run(); err != nil {
				return err
			}
			image, err = b.runtime.repositories.LookupImage(name)
			if err != nil {
				return err
			}
		} else {
			return err
		}
	}
	b.image = image.ID
	b.config = &runconfig.Config{}
	if image.Config != nil {
		b.config = image.Config
	}
	if b.config.Env == nil || len(b.config.Env) == 0 {
		b.config.Env = append(b.config.Env, "HOME=/", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin")
	}
	// Process ONBUILD triggers if they exist
	if nTriggers := len(b.config.OnBuild); nTriggers != 0 {
		fmt.Fprintf(b.errStream, "# Executing %d build triggers\n", nTriggers)
	}
	for n, step := range b.config.OnBuild {
		if err := b.BuildStep(fmt.Sprintf("onbuild-%d", n), step); err != nil {
			return err
		}
	}
	b.config.OnBuild = []string{}
	return nil
}
Exemple #9
0
func (srv *Server) ImageDelete(name string, autoPrune bool) ([]APIRmi, error) {
	img, err := srv.runtime.repositories.LookupImage(name)
	if err != nil {
		return nil, fmt.Errorf("No such image: %s", name)
	}
	if !autoPrune {
		if err := srv.runtime.graph.Delete(img.ID); err != nil {
			return nil, fmt.Errorf("Error deleting image %s: %s", name, err)
		}
		return nil, nil
	}

	name, tag := utils.ParseRepositoryTag(name)
	return srv.deleteImage(img, name, tag)
}
Exemple #10
0
// CmdTag assigns a new name and tag to an existing image. If the tag already exists,
// it is changed and the image previously referenced by the tag loses that reference.
// This may cause the old image to be garbage-collected if its reference count reaches zero.
//
// Syntax: image_tag NEWNAME OLDNAME
// Example: image_tag shykes/myapp:latest shykes/myapp:1.42.0
func (s *TagStore) CmdTag(job *engine.Job) engine.Status {
	if len(job.Args) != 2 {
		return job.Errorf("usage: %s NEWNAME OLDNAME", job.Name)
	}
	var (
		newName = job.Args[0]
		oldName = job.Args[1]
	)
	newRepo, newTag := utils.ParseRepositoryTag(newName)
	// FIXME: Set should either parse both old and new name, or neither.
	// 	the current prototype is inconsistent.
	if err := s.Set(newRepo, newTag, oldName, true); err != nil {
		return job.Error(err)
	}
	return engine.StatusOK
}
Exemple #11
0
func (store *TagStore) LookupImage(name string) (*Image, error) {
	// FIXME: standardize on returning nil when the image doesn't exist, and err for everything else
	// (so we can pass all errors here)
	repos, tag := utils.ParseRepositoryTag(name)
	if tag == "" {
		tag = DEFAULTTAG
	}
	img, err := store.GetImage(repos, tag)
	if err != nil {
		return nil, err
	} else if img == nil {
		if img, err = store.graph.Get(name); err != nil {
			return nil, err
		}
	}
	return img, nil
}
Exemple #12
0
func (srv *Server) deleteImage(img *Image, repoName, tag string) ([]APIRmi, error) {
	imgs := []APIRmi{}
	tags := []string{}

	//If delete by id, see if the id belong only to one repository
	if repoName == "" {
		for _, repoAndTag := range srv.runtime.repositories.ByID()[img.ID] {
			parsedRepo, parsedTag := utils.ParseRepositoryTag(repoAndTag)
			if repoName == "" || repoName == parsedRepo {
				repoName = parsedRepo
				if parsedTag != "" {
					tags = append(tags, parsedTag)
				}
			} else if repoName != parsedRepo {
				// the id belongs to multiple repos, like base:latest and user:test,
				// in that case return conflict
				return imgs, nil
			}
		}
	} else {
		tags = append(tags, tag)
	}
	//Untag the current image
	for _, tag := range tags {
		tagDeleted, err := srv.runtime.repositories.Delete(repoName, tag)
		if err != nil {
			return nil, err
		}
		if tagDeleted {
			imgs = append(imgs, APIRmi{Untagged: img.ID})
			srv.LogEvent("untag", img.ID, "")
		}
	}
	if len(srv.runtime.repositories.ByID()[img.ID]) == 0 {
		if err := srv.deleteImageAndChildren(img.ID, &imgs); err != nil {
			if err != ErrImageReferenced {
				return imgs, err
			}
		} else if err := srv.deleteImageParents(img, &imgs); err != nil {
			if err != ErrImageReferenced {
				return imgs, err
			}
		}
	}
	return imgs, nil
}
Exemple #13
0
func (srv *Server) ContainerCreate(job *engine.Job) string {
	var name string
	if len(job.Args) == 1 {
		name = job.Args[0]
	} else if len(job.Args) > 1 {
		return fmt.Sprintf("Usage: %s ", job.Name)
	}
	var config Config
	if err := job.ExportEnv(&config); err != nil {
		return err.Error()
	}
	if config.Memory != 0 && config.Memory < 524288 {
		return "Minimum memory limit allowed is 512k"
	}
	if config.Memory > 0 && !srv.runtime.capabilities.MemoryLimit {
		config.Memory = 0
	}
	if config.Memory > 0 && !srv.runtime.capabilities.SwapLimit {
		config.MemorySwap = -1
	}
	container, buildWarnings, err := srv.runtime.Create(&config, name)
	if err != nil {
		if srv.runtime.graph.IsNotExist(err) {
			_, tag := utils.ParseRepositoryTag(config.Image)
			if tag == "" {
				tag = DEFAULTTAG
			}
			return fmt.Sprintf("No such image: %s (tag: %s)", config.Image, tag)
		}
		return err.Error()
	}
	srv.LogEvent("create", container.ID, srv.runtime.repositories.ImageName(container.Image))
	// FIXME: this is necessary because runtime.Create might return a nil container
	// with a non-nil error. This should not happen! Once it's fixed we
	// can remove this workaround.
	if container != nil {
		job.Printf("%s\n", container.ID)
	}
	for _, warning := range buildWarnings {
		job.Errorf("%s\n", warning)
	}
	return "0"
}
Exemple #14
0
func (b *buildFile) CmdFrom(name string) error {
	image, err := b.runtime.repositories.LookupImage(name)
	if err != nil {
		if b.runtime.graph.IsNotExist(err) {
			remote, tag := utils.ParseRepositoryTag(name)
			if err := b.srv.ImagePull(remote, tag, b.out, utils.NewStreamFormatter(false), nil); err != nil {
				return err
			}
			image, err = b.runtime.repositories.LookupImage(name)
			if err != nil {
				return err
			}
		} else {
			return err
		}
	}
	b.image = image.ID
	b.config = &Config{}
	return nil
}
Exemple #15
0
func getImagesLookup(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
	if vars == nil {
		return fmt.Errorf("Missing parameter")
	}
	name := vars["name"]
	parsedRepo, parsedTag := utils.ParseRepositoryTag(name)
	if parsedTag != "" {
		imgs, err := srv.LookupImage(parsedRepo, parsedTag)
		if err != nil {
			return err
		}
		if imgs != nil {
			if len(imgs) != 0 {
				return writeJSON(w, http.StatusOK, imgs[0])
			}
		}
	}
	w.WriteHeader(http.StatusNotFound)
	return nil
}
Exemple #16
0
func (b *buildFile) CmdFrom(name string) error {
	image, err := b.runtime.repositories.LookupImage(name)
	if err != nil {
		if b.runtime.graph.IsNotExist(err) {
			remote, tag := utils.ParseRepositoryTag(name)
			pullRegistryAuth := b.authConfig
			if len(b.configFile.Configs) > 0 {
				// The request came with a full auth config file, we prefer to use that
				endpoint, _, err := registry.ResolveRepositoryName(remote)
				if err != nil {
					return err
				}
				resolvedAuth := b.configFile.ResolveAuthConfig(endpoint)
				pullRegistryAuth = &resolvedAuth
			}
			job := b.srv.Eng.Job("pull", remote, tag)
			job.SetenvBool("json", b.sf.Json())
			job.SetenvBool("parallel", true)
			job.SetenvJson("authConfig", pullRegistryAuth)
			job.Stdout.Add(b.outOld)
			if err := job.Run(); err != nil {
				return err
			}
			image, err = b.runtime.repositories.LookupImage(name)
			if err != nil {
				return err
			}
		} else {
			return err
		}
	}
	b.image = image.ID
	b.config = &Config{}
	if image.Config != nil {
		b.config = image.Config
	}
	if b.config.Env == nil || len(b.config.Env) == 0 {
		b.config.Env = append(b.config.Env, "HOME=/", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin")
	}
	return nil
}
Exemple #17
0
func (srv *Server) ContainerCreate(job *engine.Job) string {
	var name string
	if len(job.Args) == 1 {
		name = job.Args[0]
	} else if len(job.Args) > 1 {
		return fmt.Sprintf("Usage: %s ", job.Name)
	}
	var config Config
	if err := job.ExportEnv(&config); err != nil {
		return err.Error()
	}
	if config.Memory != 0 && config.Memory < 524288 {
		return "Minimum memory limit allowed is 512k"
	}
	if config.Memory > 0 && !srv.runtime.capabilities.MemoryLimit {
		config.Memory = 0
	}
	if config.Memory > 0 && !srv.runtime.capabilities.SwapLimit {
		config.MemorySwap = -1
	}
	container, buildWarnings, err := srv.runtime.Create(&config, name)
	if err != nil {
		if srv.runtime.graph.IsNotExist(err) {
			_, tag := utils.ParseRepositoryTag(config.Image)
			if tag == "" {
				tag = DEFAULTTAG
			}
			return fmt.Sprintf("No such image: %s (tag: %s)", config.Image, tag)
		}
		return err.Error()
	}
	srv.LogEvent("create", container.ID, srv.runtime.repositories.ImageName(container.Image))
	job.Printf("%s\n", container.ID)
	for _, warning := range buildWarnings {
		job.Errorf("%s\n", warning)
	}
	return "0"
}
Exemple #18
0
func (srv *Server) ImageDelete(name string, autoPrune bool) ([]APIRmi, error) {
	img, err := srv.runtime.repositories.LookupImage(name)
	if err != nil {
		return nil, fmt.Errorf("No such image: %s", name)
	}
	if !autoPrune {
		if err := srv.runtime.graph.Delete(img.ID); err != nil {
			return nil, fmt.Errorf("Cannot delete image %s: %s", name, err)
		}
		return nil, nil
	}

	// Prevent deletion if image is used by a running container
	for _, container := range srv.runtime.List() {
		if container.State.Running {
			parent, err := srv.runtime.repositories.LookupImage(container.Image)
			if err != nil {
				return nil, err
			}

			if err := parent.WalkHistory(func(p *Image) error {
				if img.ID == p.ID {
					return fmt.Errorf("Conflict, cannot delete %s because the running container %s is using it", name, container.ID)
				}
				return nil
			}); err != nil {
				return nil, err
			}
		}
	}

	if strings.Contains(img.ID, name) {
		//delete via ID
		return srv.deleteImage(img, "", "")
	}
	name, tag := utils.ParseRepositoryTag(name)
	return srv.deleteImage(img, name, tag)
}
Exemple #19
0
func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
	if version < 1.3 {
		return fmt.Errorf("Multipart upload for build is no longer supported. Please upgrade your docker client.")
	}
	remoteURL := r.FormValue("remote")
	repoName := r.FormValue("t")
	rawSuppressOutput := r.FormValue("q")
	rawNoCache := r.FormValue("nocache")
	rawRm := r.FormValue("rm")
	repoName, tag := utils.ParseRepositoryTag(repoName)

	var context io.Reader

	if remoteURL == "" {
		context = r.Body
	} else if utils.IsGIT(remoteURL) {
		if !strings.HasPrefix(remoteURL, "git://") {
			remoteURL = "https://" + remoteURL
		}
		root, err := ioutil.TempDir("", "docker-build-git")
		if err != nil {
			return err
		}
		defer os.RemoveAll(root)

		if output, err := exec.Command("git", "clone", remoteURL, root).CombinedOutput(); err != nil {
			return fmt.Errorf("Error trying to use git: %s (%s)", err, output)
		}

		c, err := archive.Tar(root, archive.Bzip2)
		if err != nil {
			return err
		}
		context = c
	} else if utils.IsURL(remoteURL) {
		f, err := utils.Download(remoteURL, ioutil.Discard)
		if err != nil {
			return err
		}
		defer f.Body.Close()
		dockerFile, err := ioutil.ReadAll(f.Body)
		if err != nil {
			return err
		}
		c, err := MkBuildContext(string(dockerFile), nil)
		if err != nil {
			return err
		}
		context = c
	}

	suppressOutput, err := getBoolParam(rawSuppressOutput)
	if err != nil {
		return err
	}
	noCache, err := getBoolParam(rawNoCache)
	if err != nil {
		return err
	}
	rm, err := getBoolParam(rawRm)
	if err != nil {
		return err
	}

	b := NewBuildFile(srv, utils.NewWriteFlusher(w), !suppressOutput, !noCache, rm)
	id, err := b.Build(context)
	if err != nil {
		return fmt.Errorf("Error build: %s", err)
	}
	if repoName != "" {
		srv.runtime.repositories.Set(repoName, tag, id, false)
	}
	return nil
}
Exemple #20
0
func (cli *DockerCli) CmdRun(args ...string) error {
	config, hostConfig, cmd, err := ParseRun(args, nil)
	if err != nil {
		return err
	}
	if config.Image == "" {
		cmd.Usage()
		return nil
	}

	var containerIDFile *os.File
	if len(hostConfig.ContainerIDFile) > 0 {
		if _, err := ioutil.ReadFile(hostConfig.ContainerIDFile); err == nil {
			return fmt.Errorf("cid file found, make sure the other container isn't running or delete %s", hostConfig.ContainerIDFile)
		}
		containerIDFile, err = os.Create(hostConfig.ContainerIDFile)
		if err != nil {
			return fmt.Errorf("failed to create the container ID file: %s", err)
		}
		defer containerIDFile.Close()
	}

	//create the container
	body, statusCode, err := cli.call("POST", "/containers/create", config)
	//if image not found try to pull it
	if statusCode == 404 {
		_, tag := utils.ParseRepositoryTag(config.Image)
		if tag == "" {
			tag = DEFAULTTAG
		}

		fmt.Fprintf(cli.err, "Unable to find image '%s' (tag: %s) locally\n", config.Image, tag)

		v := url.Values{}
		repos, tag := utils.ParseRepositoryTag(config.Image)
		v.Set("fromImage", repos)
		v.Set("tag", tag)

		// Resolve the Repository name from fqn to endpoint + name
		var endpoint string
		endpoint, _, err = registry.ResolveRepositoryName(repos)
		if err != nil {
			return err
		}

		// Load the auth config file, to be able to pull the image
		cli.LoadConfigFile()

		// Resolve the Auth config relevant for this server
		authConfig := cli.configFile.ResolveAuthConfig(endpoint)
		buf, err := json.Marshal(authConfig)
		if err != nil {
			return err
		}

		registryAuthHeader := []string{
			base64.URLEncoding.EncodeToString(buf),
		}
		err = cli.stream("POST", "/images/create?"+v.Encode(), nil, cli.err, map[string][]string{
			"X-Registry-Auth": registryAuthHeader,
		})
		if err != nil {
			return err
		}
		body, _, err = cli.call("POST", "/containers/create", config)
		if err != nil {
			return err
		}
	}
	if err != nil {
		return err
	}

	runResult := &APIRun{}
	err = json.Unmarshal(body, runResult)
	if err != nil {
		return err
	}

	for _, warning := range runResult.Warnings {
		fmt.Fprintf(cli.err, "WARNING: %s\n", warning)
	}
	if len(hostConfig.ContainerIDFile) > 0 {
		if _, err = containerIDFile.WriteString(runResult.ID); err != nil {
			return fmt.Errorf("failed to write the container ID to the file: %s", err)
		}
	}

	//start the container
	if _, _, err = cli.call("POST", "/containers/"+runResult.ID+"/start", hostConfig); err != nil {
		return err
	}

	var wait chan struct{}

	if !config.AttachStdout && !config.AttachStderr {
		// Make this asynchrone in order to let the client write to stdin before having to read the ID
		wait = make(chan struct{})
		go func() {
			defer close(wait)
			fmt.Fprintf(cli.out, "%s\n", runResult.ID)
		}()
	}

	if config.AttachStdin || config.AttachStdout || config.AttachStderr {
		if config.Tty {
			if err := cli.monitorTtySize(runResult.ID); err != nil {
				utils.Debugf("Error monitoring TTY size: %s\n", err)
			}
		}

		v := url.Values{}
		v.Set("logs", "1")
		v.Set("stream", "1")
		var out io.Writer

		if config.AttachStdin {
			v.Set("stdin", "1")
		}
		if config.AttachStdout {
			v.Set("stdout", "1")
			out = cli.out
		}
		if config.AttachStderr {
			v.Set("stderr", "1")
			out = cli.out
		}

		signals := make(chan os.Signal, 1)
		signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
		go func() {
			for sig := range signals {
				fmt.Printf("\nReceived signal: %s; cleaning up\n", sig)
				if err := cli.CmdStop("-t", "4", runResult.ID); err != nil {
					fmt.Printf("failed to stop container: %v", err)
				}
			}
		}()

		if err := cli.hijack("POST", "/containers/"+runResult.ID+"/attach?"+v.Encode(), config.Tty, cli.in, out); err != nil {
			utils.Debugf("Error hijack: %s", err)
			return err
		}
	}

	if !config.AttachStdout && !config.AttachStderr {
		// Detached mode
		<-wait
	} else {
		status, err := getExitCode(cli, runResult.ID)
		if err != nil {
			return err
		}
		if status != 0 {
			return &utils.StatusError{Status: status}
		}
	}

	return nil
}
Exemple #21
0
func (cli *DockerCli) CmdRun(args ...string) error {
	config, hostConfig, cmd, err := ParseRun(args, nil)
	if err != nil {
		return err
	}
	if config.Image == "" {
		cmd.Usage()
		return nil
	}

	var containerIDFile *os.File
	if len(hostConfig.ContainerIDFile) > 0 {
		if _, err := ioutil.ReadFile(hostConfig.ContainerIDFile); err == nil {
			return fmt.Errorf("cid file found, make sure the other container isn't running or delete %s", hostConfig.ContainerIDFile)
		}
		containerIDFile, err = os.Create(hostConfig.ContainerIDFile)
		if err != nil {
			return fmt.Errorf("failed to create the container ID file: %s", err)
		}
		defer containerIDFile.Close()
	}

	//create the container
	body, statusCode, err := cli.call("POST", "/containers/create", config)
	//if image not found try to pull it
	if statusCode == 404 {
		v := url.Values{}
		repos, tag := utils.ParseRepositoryTag(config.Image)
		v.Set("fromImage", repos)
		v.Set("tag", tag)
		err = cli.stream("POST", "/images/create?"+v.Encode(), nil, cli.err)
		if err != nil {
			return err
		}
		body, _, err = cli.call("POST", "/containers/create", config)
		if err != nil {
			return err
		}
	}
	if err != nil {
		return err
	}

	runResult := &APIRun{}
	err = json.Unmarshal(body, runResult)
	if err != nil {
		return err
	}

	for _, warning := range runResult.Warnings {
		fmt.Fprintf(cli.err, "WARNING: %s\n", warning)
	}
	if len(hostConfig.ContainerIDFile) > 0 {
		if _, err = containerIDFile.WriteString(runResult.ID); err != nil {
			return fmt.Errorf("failed to write the container ID to the file: %s", err)
		}
	}

	//start the container
	if _, _, err = cli.call("POST", "/containers/"+runResult.ID+"/start", hostConfig); err != nil {
		return err
	}

	var wait chan struct{}

	if !config.AttachStdout && !config.AttachStderr {
		// Make this asynchrone in order to let the client write to stdin before having to read the ID
		wait = make(chan struct{})
		go func() {
			defer close(wait)
			fmt.Fprintf(cli.out, "%s\n", runResult.ID)
		}()
	}

	if config.AttachStdin || config.AttachStdout || config.AttachStderr {
		if config.Tty {
			if err := cli.monitorTtySize(runResult.ID); err != nil {
				utils.Debugf("Error monitoring TTY size: %s\n", err)
			}
		}

		v := url.Values{}
		v.Set("logs", "1")
		v.Set("stream", "1")

		if config.AttachStdin {
			v.Set("stdin", "1")
		}
		if config.AttachStdout {
			v.Set("stdout", "1")
		}
		if config.AttachStderr {
			v.Set("stderr", "1")
		}

		signals := make(chan os.Signal, 1)
		signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
		go func() {
			for sig := range signals {
				fmt.Printf("\nReceived signal: %s; cleaning up\n", sig)
				if err := cli.CmdStop("-t", "4", runResult.ID); err != nil {
					fmt.Printf("failed to stop container: %v", err)
				}
			}
		}()

		if err := cli.hijack("POST", "/containers/"+runResult.ID+"/attach?"+v.Encode(), config.Tty, cli.in, cli.out); err != nil {
			utils.Debugf("Error hijack: %s", err)
			return err
		}
	}

	if !config.AttachStdout && !config.AttachStderr {
		<-wait
	}
	return nil
}
Exemple #22
0
func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
	if version < 1.3 {
		return fmt.Errorf("Multipart upload for build is no longer supported. Please upgrade your docker client.")
	}
	var (
		remoteURL         = r.FormValue("remote")
		repoName          = r.FormValue("t")
		rawSuppressOutput = r.FormValue("q")
		rawNoCache        = r.FormValue("nocache")
		rawRm             = r.FormValue("rm")
		authEncoded       = r.Header.Get("X-Registry-Auth")
		authConfig        = &auth.AuthConfig{}
		configFileEncoded = r.Header.Get("X-Registry-Config")
		configFile        = &auth.ConfigFile{}
		tag               string
	)
	repoName, tag = utils.ParseRepositoryTag(repoName)

	// This block can be removed when API versions prior to 1.9 are deprecated.
	// Both headers will be parsed and sent along to the daemon, but if a non-empty
	// ConfigFile is present, any value provided as an AuthConfig directly will
	// be overridden. See BuildFile::CmdFrom for details.
	if version < 1.9 && authEncoded != "" {
		authJson := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
		if err := json.NewDecoder(authJson).Decode(authConfig); err != nil {
			// for a pull it is not an error if no auth was given
			// to increase compatibility with the existing api it is defaulting to be empty
			authConfig = &auth.AuthConfig{}
		}
	}

	if configFileEncoded != "" {
		configFileJson := base64.NewDecoder(base64.URLEncoding, strings.NewReader(configFileEncoded))
		if err := json.NewDecoder(configFileJson).Decode(configFile); err != nil {
			// for a pull it is not an error if no auth was given
			// to increase compatibility with the existing api it is defaulting to be empty
			configFile = &auth.ConfigFile{}
		}
	}

	var context io.Reader

	if remoteURL == "" {
		context = r.Body
	} else if utils.IsGIT(remoteURL) {
		if !strings.HasPrefix(remoteURL, "git://") {
			remoteURL = "https://" + remoteURL
		}
		root, err := ioutil.TempDir("", "docker-build-git")
		if err != nil {
			return err
		}
		defer os.RemoveAll(root)

		if output, err := exec.Command("git", "clone", remoteURL, root).CombinedOutput(); err != nil {
			return fmt.Errorf("Error trying to use git: %s (%s)", err, output)
		}

		c, err := archive.Tar(root, archive.Uncompressed)
		if err != nil {
			return err
		}
		context = c
	} else if utils.IsURL(remoteURL) {
		f, err := utils.Download(remoteURL)
		if err != nil {
			return err
		}
		defer f.Body.Close()
		dockerFile, err := ioutil.ReadAll(f.Body)
		if err != nil {
			return err
		}
		c, err := MkBuildContext(string(dockerFile), nil)
		if err != nil {
			return err
		}
		context = c
	}

	suppressOutput, err := getBoolParam(rawSuppressOutput)
	if err != nil {
		return err
	}
	noCache, err := getBoolParam(rawNoCache)
	if err != nil {
		return err
	}
	rm, err := getBoolParam(rawRm)
	if err != nil {
		return err
	}

	if version >= 1.8 {
		w.Header().Set("Content-Type", "application/json")
	}
	sf := utils.NewStreamFormatter(version >= 1.8)
	b := NewBuildFile(srv,
		&StdoutFormater{
			Writer:          utils.NewWriteFlusher(w),
			StreamFormatter: sf,
		},
		&StderrFormater{
			Writer:          utils.NewWriteFlusher(w),
			StreamFormatter: sf,
		},
		!suppressOutput, !noCache, rm, utils.NewWriteFlusher(w), sf, authConfig, configFile)
	id, err := b.Build(context)
	if err != nil {
		if sf.Used() {
			w.Write(sf.FormatError(err))
			return nil
		}
		return fmt.Errorf("Error build: %s", err)
	}
	if repoName != "" {
		srv.runtime.repositories.Set(repoName, tag, id, false)
	}
	return nil
}
Exemple #23
0
func (cli *DockerCli) CmdRun(args ...string) error {
	config, hostConfig, cmd, err := ParseRun(args, nil)
	if err != nil {
		return err
	}
	if config.Image == "" {
		cmd.Usage()
		return nil
	}

	//create the container
	body, statusCode, err := cli.call("POST", "/containers/create", config)
	//if image not found try to pull it
	if statusCode == 404 {
		v := url.Values{}
		repos, tag := utils.ParseRepositoryTag(config.Image)
		v.Set("fromImage", repos)
		v.Set("tag", tag)
		err = cli.stream("POST", "/images/create?"+v.Encode(), nil, cli.err)
		if err != nil {
			return err
		}
		body, _, err = cli.call("POST", "/containers/create", config)
		if err != nil {
			return err
		}
	}
	if err != nil {
		return err
	}

	runResult := &APIRun{}
	err = json.Unmarshal(body, runResult)
	if err != nil {
		return err
	}

	for _, warning := range runResult.Warnings {
		fmt.Fprintf(cli.err, "WARNING: %s\n", warning)
	}

	//start the container
	if _, _, err = cli.call("POST", "/containers/"+runResult.ID+"/start", hostConfig); err != nil {
		return err
	}

	var wait chan struct{}

	if !config.AttachStdout && !config.AttachStderr {
		// Make this asynchrone in order to let the client write to stdin before having to read the ID
		wait = make(chan struct{})
		go func() {
			defer close(wait)
			fmt.Fprintf(cli.out, "%s\n", runResult.ID)
		}()
	}

	if config.AttachStdin || config.AttachStdout || config.AttachStderr {
		if config.Tty {
			if err := cli.monitorTtySize(runResult.ID); err != nil {
				return err
			}
		}

		v := url.Values{}
		v.Set("logs", "1")
		v.Set("stream", "1")

		if config.AttachStdin {
			v.Set("stdin", "1")
		}
		if config.AttachStdout {
			v.Set("stdout", "1")
		}
		if config.AttachStderr {
			v.Set("stderr", "1")
		}

		if err := cli.hijack("POST", "/containers/"+runResult.ID+"/attach?"+v.Encode(), config.Tty, cli.in, cli.out); err != nil {
			utils.Debugf("Error hijack: %s", err)
			return err
		}
	}

	if !config.AttachStdout && !config.AttachStderr {
		<-wait
	}
	return nil
}