github.com/crquan/docker@v1.8.1/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  	Cli "github.com/docker/docker/cli"
    14  	"github.com/docker/docker/graph/tags"
    15  	"github.com/docker/docker/pkg/parsers"
    16  	"github.com/docker/docker/registry"
    17  	"github.com/docker/docker/runconfig"
    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 = tags.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  	sopts := &streamOpts{
    51  		rawTerminal: true,
    52  		out:         out,
    53  		headers:     map[string][]string{"X-Registry-Auth": registryAuthHeader},
    54  	}
    55  	if _, err := cli.stream("POST", "/images/create?"+v.Encode(), sopts); err != nil {
    56  		return err
    57  	}
    58  	return nil
    59  }
    60  
    61  type cidFile struct {
    62  	path    string
    63  	file    *os.File
    64  	written bool
    65  }
    66  
    67  func newCIDFile(path string) (*cidFile, error) {
    68  	if _, err := os.Stat(path); err == nil {
    69  		return nil, fmt.Errorf("Container ID file found, make sure the other container isn't running or delete %s", path)
    70  	}
    71  
    72  	f, err := os.Create(path)
    73  	if err != nil {
    74  		return nil, fmt.Errorf("Failed to create the container ID file: %s", err)
    75  	}
    76  
    77  	return &cidFile{path: path, file: f}, nil
    78  }
    79  
    80  func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runconfig.HostConfig, cidfile, name string) (*types.ContainerCreateResponse, error) {
    81  	containerValues := url.Values{}
    82  	if name != "" {
    83  		containerValues.Set("name", name)
    84  	}
    85  
    86  	mergedConfig := runconfig.MergeConfigs(config, hostConfig)
    87  
    88  	var containerIDFile *cidFile
    89  	if cidfile != "" {
    90  		var err error
    91  		if containerIDFile, err = newCIDFile(cidfile); err != nil {
    92  			return nil, err
    93  		}
    94  		defer containerIDFile.Close()
    95  	}
    96  
    97  	repo, tag := parsers.ParseRepositoryTag(config.Image)
    98  	if tag == "" {
    99  		tag = tags.DEFAULTTAG
   100  	}
   101  
   102  	ref := registry.ParseReference(tag)
   103  	var trustedRef registry.Reference
   104  
   105  	if isTrusted() && !ref.HasDigest() {
   106  		var err error
   107  		trustedRef, err = cli.trustedReference(repo, ref)
   108  		if err != nil {
   109  			return nil, err
   110  		}
   111  		config.Image = trustedRef.ImageName(repo)
   112  	}
   113  
   114  	//create the container
   115  	serverResp, err := cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, nil)
   116  	//if image not found try to pull it
   117  	if serverResp.statusCode == 404 && strings.Contains(err.Error(), config.Image) {
   118  		fmt.Fprintf(cli.err, "Unable to find image '%s' locally\n", ref.ImageName(repo))
   119  
   120  		// we don't want to write to stdout anything apart from container.ID
   121  		if err = cli.pullImageCustomOut(config.Image, cli.err); err != nil {
   122  			return nil, err
   123  		}
   124  		if trustedRef != nil && !ref.HasDigest() {
   125  			repoInfo, err := registry.ParseRepositoryInfo(repo)
   126  			if err != nil {
   127  				return nil, err
   128  			}
   129  			if err := cli.tagTrusted(repoInfo, trustedRef, ref); err != nil {
   130  				return nil, err
   131  			}
   132  		}
   133  		// Retry
   134  		if serverResp, err = cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, nil); err != nil {
   135  			return nil, err
   136  		}
   137  	} else if err != nil {
   138  		return nil, err
   139  	}
   140  
   141  	defer serverResp.body.Close()
   142  
   143  	var response types.ContainerCreateResponse
   144  	if err := json.NewDecoder(serverResp.body).Decode(&response); err != nil {
   145  		return nil, err
   146  	}
   147  	for _, warning := range response.Warnings {
   148  		fmt.Fprintf(cli.err, "WARNING: %s\n", warning)
   149  	}
   150  	if containerIDFile != nil {
   151  		if err = containerIDFile.Write(response.ID); err != nil {
   152  			return nil, err
   153  		}
   154  	}
   155  	return &response, nil
   156  }
   157  
   158  // CmdCreate creates a new container from a given image.
   159  //
   160  // Usage: docker create [OPTIONS] IMAGE [COMMAND] [ARG...]
   161  func (cli *DockerCli) CmdCreate(args ...string) error {
   162  	cmd := Cli.Subcmd("create", []string{"IMAGE [COMMAND] [ARG...]"}, "Create a new container", true)
   163  	addTrustedFlags(cmd, true)
   164  
   165  	// These are flags not stored in Config/HostConfig
   166  	var (
   167  		flName = cmd.String([]string{"-name"}, "", "Assign a name to the container")
   168  	)
   169  
   170  	config, hostConfig, cmd, err := runconfig.Parse(cmd, args)
   171  	if err != nil {
   172  		cmd.ReportError(err.Error(), true)
   173  		os.Exit(1)
   174  	}
   175  	if config.Image == "" {
   176  		cmd.Usage()
   177  		return nil
   178  	}
   179  	response, err := cli.createContainer(config, hostConfig, hostConfig.ContainerIDFile, *flName)
   180  	if err != nil {
   181  		return err
   182  	}
   183  	fmt.Fprintf(cli.out, "%s\n", response.ID)
   184  	return nil
   185  }