Signed-off-by: David Calavera <david.calavera@gmail.com>
| ... | ... |
@@ -5,9 +5,7 @@ import ( |
| 5 | 5 |
"encoding/json" |
| 6 | 6 |
"fmt" |
| 7 | 7 |
"io" |
| 8 |
- "net/url" |
|
| 9 | 8 |
"os" |
| 10 |
- "strings" |
|
| 11 | 9 |
|
| 12 | 10 |
"github.com/docker/distribution/reference" |
| 13 | 11 |
"github.com/docker/docker/api/client/lib" |
| ... | ... |
@@ -88,11 +86,6 @@ func newCIDFile(path string) (*cidFile, error) {
|
| 88 | 88 |
} |
| 89 | 89 |
|
| 90 | 90 |
func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runconfig.HostConfig, cidfile, name string) (*types.ContainerCreateResponse, error) {
|
| 91 |
- containerValues := url.Values{}
|
|
| 92 |
- if name != "" {
|
|
| 93 |
- containerValues.Set("name", name)
|
|
| 94 |
- } |
|
| 95 |
- |
|
| 96 | 91 |
mergedConfig := runconfig.MergeConfigs(config, hostConfig) |
| 97 | 92 |
|
| 98 | 93 |
var containerIDFile *cidFile |
| ... | ... |
@@ -133,34 +126,32 @@ func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runc |
| 133 | 133 |
} |
| 134 | 134 |
|
| 135 | 135 |
//create the container |
| 136 |
- serverResp, err := cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, nil)
|
|
| 136 |
+ response, err := cli.client.ContainerCreate(mergedConfig, name) |
|
| 137 | 137 |
//if image not found try to pull it |
| 138 |
- if serverResp.statusCode == 404 && strings.Contains(err.Error(), config.Image) {
|
|
| 139 |
- fmt.Fprintf(cli.err, "Unable to find image '%s' locally\n", ref.String()) |
|
| 138 |
+ if err != nil {
|
|
| 139 |
+ if lib.IsErrImageNotFound(err) {
|
|
| 140 |
+ fmt.Fprintf(cli.err, "Unable to find image '%s' locally\n", ref.String()) |
|
| 140 | 141 |
|
| 141 |
- // we don't want to write to stdout anything apart from container.ID |
|
| 142 |
- if err = cli.pullImageCustomOut(config.Image, cli.err); err != nil {
|
|
| 143 |
- return nil, err |
|
| 144 |
- } |
|
| 145 |
- if trustedRef != nil && !isDigested {
|
|
| 146 |
- if err := cli.tagTrusted(trustedRef, ref.(reference.NamedTagged)); err != nil {
|
|
| 142 |
+ // we don't want to write to stdout anything apart from container.ID |
|
| 143 |
+ if err = cli.pullImageCustomOut(config.Image, cli.err); err != nil {
|
|
| 147 | 144 |
return nil, err |
| 148 | 145 |
} |
| 149 |
- } |
|
| 150 |
- // Retry |
|
| 151 |
- if serverResp, err = cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, nil); err != nil {
|
|
| 146 |
+ if trustedRef != nil && !isDigested {
|
|
| 147 |
+ if err := cli.tagTrusted(trustedRef, ref.(reference.NamedTagged)); err != nil {
|
|
| 148 |
+ return nil, err |
|
| 149 |
+ } |
|
| 150 |
+ } |
|
| 151 |
+ // Retry |
|
| 152 |
+ var retryErr error |
|
| 153 |
+ response, retryErr = cli.client.ContainerCreate(mergedConfig, name) |
|
| 154 |
+ if retryErr != nil {
|
|
| 155 |
+ return nil, retryErr |
|
| 156 |
+ } |
|
| 157 |
+ } else {
|
|
| 152 | 158 |
return nil, err |
| 153 | 159 |
} |
| 154 |
- } else if err != nil {
|
|
| 155 |
- return nil, err |
|
| 156 | 160 |
} |
| 157 | 161 |
|
| 158 |
- defer serverResp.body.Close() |
|
| 159 |
- |
|
| 160 |
- var response types.ContainerCreateResponse |
|
| 161 |
- if err := json.NewDecoder(serverResp.body).Decode(&response); err != nil {
|
|
| 162 |
- return nil, err |
|
| 163 |
- } |
|
| 164 | 162 |
for _, warning := range response.Warnings {
|
| 165 | 163 |
fmt.Fprintf(cli.err, "WARNING: %s\n", warning) |
| 166 | 164 |
} |
| 167 | 165 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,43 @@ |
| 0 |
+package lib |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "encoding/json" |
|
| 4 |
+ "net/url" |
|
| 5 |
+ "strings" |
|
| 6 |
+ |
|
| 7 |
+ "github.com/docker/docker/api/types" |
|
| 8 |
+ "github.com/docker/docker/runconfig" |
|
| 9 |
+) |
|
| 10 |
+ |
|
| 11 |
+// ContainerCreate creates a new container based in the given configuration. |
|
| 12 |
+// It can be associated with a name, but it's not mandatory. |
|
| 13 |
+func (cli *Client) ContainerCreate(config *runconfig.ContainerConfigWrapper, containerName string) (types.ContainerCreateResponse, error) {
|
|
| 14 |
+ var ( |
|
| 15 |
+ query url.Values |
|
| 16 |
+ response types.ContainerCreateResponse |
|
| 17 |
+ ) |
|
| 18 |
+ if containerName != "" {
|
|
| 19 |
+ query.Set("name", containerName)
|
|
| 20 |
+ } |
|
| 21 |
+ |
|
| 22 |
+ serverResp, err := cli.POST("/containers/create", query, config, nil)
|
|
| 23 |
+ if err != nil {
|
|
| 24 |
+ if serverResp != nil && serverResp.statusCode == 404 && strings.Contains(err.Error(), config.Image) {
|
|
| 25 |
+ return response, imageNotFoundError{config.Image}
|
|
| 26 |
+ } |
|
| 27 |
+ return response, err |
|
| 28 |
+ } |
|
| 29 |
+ |
|
| 30 |
+ if serverResp.statusCode == 404 && strings.Contains(err.Error(), config.Image) {
|
|
| 31 |
+ } |
|
| 32 |
+ |
|
| 33 |
+ if err != nil {
|
|
| 34 |
+ return response, err |
|
| 35 |
+ } |
|
| 36 |
+ |
|
| 37 |
+ if err := json.NewDecoder(serverResp.body).Decode(&response); err != nil {
|
|
| 38 |
+ return response, err |
|
| 39 |
+ } |
|
| 40 |
+ |
|
| 41 |
+ return response, nil |
|
| 42 |
+} |
| 0 | 43 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,31 @@ |
| 0 |
+package lib |
|
| 1 |
+ |
|
| 2 |
+import "fmt" |
|
| 3 |
+ |
|
| 4 |
+// imageNotFoundError implements an error returned when an image is not in the docker host. |
|
| 5 |
+type imageNotFoundError struct {
|
|
| 6 |
+ imageID string |
|
| 7 |
+} |
|
| 8 |
+ |
|
| 9 |
+// Error returns a string representation of an imageNotFoundError |
|
| 10 |
+func (i imageNotFoundError) Error() string {
|
|
| 11 |
+ return fmt.Sprintf("Image not found: %s", i.imageID)
|
|
| 12 |
+} |
|
| 13 |
+ |
|
| 14 |
+// ImageNotFound returns the ID of the image not found on the docker host. |
|
| 15 |
+func (i imageNotFoundError) ImageIDNotFound() string {
|
|
| 16 |
+ return i.imageID |
|
| 17 |
+} |
|
| 18 |
+ |
|
| 19 |
+// ImageNotFound is an interface that describes errors caused |
|
| 20 |
+// when an image is not found in the docker host. |
|
| 21 |
+type ImageNotFound interface {
|
|
| 22 |
+ ImageIDNotFound() string |
|
| 23 |
+} |
|
| 24 |
+ |
|
| 25 |
+// IsImageNotFound returns true when the error is caused |
|
| 26 |
+// when an image is not found in the docker host. |
|
| 27 |
+func IsErrImageNotFound(err error) bool {
|
|
| 28 |
+ _, ok := err.(ImageNotFound) |
|
| 29 |
+ return ok |
|
| 30 |
+} |