github.com/a4a881d4/docker@v1.9.0-rc2/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...]"}, Cli.DockerCommands["create"].Description, 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 }