8 "github.com/docker/cli/cli"
9 "github.com/docker/cli/cli/command"
10 "github.com/docker/cli/cli/command/image"
11 "github.com/docker/distribution/reference"
12 "github.com/docker/docker/api/types"
13 "github.com/docker/docker/api/types/container"
14 apiclient "github.com/docker/docker/client"
15 "github.com/docker/docker/pkg/jsonmessage"
16 "github.com/docker/docker/registry"
17 "github.com/pkg/errors"
18 "github.com/spf13/cobra"
19 "github.com/spf13/pflag"
20 "golang.org/x/net/context"
23 type createOptions struct {
27 // NewCreateCommand creates a new cobra.Command for `docker create`
28 func NewCreateCommand(dockerCli command.Cli) *cobra.Command {
29 var opts createOptions
30 var copts *containerOptions
32 cmd := &cobra.Command{
33 Use: "create [OPTIONS] IMAGE [COMMAND] [ARG...]",
34 Short: "Create a new container",
35 Args: cli.RequiresMinArgs(1),
36 RunE: func(cmd *cobra.Command, args []string) error {
41 return runCreate(dockerCli, cmd.Flags(), &opts, copts)
46 flags.SetInterspersed(false)
48 flags.StringVar(&opts.name, "name", "", "Assign a name to the container")
50 // Add an explicit help that doesn't have a `-h` to prevent the conflict
52 flags.Bool("help", false, "Print usage")
54 command.AddTrustVerificationFlags(flags)
55 copts = addFlags(flags)
59 func runCreate(dockerCli command.Cli, flags *pflag.FlagSet, opts *createOptions, copts *containerOptions) error {
60 containerConfig, err := parse(flags, copts)
62 reportError(dockerCli.Err(), "create", err.Error(), true)
63 return cli.StatusError{StatusCode: 125}
65 response, err := createContainer(context.Background(), dockerCli, containerConfig, opts.name)
69 fmt.Fprintln(dockerCli.Out(), response.ID)
73 func pullImage(ctx context.Context, dockerCli command.Cli, image string, out io.Writer) error {
74 ref, err := reference.ParseNormalizedNamed(image)
79 // Resolve the Repository name from fqn to RepositoryInfo
80 repoInfo, err := registry.ParseRepositoryInfo(ref)
85 authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index)
86 encodedAuth, err := command.EncodeAuthToBase64(authConfig)
91 options := types.ImageCreateOptions{
92 RegistryAuth: encodedAuth,
95 responseBody, err := dockerCli.Client().ImageCreate(ctx, image, options)
99 defer responseBody.Close()
101 return jsonmessage.DisplayJSONMessagesStream(
104 dockerCli.Out().FD(),
105 dockerCli.Out().IsTerminal(),
109 type cidFile struct {
115 func (cid *cidFile) Close() error {
121 if err := os.Remove(cid.path); err != nil {
122 return errors.Errorf("failed to remove the CID file '%s': %s \n", cid.path, err)
128 func (cid *cidFile) Write(id string) error {
129 if _, err := cid.file.Write([]byte(id)); err != nil {
130 return errors.Errorf("Failed to write the container ID to the file: %s", err)
136 func newCIDFile(path string) (*cidFile, error) {
137 if _, err := os.Stat(path); err == nil {
138 return nil, errors.Errorf("Container ID file found, make sure the other container isn't running or delete %s", path)
141 f, err := os.Create(path)
143 return nil, errors.Errorf("Failed to create the container ID file: %s", err)
146 return &cidFile{path: path, file: f}, nil
149 func createContainer(ctx context.Context, dockerCli command.Cli, containerConfig *containerConfig, name string) (*container.ContainerCreateCreatedBody, error) {
150 config := containerConfig.Config
151 hostConfig := containerConfig.HostConfig
152 networkingConfig := containerConfig.NetworkingConfig
153 stderr := dockerCli.Err()
156 containerIDFile *cidFile
157 trustedRef reference.Canonical
158 namedRef reference.Named
161 cidfile := hostConfig.ContainerIDFile
164 if containerIDFile, err = newCIDFile(cidfile); err != nil {
167 defer containerIDFile.Close()
170 ref, err := reference.ParseAnyReference(config.Image)
174 if named, ok := ref.(reference.Named); ok {
175 namedRef = reference.TagNameOnly(named)
177 if taggedRef, ok := namedRef.(reference.NamedTagged); ok && command.IsTrusted() {
179 trustedRef, err = image.TrustedReference(ctx, dockerCli, taggedRef, nil)
183 config.Image = reference.FamiliarString(trustedRef)
187 //create the container
188 response, err := dockerCli.Client().ContainerCreate(ctx, config, hostConfig, networkingConfig, name)
190 //if image not found try to pull it
192 if apiclient.IsErrImageNotFound(err) && namedRef != nil {
193 fmt.Fprintf(stderr, "Unable to find image '%s' locally\n", reference.FamiliarString(namedRef))
195 // we don't want to write to stdout anything apart from container.ID
196 if err = pullImage(ctx, dockerCli, config.Image, stderr); err != nil {
199 if taggedRef, ok := namedRef.(reference.NamedTagged); ok && trustedRef != nil {
200 if err := image.TagTrusted(ctx, dockerCli, trustedRef, taggedRef); err != nil {
206 response, retryErr = dockerCli.Client().ContainerCreate(ctx, config, hostConfig, networkingConfig, name)
215 for _, warning := range response.Warnings {
216 fmt.Fprintf(stderr, "WARNING: %s\n", warning)
218 if containerIDFile != nil {
219 if err = containerIDFile.Write(response.ID); err != nil {
223 return &response, nil