github.com/guilhermebr/docker@v1.4.2-0.20150428121140-67da055cebca/api/client/create.go (about)

     1  package client
     2  
     3  import (
     4  	"encoding/base64"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"net/url"
     9  	"os"
    10  	"strings"
    11  
    12  	"github.com/docker/docker/api/types"
    13  	"github.com/docker/docker/graph"
    14  	"github.com/docker/docker/pkg/parsers"
    15  	"github.com/docker/docker/registry"
    16  	"github.com/docker/docker/runconfig"
    17  	"github.com/docker/docker/utils"
    18  )
    19  
    20  func (cli *DockerCli) pullImage(image string) error {
    21  	return cli.pullImageCustomOut(image, cli.out)
    22  }
    23  
    24  func (cli *DockerCli) pullImageCustomOut(image string, out io.Writer) error {
    25  	v := url.Values{}
    26  	repos, tag := parsers.ParseRepositoryTag(image)
    27  	// pull only the image tagged 'latest' if no tag was specified
    28  	if tag == "" {
    29  		tag = graph.DEFAULTTAG
    30  	}
    31  	v.Set("fromImage", repos)
    32  	v.Set("tag", tag)
    33  
    34  	// Resolve the Repository name from fqn to RepositoryInfo
    35  	repoInfo, err := registry.ParseRepositoryInfo(repos)
    36  	if err != nil {
    37  		return err
    38  	}
    39  
    40  	// Resolve the Auth config relevant for this server
    41  	authConfig := registry.ResolveAuthConfig(cli.configFile, repoInfo.Index)
    42  	buf, err := json.Marshal(authConfig)
    43  	if err != nil {
    44  		return err
    45  	}
    46  
    47  	registryAuthHeader := []string{
    48  		base64.URLEncoding.EncodeToString(buf),
    49  	}
    50  	if err = cli.stream("POST", "/images/create?"+v.Encode(), nil, out, map[string][]string{"X-Registry-Auth": registryAuthHeader}); err != nil {
    51  		return err
    52  	}
    53  	return nil
    54  }
    55  
    56  type cidFile struct {
    57  	path    string
    58  	file    *os.File
    59  	written bool
    60  }
    61  
    62  func newCIDFile(path string) (*cidFile, error) {
    63  	if _, err := os.Stat(path); err == nil {
    64  		return nil, fmt.Errorf("Container ID file found, make sure the other container isn't running or delete %s", path)
    65  	}
    66  
    67  	f, err := os.Create(path)
    68  	if err != nil {
    69  		return nil, fmt.Errorf("Failed to create the container ID file: %s", err)
    70  	}
    71  
    72  	return &cidFile{path: path, file: f}, nil
    73  }
    74  
    75  func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runconfig.HostConfig, cidfile, name string) (*types.ContainerCreateResponse, error) {
    76  	containerValues := url.Values{}
    77  	if name != "" {
    78  		containerValues.Set("name", name)
    79  	}
    80  
    81  	mergedConfig := runconfig.MergeConfigs(config, hostConfig)
    82  
    83  	var containerIDFile *cidFile
    84  	if cidfile != "" {
    85  		var err error
    86  		if containerIDFile, err = newCIDFile(cidfile); err != nil {
    87  			return nil, err
    88  		}
    89  		defer containerIDFile.Close()
    90  	}
    91  
    92  	//create the container
    93  	stream, statusCode, err := cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, nil)
    94  	//if image not found try to pull it
    95  	if statusCode == 404 && strings.Contains(err.Error(), config.Image) {
    96  		repo, tag := parsers.ParseRepositoryTag(config.Image)
    97  		if tag == "" {
    98  			tag = graph.DEFAULTTAG
    99  		}
   100  		fmt.Fprintf(cli.err, "Unable to find image '%s' locally\n", utils.ImageReference(repo, tag))
   101  
   102  		// we don't want to write to stdout anything apart from container.ID
   103  		if err = cli.pullImageCustomOut(config.Image, cli.err); err != nil {
   104  			return nil, err
   105  		}
   106  		// Retry
   107  		if stream, _, err = cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, nil); err != nil {
   108  			return nil, err
   109  		}
   110  	} else if err != nil {
   111  		return nil, err
   112  	}
   113  
   114  	var response types.ContainerCreateResponse
   115  	if err := json.NewDecoder(stream).Decode(&response); err != nil {
   116  		return nil, err
   117  	}
   118  	for _, warning := range response.Warnings {
   119  		fmt.Fprintf(cli.err, "WARNING: %s\n", warning)
   120  	}
   121  	if containerIDFile != nil {
   122  		if err = containerIDFile.Write(response.ID); err != nil {
   123  			return nil, err
   124  		}
   125  	}
   126  	return &response, nil
   127  }
   128  
   129  // CmdCreate creates a new container from a given image.
   130  //
   131  // Usage: docker create [OPTIONS] IMAGE [COMMAND] [ARG...]
   132  func (cli *DockerCli) CmdCreate(args ...string) error {
   133  	cmd := cli.Subcmd("create", "IMAGE [COMMAND] [ARG...]", "Create a new container", true)
   134  
   135  	// These are flags not stored in Config/HostConfig
   136  	var (
   137  		flName = cmd.String([]string{"-name"}, "", "Assign a name to the container")
   138  	)
   139  
   140  	config, hostConfig, cmd, err := runconfig.Parse(cmd, args)
   141  	if err != nil {
   142  		cmd.ReportError(err.Error(), true)
   143  	}
   144  	if config.Image == "" {
   145  		cmd.Usage()
   146  		return nil
   147  	}
   148  	response, err := cli.createContainer(config, hostConfig, hostConfig.ContainerIDFile, *flName)
   149  	if err != nil {
   150  		return err
   151  	}
   152  	fmt.Fprintf(cli.out, "%s\n", response.ID)
   153  	return nil
   154  }