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 }