Tizen_4.0 base
[platform/upstream/docker-engine.git] / vendor / github.com / docker / cli / cli / command / container / create.go
1 package container
2
3 import (
4         "fmt"
5         "io"
6         "os"
7
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"
21 )
22
23 type createOptions struct {
24         name string
25 }
26
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
31
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 {
37                         copts.Image = args[0]
38                         if len(args) > 1 {
39                                 copts.Args = args[1:]
40                         }
41                         return runCreate(dockerCli, cmd.Flags(), &opts, copts)
42                 },
43         }
44
45         flags := cmd.Flags()
46         flags.SetInterspersed(false)
47
48         flags.StringVar(&opts.name, "name", "", "Assign a name to the container")
49
50         // Add an explicit help that doesn't have a `-h` to prevent the conflict
51         // with hostname
52         flags.Bool("help", false, "Print usage")
53
54         command.AddTrustVerificationFlags(flags)
55         copts = addFlags(flags)
56         return cmd
57 }
58
59 func runCreate(dockerCli command.Cli, flags *pflag.FlagSet, opts *createOptions, copts *containerOptions) error {
60         containerConfig, err := parse(flags, copts)
61         if err != nil {
62                 reportError(dockerCli.Err(), "create", err.Error(), true)
63                 return cli.StatusError{StatusCode: 125}
64         }
65         response, err := createContainer(context.Background(), dockerCli, containerConfig, opts.name)
66         if err != nil {
67                 return err
68         }
69         fmt.Fprintln(dockerCli.Out(), response.ID)
70         return nil
71 }
72
73 func pullImage(ctx context.Context, dockerCli command.Cli, image string, out io.Writer) error {
74         ref, err := reference.ParseNormalizedNamed(image)
75         if err != nil {
76                 return err
77         }
78
79         // Resolve the Repository name from fqn to RepositoryInfo
80         repoInfo, err := registry.ParseRepositoryInfo(ref)
81         if err != nil {
82                 return err
83         }
84
85         authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index)
86         encodedAuth, err := command.EncodeAuthToBase64(authConfig)
87         if err != nil {
88                 return err
89         }
90
91         options := types.ImageCreateOptions{
92                 RegistryAuth: encodedAuth,
93         }
94
95         responseBody, err := dockerCli.Client().ImageCreate(ctx, image, options)
96         if err != nil {
97                 return err
98         }
99         defer responseBody.Close()
100
101         return jsonmessage.DisplayJSONMessagesStream(
102                 responseBody,
103                 out,
104                 dockerCli.Out().FD(),
105                 dockerCli.Out().IsTerminal(),
106                 nil)
107 }
108
109 type cidFile struct {
110         path    string
111         file    *os.File
112         written bool
113 }
114
115 func (cid *cidFile) Close() error {
116         cid.file.Close()
117
118         if cid.written {
119                 return nil
120         }
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)
123         }
124
125         return nil
126 }
127
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)
131         }
132         cid.written = true
133         return nil
134 }
135
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)
139         }
140
141         f, err := os.Create(path)
142         if err != nil {
143                 return nil, errors.Errorf("Failed to create the container ID file: %s", err)
144         }
145
146         return &cidFile{path: path, file: f}, nil
147 }
148
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()
154
155         var (
156                 containerIDFile *cidFile
157                 trustedRef      reference.Canonical
158                 namedRef        reference.Named
159         )
160
161         cidfile := hostConfig.ContainerIDFile
162         if cidfile != "" {
163                 var err error
164                 if containerIDFile, err = newCIDFile(cidfile); err != nil {
165                         return nil, err
166                 }
167                 defer containerIDFile.Close()
168         }
169
170         ref, err := reference.ParseAnyReference(config.Image)
171         if err != nil {
172                 return nil, err
173         }
174         if named, ok := ref.(reference.Named); ok {
175                 namedRef = reference.TagNameOnly(named)
176
177                 if taggedRef, ok := namedRef.(reference.NamedTagged); ok && command.IsTrusted() {
178                         var err error
179                         trustedRef, err = image.TrustedReference(ctx, dockerCli, taggedRef, nil)
180                         if err != nil {
181                                 return nil, err
182                         }
183                         config.Image = reference.FamiliarString(trustedRef)
184                 }
185         }
186
187         //create the container
188         response, err := dockerCli.Client().ContainerCreate(ctx, config, hostConfig, networkingConfig, name)
189
190         //if image not found try to pull it
191         if err != nil {
192                 if apiclient.IsErrImageNotFound(err) && namedRef != nil {
193                         fmt.Fprintf(stderr, "Unable to find image '%s' locally\n", reference.FamiliarString(namedRef))
194
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 {
197                                 return nil, err
198                         }
199                         if taggedRef, ok := namedRef.(reference.NamedTagged); ok && trustedRef != nil {
200                                 if err := image.TagTrusted(ctx, dockerCli, trustedRef, taggedRef); err != nil {
201                                         return nil, err
202                                 }
203                         }
204                         // Retry
205                         var retryErr error
206                         response, retryErr = dockerCli.Client().ContainerCreate(ctx, config, hostConfig, networkingConfig, name)
207                         if retryErr != nil {
208                                 return nil, retryErr
209                         }
210                 } else {
211                         return nil, err
212                 }
213         }
214
215         for _, warning := range response.Warnings {
216                 fmt.Fprintf(stderr, "WARNING: %s\n", warning)
217         }
218         if containerIDFile != nil {
219                 if err = containerIDFile.Write(response.ID); err != nil {
220                         return nil, err
221                 }
222         }
223         return &response, nil
224 }