| ... | ... |
@@ -99,7 +99,6 @@ be found. |
| 99 | 99 |
+ Add `Isolation` to the /info endpoint [#26255](https://github.com/docker/docker/pull/26255) |
| 100 | 100 |
+ Add `userns` to the /info endpoint [#27840](https://github.com/docker/docker/pull/27840) |
| 101 | 101 |
- Do not allow more than one mode be requested at once in the services endpoint [#26643](https://github.com/docker/docker/pull/26643) |
| 102 |
-+ Add `--mount` flag to `docker create` and `docker run` [#26825](https://github.com/docker/docker/pull/26825)[#28150](https://github.com/docker/docker/pull/28150) |
|
| 103 | 102 |
+ Add capability to /containers/create API to specify mounts in a more granular and safer way [#22373](https://github.com/docker/docker/pull/22373) |
| 104 | 103 |
+ Add `--format` flag to `network ls` and `volume ls` [#23475](https://github.com/docker/docker/pull/23475) |
| 105 | 104 |
* Allow the top-level `docker inspect` command to inspect any kind of resource [#23614](https://github.com/docker/docker/pull/23614) |
| ... | ... |
@@ -18,6 +18,10 @@ |
| 18 | 18 |
# ppc64le/golang is a debian:jessie based image with golang installed |
| 19 | 19 |
FROM ppc64le/golang:1.6.3 |
| 20 | 20 |
|
| 21 |
+# allow replacing httpredir or deb mirror |
|
| 22 |
+ARG APT_MIRROR=deb.debian.org |
|
| 23 |
+RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list |
|
| 24 |
+ |
|
| 21 | 25 |
# Packaged dependencies |
| 22 | 26 |
RUN apt-get update && apt-get install -y \ |
| 23 | 27 |
apparmor \ |
| ... | ... |
@@ -1,3 +1,14 @@ |
| 1 |
+# A Swagger 2.0 (a.k.a. OpenAPI) definition of the Engine API. |
|
| 2 |
+# |
|
| 3 |
+# This is used for generating API documentation and the types used by the |
|
| 4 |
+# client/server. See api/README.md for more information. |
|
| 5 |
+# |
|
| 6 |
+# Some style notes: |
|
| 7 |
+# - This file is used by ReDoc, which allows GitHub Flavored Markdown in |
|
| 8 |
+# descriptions. |
|
| 9 |
+# - There is no maximum line length, for ease of editing and pretty diffs. |
|
| 10 |
+# - operationIds are in the format "NounVerb", with a singular noun. |
|
| 11 |
+ |
|
| 1 | 12 |
swagger: "2.0" |
| 2 | 13 |
schemes: |
| 3 | 14 |
- "http" |
| ... | ... |
@@ -45,13 +56,13 @@ info: |
| 45 | 45 |
|
| 46 | 46 |
Docker version | API version | Changes |
| 47 | 47 |
----------------|-------------|--------- |
| 48 |
- 1.12.x | [1.24](/engine/api/v1.24/) | [API changes](/engine/api/version-history/#v1-24-api-changes) |
|
| 49 |
- 1.11.x | [1.23](/engine/api/v1.23/) | [API changes](/engine/api/version-history/#v1-23-api-changes) |
|
| 50 |
- 1.10.x | [1.22](/engine/api/v1.22/) | [API changes](/engine/api/version-history/#v1-22-api-changes) |
|
| 51 |
- 1.9.x | [1.21](/engine/api/v1.21/) | [API changes](/engine/api/version-history/#v1-21-api-changes) |
|
| 52 |
- 1.8.x | [1.20](/engine/api/v1.20/) | [API changes](/engine/api/version-history/#v1-20-api-changes) |
|
| 53 |
- 1.7.x | [1.19](/engine/api/v1.19/) | [API changes](/engine/api/version-history/#v1-19-api-changes) |
|
| 54 |
- 1.6.x | [1.18](/engine/api/v1.18/) | [API changes](/engine/api/version-history/#v1-18-api-changes) |
|
| 48 |
+ 1.12.x | [1.24](https://docs.docker.com/engine/api/v1.24/) | [API changes](https://docs.docker.com/engine/api/version-history/#v1-24-api-changes) |
|
| 49 |
+ 1.11.x | [1.23](https://docs.docker.com/engine/api/v1.23/) | [API changes](https://docs.docker.com/engine/api/version-history/#v1-23-api-changes) |
|
| 50 |
+ 1.10.x | [1.22](https://docs.docker.com/engine/api/v1.22/) | [API changes](https://docs.docker.com/engine/api/version-history/#v1-22-api-changes) |
|
| 51 |
+ 1.9.x | [1.21](https://docs.docker.com/engine/api/v1.21/) | [API changes](https://docs.docker.com/engine/api/version-history/#v1-21-api-changes) |
|
| 52 |
+ 1.8.x | [1.20](https://docs.docker.com/engine/api/v1.20/) | [API changes](https://docs.docker.com/engine/api/version-history/#v1-20-api-changes) |
|
| 53 |
+ 1.7.x | [1.19](https://docs.docker.com/engine/api/v1.19/) | [API changes](https://docs.docker.com/engine/api/version-history/#v1-19-api-changes) |
|
| 54 |
+ 1.6.x | [1.18](https://docs.docker.com/engine/api/v1.18/) | [API changes](https://docs.docker.com/engine/api/version-history/#v1-18-api-changes) |
|
| 55 | 55 |
|
| 56 | 56 |
# Authentication |
| 57 | 57 |
|
| ... | ... |
@@ -68,7 +79,7 @@ info: |
| 68 | 68 |
|
| 69 | 69 |
The `serveraddress` is a domain/IP without a protocol. Throughout this structure, double quotes are required. |
| 70 | 70 |
|
| 71 |
- If you have already got an identity token from the [`/auth` endpoint](#operation/checkAuthentication), you can just pass this instead of credentials: |
|
| 71 |
+ If you have already got an identity token from the [`/auth` endpoint](#operation/SystemAuth), you can just pass this instead of credentials: |
|
| 72 | 72 |
|
| 73 | 73 |
``` |
| 74 | 74 |
{
|
| ... | ... |
@@ -76,6 +87,48 @@ info: |
| 76 | 76 |
} |
| 77 | 77 |
``` |
| 78 | 78 |
|
| 79 |
+# The tags on paths define the menu sections in the ReDoc documentation, so |
|
| 80 |
+# the usage of tags must make sense for that: |
|
| 81 |
+# - They should be singular, not plural. |
|
| 82 |
+# - There should not be too many tags, or the menu becomes unwieldly. For |
|
| 83 |
+# example, it is preferable to add a path to the "System" tag instead of |
|
| 84 |
+# creating a tag with a single path in it. |
|
| 85 |
+# - The order of tags in this list defines the order in the menu. |
|
| 86 |
+tags: |
|
| 87 |
+ # Primary objects |
|
| 88 |
+ - name: "Container" |
|
| 89 |
+ description: | |
|
| 90 |
+ Create and manage containers. |
|
| 91 |
+ - name: "Image" |
|
| 92 |
+ - name: "Network" |
|
| 93 |
+ description: | |
|
| 94 |
+ Networks are user-defined networks that containers can be attached to. See the [networking documentation](https://docs.docker.com/engine/userguide/networking/) for more information. |
|
| 95 |
+ - name: "Volume" |
|
| 96 |
+ description: | |
|
| 97 |
+ Create and manage persistent storage that can be attached to containers. |
|
| 98 |
+ - name: "Exec" |
|
| 99 |
+ description: | |
|
| 100 |
+ Run new commands inside running containers. See the [command-line reference](https://docs.docker.com/engine/reference/commandline/exec/) for more information. |
|
| 101 |
+ |
|
| 102 |
+ To exec a command in a container, you first need to create an exec instance, then start it. These two API endpoints are wrapped up in a single command-line command, `docker exec`. |
|
| 103 |
+ - name: "Secret" |
|
| 104 |
+ # Swarm things |
|
| 105 |
+ - name: "Swarm" |
|
| 106 |
+ description: | |
|
| 107 |
+ Engines can be clustered together in a swarm. See [the swarm mode documentation](https://docs.docker.com/engine/swarm/) for more information. |
|
| 108 |
+ - name: "Node" |
|
| 109 |
+ description: | |
|
| 110 |
+ Nodes are instances of the Engine participating in a swarm. Swarm mode must be enabled for these endpoints to work. |
|
| 111 |
+ - name: "Service" |
|
| 112 |
+ description: | |
|
| 113 |
+ Services are the definitions of tasks to run on a swarm. Swarm mode must be enabled for these endpoints to work. |
|
| 114 |
+ - name: "Task" |
|
| 115 |
+ description: | |
|
| 116 |
+ A task is a container running on a swarm. It is the atomic scheduling unit of swarm. Swarm mode must be enabled for these endpoints to work. |
|
| 117 |
+ # System things |
|
| 118 |
+ - name: "Plugin" |
|
| 119 |
+ - name: "System" |
|
| 120 |
+ |
|
| 79 | 121 |
definitions: |
| 80 | 122 |
Port: |
| 81 | 123 |
type: "object" |
| ... | ... |
@@ -2387,7 +2440,7 @@ paths: |
| 2387 | 2387 |
/containers/json: |
| 2388 | 2388 |
get: |
| 2389 | 2389 |
summary: "List containers" |
| 2390 |
- operationId: "GetContainerList" |
|
| 2390 |
+ operationId: "ContainerList" |
|
| 2391 | 2391 |
produces: |
| 2392 | 2392 |
- "application/json" |
| 2393 | 2393 |
parameters: |
| ... | ... |
@@ -2565,8 +2618,7 @@ paths: |
| 2565 | 2565 |
description: "server error" |
| 2566 | 2566 |
schema: |
| 2567 | 2567 |
$ref: "#/definitions/ErrorResponse" |
| 2568 |
- tags: |
|
| 2569 |
- - "Container" |
|
| 2568 |
+ tags: ["Container"] |
|
| 2570 | 2569 |
/containers/create: |
| 2571 | 2570 |
post: |
| 2572 | 2571 |
summary: "Create a container" |
| ... | ... |
@@ -2765,13 +2817,12 @@ paths: |
| 2765 | 2765 |
description: "server error" |
| 2766 | 2766 |
schema: |
| 2767 | 2767 |
$ref: "#/definitions/ErrorResponse" |
| 2768 |
- tags: |
|
| 2769 |
- - "Container" |
|
| 2768 |
+ tags: ["Container"] |
|
| 2770 | 2769 |
/containers/{id}/json:
|
| 2771 | 2770 |
get: |
| 2772 | 2771 |
summary: "Inspect a container" |
| 2773 | 2772 |
description: "Return low-level information about a container." |
| 2774 |
- operationId: "GetContainerInspect" |
|
| 2773 |
+ operationId: "ContainerInspect" |
|
| 2775 | 2774 |
produces: |
| 2776 | 2775 |
- "application/json" |
| 2777 | 2776 |
responses: |
| ... | ... |
@@ -3042,13 +3093,12 @@ paths: |
| 3042 | 3042 |
type: "boolean" |
| 3043 | 3043 |
default: false |
| 3044 | 3044 |
description: "Return the size of container as fields `SizeRw` and `SizeRootFs`" |
| 3045 |
- tags: |
|
| 3046 |
- - "Container" |
|
| 3045 |
+ tags: ["Container"] |
|
| 3047 | 3046 |
/containers/{id}/top:
|
| 3048 | 3047 |
get: |
| 3049 | 3048 |
summary: "List processes running inside a container" |
| 3050 | 3049 |
description: "On Unix systems, this is done by running the `ps` command. This endpoint is not supported on Windows." |
| 3051 |
- operationId: "GetContainerTop" |
|
| 3050 |
+ operationId: "ContainerTop" |
|
| 3052 | 3051 |
responses: |
| 3053 | 3052 |
200: |
| 3054 | 3053 |
description: "no error" |
| ... | ... |
@@ -3119,8 +3169,7 @@ paths: |
| 3119 | 3119 |
description: "The arguments to pass to `ps`. For example, `aux`" |
| 3120 | 3120 |
type: "string" |
| 3121 | 3121 |
default: "-ef" |
| 3122 |
- tags: |
|
| 3123 |
- - "Container" |
|
| 3122 |
+ tags: ["Container"] |
|
| 3124 | 3123 |
/containers/{id}/logs:
|
| 3125 | 3124 |
get: |
| 3126 | 3125 |
summary: "Get container logs" |
| ... | ... |
@@ -3128,7 +3177,7 @@ paths: |
| 3128 | 3128 |
Get `stdout` and `stderr` logs from a container. |
| 3129 | 3129 |
|
| 3130 | 3130 |
Note: This endpoint works only for containers with the `json-file` or `journald` logging driver. |
| 3131 |
- operationId: "GetContainerLogs" |
|
| 3131 |
+ operationId: "ContainerLogs" |
|
| 3132 | 3132 |
responses: |
| 3133 | 3133 |
101: |
| 3134 | 3134 |
description: "logs returned as a stream" |
| ... | ... |
@@ -3161,7 +3210,7 @@ paths: |
| 3161 | 3161 |
description: | |
| 3162 | 3162 |
Return the logs as a stream. |
| 3163 | 3163 |
|
| 3164 |
- This will return a `101` HTTP response with a `Connection: upgrade` header, then hijack the HTTP connection to send raw output. For more information about hijacking and the stream format, [see the documentation for the attach endpoint](#operation/PostContainerAttach). |
|
| 3164 |
+ This will return a `101` HTTP response with a `Connection: upgrade` header, then hijack the HTTP connection to send raw output. For more information about hijacking and the stream format, [see the documentation for the attach endpoint](#operation/ContainerAttach). |
|
| 3165 | 3165 |
type: "boolean" |
| 3166 | 3166 |
default: false |
| 3167 | 3167 |
- name: "stdout" |
| ... | ... |
@@ -3189,8 +3238,7 @@ paths: |
| 3189 | 3189 |
description: "Only return this number of log lines from the end of the logs. Specify as an integer or `all` to output all log lines." |
| 3190 | 3190 |
type: "string" |
| 3191 | 3191 |
default: "all" |
| 3192 |
- tags: |
|
| 3193 |
- - "Container" |
|
| 3192 |
+ tags: ["Container"] |
|
| 3194 | 3193 |
/containers/{id}/changes:
|
| 3195 | 3194 |
get: |
| 3196 | 3195 |
summary: "Get changes on a container’s filesystem" |
| ... | ... |
@@ -3200,7 +3248,7 @@ paths: |
| 3200 | 3200 |
- `0`: Modified |
| 3201 | 3201 |
- `1`: Added |
| 3202 | 3202 |
- `2`: Deleted |
| 3203 |
- operationId: "GetContainerChanges" |
|
| 3203 |
+ operationId: "ContainerChanges" |
|
| 3204 | 3204 |
produces: |
| 3205 | 3205 |
- "application/json" |
| 3206 | 3206 |
responses: |
| ... | ... |
@@ -3246,13 +3294,12 @@ paths: |
| 3246 | 3246 |
required: true |
| 3247 | 3247 |
description: "ID or name of the container" |
| 3248 | 3248 |
type: "string" |
| 3249 |
- tags: |
|
| 3250 |
- - "Container" |
|
| 3249 |
+ tags: ["Container"] |
|
| 3251 | 3250 |
/containers/{id}/export:
|
| 3252 | 3251 |
get: |
| 3253 | 3252 |
summary: "Export a container" |
| 3254 | 3253 |
description: "Export the contents of a container as a tarball." |
| 3255 |
- operationId: "GetContainerExport" |
|
| 3254 |
+ operationId: "ContainerExport" |
|
| 3256 | 3255 |
produces: |
| 3257 | 3256 |
- "application/octet-stream" |
| 3258 | 3257 |
responses: |
| ... | ... |
@@ -3275,8 +3322,7 @@ paths: |
| 3275 | 3275 |
required: true |
| 3276 | 3276 |
description: "ID or name of the container" |
| 3277 | 3277 |
type: "string" |
| 3278 |
- tags: |
|
| 3279 |
- - "Container" |
|
| 3278 |
+ tags: ["Container"] |
|
| 3280 | 3279 |
/containers/{id}/stats:
|
| 3281 | 3280 |
get: |
| 3282 | 3281 |
summary: "Get container stats based on resource usage" |
| ... | ... |
@@ -3284,7 +3330,7 @@ paths: |
| 3284 | 3284 |
This endpoint returns a live stream of a container’s resource usage statistics. |
| 3285 | 3285 |
|
| 3286 | 3286 |
The `precpu_stats` is the CPU statistic of last read, which is used for calculating the CPU usage percentage. It is not the same as the `cpu_stats` field. |
| 3287 |
- operationId: "GetContainerStats" |
|
| 3287 |
+ operationId: "ContainerStats" |
|
| 3288 | 3288 |
produces: |
| 3289 | 3289 |
- "application/json" |
| 3290 | 3290 |
responses: |
| ... | ... |
@@ -3404,13 +3450,12 @@ paths: |
| 3404 | 3404 |
description: "Stream the output. If false, the stats will be output once and then it will disconnect." |
| 3405 | 3405 |
type: "boolean" |
| 3406 | 3406 |
default: true |
| 3407 |
- tags: |
|
| 3408 |
- - "Container" |
|
| 3407 |
+ tags: ["Container"] |
|
| 3409 | 3408 |
/containers/{id}/resize:
|
| 3410 | 3409 |
post: |
| 3411 | 3410 |
summary: "Resize a container TTY" |
| 3412 | 3411 |
description: "Resize the TTY for a container. You must restart the container for the resize to take effect." |
| 3413 |
- operationId: "PostContainerResize" |
|
| 3412 |
+ operationId: "ContainerResize" |
|
| 3414 | 3413 |
consumes: |
| 3415 | 3414 |
- "application/octet-stream" |
| 3416 | 3415 |
produces: |
| ... | ... |
@@ -3443,12 +3488,11 @@ paths: |
| 3443 | 3443 |
in: "query" |
| 3444 | 3444 |
description: "Width of the tty session in characters" |
| 3445 | 3445 |
type: "integer" |
| 3446 |
- tags: |
|
| 3447 |
- - "Container" |
|
| 3446 |
+ tags: ["Container"] |
|
| 3448 | 3447 |
/containers/{id}/start:
|
| 3449 | 3448 |
post: |
| 3450 | 3449 |
summary: "Start a container" |
| 3451 |
- operationId: "PostContainerStart" |
|
| 3450 |
+ operationId: "ContainerStart" |
|
| 3452 | 3451 |
responses: |
| 3453 | 3452 |
204: |
| 3454 | 3453 |
description: "no error" |
| ... | ... |
@@ -3477,12 +3521,11 @@ paths: |
| 3477 | 3477 |
in: "query" |
| 3478 | 3478 |
description: "Override the key sequence for detaching a container. Format is a single character `[a-Z]` or `ctrl-<value>` where `<value>` is one of: `a-z`, `@`, `^`, `[`, `,` or `_`." |
| 3479 | 3479 |
type: "string" |
| 3480 |
- tags: |
|
| 3481 |
- - "Container" |
|
| 3480 |
+ tags: ["Container"] |
|
| 3482 | 3481 |
/containers/{id}/stop:
|
| 3483 | 3482 |
post: |
| 3484 | 3483 |
summary: "Stop a container" |
| 3485 |
- operationId: "PostContainerStop" |
|
| 3484 |
+ operationId: "ContainerStop" |
|
| 3486 | 3485 |
responses: |
| 3487 | 3486 |
204: |
| 3488 | 3487 |
description: "no error" |
| ... | ... |
@@ -3511,12 +3554,11 @@ paths: |
| 3511 | 3511 |
in: "query" |
| 3512 | 3512 |
description: "Number of seconds to wait before killing the container" |
| 3513 | 3513 |
type: "integer" |
| 3514 |
- tags: |
|
| 3515 |
- - "Container" |
|
| 3514 |
+ tags: ["Container"] |
|
| 3516 | 3515 |
/containers/{id}/restart:
|
| 3517 | 3516 |
post: |
| 3518 | 3517 |
summary: "Restart a container" |
| 3519 |
- operationId: "PostContainerRestart" |
|
| 3518 |
+ operationId: "ContainerRestart" |
|
| 3520 | 3519 |
responses: |
| 3521 | 3520 |
204: |
| 3522 | 3521 |
description: "no error" |
| ... | ... |
@@ -3541,13 +3583,12 @@ paths: |
| 3541 | 3541 |
in: "query" |
| 3542 | 3542 |
description: "Number of seconds to wait before killing the container" |
| 3543 | 3543 |
type: "integer" |
| 3544 |
- tags: |
|
| 3545 |
- - "Container" |
|
| 3544 |
+ tags: ["Container"] |
|
| 3546 | 3545 |
/containers/{id}/kill:
|
| 3547 | 3546 |
post: |
| 3548 | 3547 |
summary: "Kill a container" |
| 3549 | 3548 |
description: "Send a POSIX signal to a container, defaulting to killing to the container." |
| 3550 |
- operationId: "PostContainerKill" |
|
| 3549 |
+ operationId: "ContainerKill" |
|
| 3551 | 3550 |
responses: |
| 3552 | 3551 |
204: |
| 3553 | 3552 |
description: "no error" |
| ... | ... |
@@ -3573,8 +3614,7 @@ paths: |
| 3573 | 3573 |
description: "Signal to send to the container as an integer or string (e.g. `SIGINT`)" |
| 3574 | 3574 |
type: "string" |
| 3575 | 3575 |
default: "SIGKILL" |
| 3576 |
- tags: |
|
| 3577 |
- - "Container" |
|
| 3576 |
+ tags: ["Container"] |
|
| 3578 | 3577 |
/containers/{id}/update:
|
| 3579 | 3578 |
post: |
| 3580 | 3579 |
summary: "Update a container" |
| ... | ... |
@@ -3635,12 +3675,11 @@ paths: |
| 3635 | 3635 |
RestartPolicy: |
| 3636 | 3636 |
MaximumRetryCount: 4 |
| 3637 | 3637 |
Name: "on-failure" |
| 3638 |
- tags: |
|
| 3639 |
- - "Container" |
|
| 3638 |
+ tags: ["Container"] |
|
| 3640 | 3639 |
/containers/{id}/rename:
|
| 3641 | 3640 |
post: |
| 3642 | 3641 |
summary: "Rename a container" |
| 3643 |
- operationId: "PostContainerRename" |
|
| 3642 |
+ operationId: "ContainerRename" |
|
| 3644 | 3643 |
responses: |
| 3645 | 3644 |
204: |
| 3646 | 3645 |
description: "no error" |
| ... | ... |
@@ -3670,8 +3709,7 @@ paths: |
| 3670 | 3670 |
required: true |
| 3671 | 3671 |
description: "New name for the container" |
| 3672 | 3672 |
type: "string" |
| 3673 |
- tags: |
|
| 3674 |
- - "Container" |
|
| 3673 |
+ tags: ["Container"] |
|
| 3675 | 3674 |
/containers/{id}/pause:
|
| 3676 | 3675 |
post: |
| 3677 | 3676 |
summary: "Pause a container" |
| ... | ... |
@@ -3679,7 +3717,7 @@ paths: |
| 3679 | 3679 |
Use the cgroups freezer to suspend all processes in a container. |
| 3680 | 3680 |
|
| 3681 | 3681 |
Traditionally, when suspending a process the `SIGSTOP` signal is used, which is observable by the process being suspended. With the cgroups freezer the process is unaware, and unable to capture, that it is being suspended, and subsequently resumed. |
| 3682 |
- operationId: "PostContainerPause" |
|
| 3682 |
+ operationId: "ContainerPause" |
|
| 3683 | 3683 |
responses: |
| 3684 | 3684 |
204: |
| 3685 | 3685 |
description: "no error" |
| ... | ... |
@@ -3700,13 +3738,12 @@ paths: |
| 3700 | 3700 |
required: true |
| 3701 | 3701 |
description: "ID or name of the container" |
| 3702 | 3702 |
type: "string" |
| 3703 |
- tags: |
|
| 3704 |
- - "Container" |
|
| 3703 |
+ tags: ["Container"] |
|
| 3705 | 3704 |
/containers/{id}/unpause:
|
| 3706 | 3705 |
post: |
| 3707 | 3706 |
summary: "Unpause a container" |
| 3708 | 3707 |
description: "Resume a container which has been paused." |
| 3709 |
- operationId: "PostContainerUnpause" |
|
| 3708 |
+ operationId: "ContainerUnpause" |
|
| 3710 | 3709 |
responses: |
| 3711 | 3710 |
204: |
| 3712 | 3711 |
description: "no error" |
| ... | ... |
@@ -3727,8 +3764,7 @@ paths: |
| 3727 | 3727 |
required: true |
| 3728 | 3728 |
description: "ID or name of the container" |
| 3729 | 3729 |
type: "string" |
| 3730 |
- tags: |
|
| 3731 |
- - "Container" |
|
| 3730 |
+ tags: ["Container"] |
|
| 3732 | 3731 |
/containers/{id}/attach:
|
| 3733 | 3732 |
post: |
| 3734 | 3733 |
summary: "Attach to a container" |
| ... | ... |
@@ -3737,7 +3773,7 @@ paths: |
| 3737 | 3737 |
|
| 3738 | 3738 |
Either the `stream` or `logs` parameter must be `true` for this endpoint to do anything. |
| 3739 | 3739 |
|
| 3740 |
- See [the documentation for the `docker attach` command](/engine/reference/commandline/attach/) for more details. |
|
| 3740 |
+ See [the documentation for the `docker attach` command](https://docs.docker.com/engine/reference/commandline/attach/) for more details. |
|
| 3741 | 3741 |
|
| 3742 | 3742 |
### Hijacking |
| 3743 | 3743 |
|
| ... | ... |
@@ -3777,7 +3813,7 @@ paths: |
| 3777 | 3777 |
|
| 3778 | 3778 |
### Stream format |
| 3779 | 3779 |
|
| 3780 |
- When the TTY setting is disabled in [`POST /containers/create`](#operation/PostContainerCreate), the stream over the hijacked connected is multiplexed to separate out `stdout` and `stderr`. The stream consists of a series of frames, each containing a header and a payload. |
|
| 3780 |
+ When the TTY setting is disabled in [`POST /containers/create`](#operation/ContainerCreate), the stream over the hijacked connected is multiplexed to separate out `stdout` and `stderr`. The stream consists of a series of frames, each containing a header and a payload. |
|
| 3781 | 3781 |
|
| 3782 | 3782 |
The header contains the information which the stream writes (`stdout` or `stderr`). It also contains the size of the associated frame encoded in the last four bytes (`uint32`). |
| 3783 | 3783 |
|
| ... | ... |
@@ -3807,9 +3843,9 @@ paths: |
| 3807 | 3807 |
|
| 3808 | 3808 |
### Stream format when using a TTY |
| 3809 | 3809 |
|
| 3810 |
- When the TTY setting is enabled in [`POST /containers/create`](#operation/PostContainerCreate), the stream is not multiplexed. The data exchanged over the hijacked connection is simply the raw data from the process PTY and client's `stdin`. |
|
| 3810 |
+ When the TTY setting is enabled in [`POST /containers/create`](#operation/ContainerCreate), the stream is not multiplexed. The data exchanged over the hijacked connection is simply the raw data from the process PTY and client's `stdin`. |
|
| 3811 | 3811 |
|
| 3812 |
- operationId: "PostContainerAttach" |
|
| 3812 |
+ operationId: "ContainerAttach" |
|
| 3813 | 3813 |
produces: |
| 3814 | 3814 |
- "application/vnd.docker.raw-stream" |
| 3815 | 3815 |
responses: |
| ... | ... |
@@ -3872,12 +3908,11 @@ paths: |
| 3872 | 3872 |
description: "Attach to `stderr`" |
| 3873 | 3873 |
type: "boolean" |
| 3874 | 3874 |
default: false |
| 3875 |
- tags: |
|
| 3876 |
- - "Container" |
|
| 3875 |
+ tags: ["Container"] |
|
| 3877 | 3876 |
/containers/{id}/attach/ws:
|
| 3878 | 3877 |
get: |
| 3879 | 3878 |
summary: "Attach to a container via a websocket" |
| 3880 |
- operationId: "PostContainerAttachWebsocket" |
|
| 3879 |
+ operationId: "ContainerAttachWebsocket" |
|
| 3881 | 3880 |
responses: |
| 3882 | 3881 |
101: |
| 3883 | 3882 |
description: "no error, hints proxy about hijacking" |
| ... | ... |
@@ -3933,8 +3968,7 @@ paths: |
| 3933 | 3933 |
description: "Attach to `stderr`" |
| 3934 | 3934 |
type: "boolean" |
| 3935 | 3935 |
default: false |
| 3936 |
- tags: |
|
| 3937 |
- - "Container" |
|
| 3936 |
+ tags: ["Container"] |
|
| 3938 | 3937 |
/containers/{id}/wait:
|
| 3939 | 3938 |
post: |
| 3940 | 3939 |
summary: "Wait for a container" |
| ... | ... |
@@ -3969,12 +4003,11 @@ paths: |
| 3969 | 3969 |
required: true |
| 3970 | 3970 |
description: "ID or name of the container" |
| 3971 | 3971 |
type: "string" |
| 3972 |
- tags: |
|
| 3973 |
- - "Container" |
|
| 3972 |
+ tags: ["Container"] |
|
| 3974 | 3973 |
/containers/{id}:
|
| 3975 | 3974 |
delete: |
| 3976 | 3975 |
summary: "Remove a container" |
| 3977 |
- operationId: "DeleteContainer" |
|
| 3976 |
+ operationId: "ContainerDelete" |
|
| 3978 | 3977 |
responses: |
| 3979 | 3978 |
204: |
| 3980 | 3979 |
description: "no error" |
| ... | ... |
@@ -4009,13 +4042,12 @@ paths: |
| 4009 | 4009 |
description: "If the container is running, kill it before removing it." |
| 4010 | 4010 |
type: "boolean" |
| 4011 | 4011 |
default: false |
| 4012 |
- tags: |
|
| 4013 |
- - "Container" |
|
| 4012 |
+ tags: ["Container"] |
|
| 4014 | 4013 |
/containers/{id}/archive:
|
| 4015 | 4014 |
head: |
| 4016 | 4015 |
summary: "Get information about files in a container" |
| 4017 | 4016 |
description: "A response header `X-Docker-Container-Path-Stat` is return containing a base64 - encoded JSON object with some filesystem header information about the path." |
| 4018 |
- operationId: "HeadContainerArchive" |
|
| 4017 |
+ operationId: "ContainerArchiveHead" |
|
| 4019 | 4018 |
responses: |
| 4020 | 4019 |
200: |
| 4021 | 4020 |
description: "no error" |
| ... | ... |
@@ -4056,12 +4088,11 @@ paths: |
| 4056 | 4056 |
required: true |
| 4057 | 4057 |
description: "Resource in the container’s filesystem to archive." |
| 4058 | 4058 |
type: "string" |
| 4059 |
- tags: |
|
| 4060 |
- - "Container" |
|
| 4059 |
+ tags: ["Container"] |
|
| 4061 | 4060 |
get: |
| 4062 | 4061 |
summary: "Get an archive of a filesystem resource in a container" |
| 4063 | 4062 |
description: "Get an tar archive of a resource in the filesystem of container id." |
| 4064 |
- operationId: "GetContainerArchive" |
|
| 4063 |
+ operationId: "ContainerGetArchive" |
|
| 4065 | 4064 |
produces: |
| 4066 | 4065 |
- "application/x-tar" |
| 4067 | 4066 |
responses: |
| ... | ... |
@@ -4100,12 +4131,11 @@ paths: |
| 4100 | 4100 |
required: true |
| 4101 | 4101 |
description: "Resource in the container’s filesystem to archive." |
| 4102 | 4102 |
type: "string" |
| 4103 |
- tags: |
|
| 4104 |
- - "Container" |
|
| 4103 |
+ tags: ["Container"] |
|
| 4105 | 4104 |
put: |
| 4106 | 4105 |
summary: "Extract an archive of files or folders to a directory in a container" |
| 4107 | 4106 |
description: "Upload a tar archive to be extracted to a path in the filesystem of container id." |
| 4108 |
- operationId: "PutContainerArchive" |
|
| 4107 |
+ operationId: "ContainerPutArchive" |
|
| 4109 | 4108 |
consumes: |
| 4110 | 4109 |
- "application/x-tar" |
| 4111 | 4110 |
- "application/octet-stream" |
| ... | ... |
@@ -4152,8 +4182,7 @@ paths: |
| 4152 | 4152 |
description: "The input stream must be a tar archive compressed with one of the following algorithms: identity (no compression), gzip, bzip2, xz." |
| 4153 | 4153 |
schema: |
| 4154 | 4154 |
type: "string" |
| 4155 |
- tags: |
|
| 4156 |
- - "Container" |
|
| 4155 |
+ tags: ["Container"] |
|
| 4157 | 4156 |
/containers/prune: |
| 4158 | 4157 |
post: |
| 4159 | 4158 |
summary: "Delete stopped containers" |
| ... | ... |
@@ -4181,13 +4210,12 @@ paths: |
| 4181 | 4181 |
description: "Server error" |
| 4182 | 4182 |
schema: |
| 4183 | 4183 |
$ref: "#/definitions/ErrorResponse" |
| 4184 |
- tags: |
|
| 4185 |
- - "Container" |
|
| 4184 |
+ tags: ["Container"] |
|
| 4186 | 4185 |
/images/json: |
| 4187 | 4186 |
get: |
| 4188 | 4187 |
summary: "List Images" |
| 4189 | 4188 |
description: "Returns a list of images on the server. Note that it uses a different, smaller representation of an image than inspecting a single image." |
| 4190 |
- operationId: "GetImageList" |
|
| 4189 |
+ operationId: "ImageList" |
|
| 4191 | 4190 |
produces: |
| 4192 | 4191 |
- "application/json" |
| 4193 | 4192 |
responses: |
| ... | ... |
@@ -4253,20 +4281,19 @@ paths: |
| 4253 | 4253 |
description: "Show digest information as a `RepoDigests` field on each image." |
| 4254 | 4254 |
type: "boolean" |
| 4255 | 4255 |
default: false |
| 4256 |
- tags: |
|
| 4257 |
- - "Image" |
|
| 4256 |
+ tags: ["Image"] |
|
| 4258 | 4257 |
/build: |
| 4259 | 4258 |
post: |
| 4260 | 4259 |
summary: "Build an image" |
| 4261 | 4260 |
description: | |
| 4262 | 4261 |
Build an image from a tar archive with a `Dockerfile` in it. |
| 4263 | 4262 |
|
| 4264 |
- The `Dockerfile` specifies how the image is built from the tar archive. It is typically in the archive's root, but can be at a different path or have a different name by specifying the `dockerfile` parameter. [See the `Dockerfile` reference for more information](/engine/reference/builder/). |
|
| 4263 |
+ The `Dockerfile` specifies how the image is built from the tar archive. It is typically in the archive's root, but can be at a different path or have a different name by specifying the `dockerfile` parameter. [See the `Dockerfile` reference for more information](https://docs.docker.com/engine/reference/builder/). |
|
| 4265 | 4264 |
|
| 4266 | 4265 |
The Docker daemon performs a preliminary validation of the `Dockerfile` before starting the build, and returns an error if the syntax is incorrect. After that, each instruction is run one-by-one until the ID of the new image is output. |
| 4267 | 4266 |
|
| 4268 | 4267 |
The build is canceled if the client drops the connection by quitting or being killed. |
| 4269 |
- operationId: "PostImageBuild" |
|
| 4268 |
+ operationId: "ImageBuild" |
|
| 4270 | 4269 |
consumes: |
| 4271 | 4270 |
- "application/octet-stream" |
| 4272 | 4271 |
produces: |
| ... | ... |
@@ -4345,7 +4372,7 @@ paths: |
| 4345 | 4345 |
type: "integer" |
| 4346 | 4346 |
- name: "buildargs" |
| 4347 | 4347 |
in: "query" |
| 4348 |
- description: "JSON map of string pairs for build-time variables. Users pass these values at build-time. Docker uses the buildargs as the environment context for commands run via the `Dockerfile` RUN instruction, or for variable expansion in other `Dockerfile` instructions. This is not meant for passing secret values. [Read more about the buildargs instruction.](/engine/reference/builder/#arg)" |
|
| 4348 |
+ description: "JSON map of string pairs for build-time variables. Users pass these values at build-time. Docker uses the buildargs as the environment context for commands run via the `Dockerfile` RUN instruction, or for variable expansion in other `Dockerfile` instructions. This is not meant for passing secret values. [Read more about the buildargs instruction.](https://docs.docker.com/engine/reference/builder/#arg)" |
|
| 4349 | 4349 |
type: "integer" |
| 4350 | 4350 |
- name: "shmsize" |
| 4351 | 4351 |
in: "query" |
| ... | ... |
@@ -4401,13 +4428,12 @@ paths: |
| 4401 | 4401 |
description: "server error" |
| 4402 | 4402 |
schema: |
| 4403 | 4403 |
$ref: "#/definitions/ErrorResponse" |
| 4404 |
- tags: |
|
| 4405 |
- - "Image" |
|
| 4404 |
+ tags: ["Image"] |
|
| 4406 | 4405 |
/images/create: |
| 4407 | 4406 |
post: |
| 4408 | 4407 |
summary: "Create an image" |
| 4409 | 4408 |
description: "Create an image by either pulling it from a registry or importing it." |
| 4410 |
- operationId: "PostImageCreate" |
|
| 4409 |
+ operationId: "ImageCreate" |
|
| 4411 | 4410 |
consumes: |
| 4412 | 4411 |
- "text/plain" |
| 4413 | 4412 |
- "application/octet-stream" |
| ... | ... |
@@ -4447,13 +4473,12 @@ paths: |
| 4447 | 4447 |
in: "header" |
| 4448 | 4448 |
description: "A base64-encoded auth configuration. [See the authentication section for details.](#section/Authentication)" |
| 4449 | 4449 |
type: "string" |
| 4450 |
- tags: |
|
| 4451 |
- - "Image" |
|
| 4450 |
+ tags: ["Image"] |
|
| 4452 | 4451 |
/images/{name}/json:
|
| 4453 | 4452 |
get: |
| 4454 | 4453 |
summary: "Inspect an image" |
| 4455 | 4454 |
description: "Return low-level information about an image." |
| 4456 |
- operationId: "GetImageInspect" |
|
| 4455 |
+ operationId: "ImageInspect" |
|
| 4457 | 4456 |
produces: |
| 4458 | 4457 |
- "application/json" |
| 4459 | 4458 |
responses: |
| ... | ... |
@@ -4554,13 +4579,12 @@ paths: |
| 4554 | 4554 |
description: "Image name or id" |
| 4555 | 4555 |
type: "string" |
| 4556 | 4556 |
required: true |
| 4557 |
- tags: |
|
| 4558 |
- - "Image" |
|
| 4557 |
+ tags: ["Image"] |
|
| 4559 | 4558 |
/images/{name}/history:
|
| 4560 | 4559 |
get: |
| 4561 | 4560 |
summary: "Get the history of an image" |
| 4562 | 4561 |
description: "Return parent layers of an image." |
| 4563 |
- operationId: "GetImageHistory" |
|
| 4562 |
+ operationId: "ImageHistory" |
|
| 4564 | 4563 |
produces: |
| 4565 | 4564 |
- "application/json" |
| 4566 | 4565 |
responses: |
| ... | ... |
@@ -4625,8 +4649,7 @@ paths: |
| 4625 | 4625 |
description: "Image name or ID" |
| 4626 | 4626 |
type: "string" |
| 4627 | 4627 |
required: true |
| 4628 |
- tags: |
|
| 4629 |
- - "Image" |
|
| 4628 |
+ tags: ["Image"] |
|
| 4630 | 4629 |
/images/{name}/push:
|
| 4631 | 4630 |
post: |
| 4632 | 4631 |
summary: "Push an image" |
| ... | ... |
@@ -4636,7 +4659,7 @@ paths: |
| 4636 | 4636 |
If you wish to push an image on to a private registry, that image must already have a tag which references the registry. For example, `registry.example.com/myimage:latest`. |
| 4637 | 4637 |
|
| 4638 | 4638 |
The push is cancelled if the HTTP connection is closed. |
| 4639 |
- operationId: "PostImagePush" |
|
| 4639 |
+ operationId: "ImagePush" |
|
| 4640 | 4640 |
consumes: |
| 4641 | 4641 |
- "application/octet-stream" |
| 4642 | 4642 |
responses: |
| ... | ... |
@@ -4665,13 +4688,12 @@ paths: |
| 4665 | 4665 |
description: "A base64-encoded auth configuration. [See the authentication section for details.](#section/Authentication)" |
| 4666 | 4666 |
type: "string" |
| 4667 | 4667 |
required: true |
| 4668 |
- tags: |
|
| 4669 |
- - "Image" |
|
| 4668 |
+ tags: ["Image"] |
|
| 4670 | 4669 |
/images/{name}/tag:
|
| 4671 | 4670 |
post: |
| 4672 | 4671 |
summary: "Tag an image" |
| 4673 | 4672 |
description: "Tag an image so that it becomes part of a repository." |
| 4674 |
- operationId: "PostImageTag" |
|
| 4673 |
+ operationId: "ImageTag" |
|
| 4675 | 4674 |
responses: |
| 4676 | 4675 |
201: |
| 4677 | 4676 |
description: "No error" |
| ... | ... |
@@ -4705,8 +4727,7 @@ paths: |
| 4705 | 4705 |
in: "query" |
| 4706 | 4706 |
description: "The name of the new tag." |
| 4707 | 4707 |
type: "string" |
| 4708 |
- tags: |
|
| 4709 |
- - "Image" |
|
| 4708 |
+ tags: ["Image"] |
|
| 4710 | 4709 |
/images/{name}:
|
| 4711 | 4710 |
delete: |
| 4712 | 4711 |
summary: "Remove an image" |
| ... | ... |
@@ -4714,7 +4735,7 @@ paths: |
| 4714 | 4714 |
Remove an image, along with any untagged parent images that were referenced by that image. |
| 4715 | 4715 |
|
| 4716 | 4716 |
Images can't be removed if they have descendant images, are being used by a running container or are being used by a build. |
| 4717 |
- operationId: "DeleteImage" |
|
| 4717 |
+ operationId: "ImageDelete" |
|
| 4718 | 4718 |
produces: |
| 4719 | 4719 |
- "application/json" |
| 4720 | 4720 |
responses: |
| ... | ... |
@@ -4757,13 +4778,12 @@ paths: |
| 4757 | 4757 |
description: "Do not delete untagged parent images" |
| 4758 | 4758 |
type: "boolean" |
| 4759 | 4759 |
default: false |
| 4760 |
- tags: |
|
| 4761 |
- - "Image" |
|
| 4760 |
+ tags: ["Image"] |
|
| 4762 | 4761 |
/images/search: |
| 4763 | 4762 |
get: |
| 4764 | 4763 |
summary: "Search images" |
| 4765 | 4764 |
description: "Search for an image on Docker Hub." |
| 4766 |
- operationId: "GetImageSearch" |
|
| 4765 |
+ operationId: "ImageSearch" |
|
| 4767 | 4766 |
produces: |
| 4768 | 4767 |
- "application/json" |
| 4769 | 4768 |
responses: |
| ... | ... |
@@ -4824,8 +4844,7 @@ paths: |
| 4824 | 4824 |
- `is-automated=(true|false)` |
| 4825 | 4825 |
- `is-official=(true|false)` |
| 4826 | 4826 |
type: "string" |
| 4827 |
- tags: |
|
| 4828 |
- - "Image" |
|
| 4827 |
+ tags: ["Image"] |
|
| 4829 | 4828 |
/images/prune: |
| 4830 | 4829 |
post: |
| 4831 | 4830 |
summary: "Delete unused images" |
| ... | ... |
@@ -4863,13 +4882,12 @@ paths: |
| 4863 | 4863 |
description: "Server error" |
| 4864 | 4864 |
schema: |
| 4865 | 4865 |
$ref: "#/definitions/ErrorResponse" |
| 4866 |
- tags: |
|
| 4867 |
- - "Image" |
|
| 4866 |
+ tags: ["Image"] |
|
| 4868 | 4867 |
/auth: |
| 4869 | 4868 |
post: |
| 4870 | 4869 |
summary: "Check auth configuration" |
| 4871 | 4870 |
description: "Validate credentials for a registry and, if available, get an identity token for accessing the registry without password." |
| 4872 |
- operationId: "Authenticate" |
|
| 4871 |
+ operationId: "SystemAuth" |
|
| 4873 | 4872 |
consumes: ["application/json"] |
| 4874 | 4873 |
produces: ["application/json"] |
| 4875 | 4874 |
responses: |
| ... | ... |
@@ -4903,11 +4921,11 @@ paths: |
| 4903 | 4903 |
description: "Authentication to check" |
| 4904 | 4904 |
schema: |
| 4905 | 4905 |
$ref: "#/definitions/AuthConfig" |
| 4906 |
- tags: ["Registry"] |
|
| 4906 |
+ tags: ["System"] |
|
| 4907 | 4907 |
/info: |
| 4908 | 4908 |
get: |
| 4909 | 4909 |
summary: "Get system information" |
| 4910 |
- operationId: "getSystemInformation" |
|
| 4910 |
+ operationId: "SystemInfo" |
|
| 4911 | 4911 |
produces: |
| 4912 | 4912 |
- "application/json" |
| 4913 | 4913 |
responses: |
| ... | ... |
@@ -5115,13 +5133,12 @@ paths: |
| 5115 | 5115 |
description: "Server error" |
| 5116 | 5116 |
schema: |
| 5117 | 5117 |
$ref: "#/definitions/ErrorResponse" |
| 5118 |
- tags: |
|
| 5119 |
- - "Misc" |
|
| 5118 |
+ tags: ["System"] |
|
| 5120 | 5119 |
/version: |
| 5121 | 5120 |
get: |
| 5122 | 5121 |
summary: "Get version" |
| 5123 | 5122 |
description: "Returns the version of Docker that is running and various information about the system that Docker is running on." |
| 5124 |
- operationId: "getVersion" |
|
| 5123 |
+ operationId: "SystemVersion" |
|
| 5125 | 5124 |
produces: |
| 5126 | 5125 |
- "application/json" |
| 5127 | 5126 |
responses: |
| ... | ... |
@@ -5166,13 +5183,12 @@ paths: |
| 5166 | 5166 |
description: "server error" |
| 5167 | 5167 |
schema: |
| 5168 | 5168 |
$ref: "#/definitions/ErrorResponse" |
| 5169 |
- tags: |
|
| 5170 |
- - "Misc" |
|
| 5169 |
+ tags: ["System"] |
|
| 5171 | 5170 |
/_ping: |
| 5172 | 5171 |
get: |
| 5173 | 5172 |
summary: "Ping" |
| 5174 | 5173 |
description: "This is a dummy endpoint you can use to test if the server is accessible." |
| 5175 |
- operationId: "ping" |
|
| 5174 |
+ operationId: "SystemPing" |
|
| 5176 | 5175 |
produces: |
| 5177 | 5176 |
- "text/plain" |
| 5178 | 5177 |
responses: |
| ... | ... |
@@ -5185,12 +5201,11 @@ paths: |
| 5185 | 5185 |
description: "server error" |
| 5186 | 5186 |
schema: |
| 5187 | 5187 |
$ref: "#/definitions/ErrorResponse" |
| 5188 |
- tags: |
|
| 5189 |
- - "Misc" |
|
| 5188 |
+ tags: ["System"] |
|
| 5190 | 5189 |
/commit: |
| 5191 | 5190 |
post: |
| 5192 | 5191 |
summary: "Create a new image from a container" |
| 5193 |
- operationId: "PostImageCommit" |
|
| 5192 |
+ operationId: "ImageCommit" |
|
| 5194 | 5193 |
consumes: |
| 5195 | 5194 |
- "application/json" |
| 5196 | 5195 |
produces: |
| ... | ... |
@@ -5246,8 +5261,7 @@ paths: |
| 5246 | 5246 |
in: "query" |
| 5247 | 5247 |
description: "`Dockerfile` instructions to apply while committing" |
| 5248 | 5248 |
type: "string" |
| 5249 |
- tags: |
|
| 5250 |
- - "Image" |
|
| 5249 |
+ tags: ["Image"] |
|
| 5251 | 5250 |
/events: |
| 5252 | 5251 |
get: |
| 5253 | 5252 |
summary: "Monitor events" |
| ... | ... |
@@ -5266,7 +5280,7 @@ paths: |
| 5266 | 5266 |
|
| 5267 | 5267 |
The Docker daemon reports these events: `reload` |
| 5268 | 5268 |
|
| 5269 |
- operationId: "getEvents" |
|
| 5269 |
+ operationId: "SystemEvents" |
|
| 5270 | 5270 |
produces: |
| 5271 | 5271 |
- "application/json" |
| 5272 | 5272 |
responses: |
| ... | ... |
@@ -5337,11 +5351,11 @@ paths: |
| 5337 | 5337 |
- `network=<string>` network name or ID |
| 5338 | 5338 |
- `daemon=<string>` daemon name or ID |
| 5339 | 5339 |
type: "string" |
| 5340 |
- tags: |
|
| 5341 |
- - "Misc" |
|
| 5340 |
+ tags: ["System"] |
|
| 5342 | 5341 |
/system/df: |
| 5343 | 5342 |
get: |
| 5344 | 5343 |
summary: "Get data usage information" |
| 5344 |
+ operationId: "SystemDataUsage" |
|
| 5345 | 5345 |
responses: |
| 5346 | 5346 |
200: |
| 5347 | 5347 |
description: "no error" |
| ... | ... |
@@ -5426,8 +5440,7 @@ paths: |
| 5426 | 5426 |
description: "server error" |
| 5427 | 5427 |
schema: |
| 5428 | 5428 |
$ref: "#/definitions/ErrorResponse" |
| 5429 |
- tags: |
|
| 5430 |
- - "Misc" |
|
| 5429 |
+ tags: ["System"] |
|
| 5431 | 5430 |
/images/{name}/get:
|
| 5432 | 5431 |
get: |
| 5433 | 5432 |
summary: "Export an image" |
| ... | ... |
@@ -5455,7 +5468,7 @@ paths: |
| 5455 | 5455 |
} |
| 5456 | 5456 |
} |
| 5457 | 5457 |
``` |
| 5458 |
- operationId: "GetImage" |
|
| 5458 |
+ operationId: "ImageGet" |
|
| 5459 | 5459 |
produces: |
| 5460 | 5460 |
- "application/x-tar" |
| 5461 | 5461 |
responses: |
| ... | ... |
@@ -5474,8 +5487,7 @@ paths: |
| 5474 | 5474 |
description: "Image name or ID" |
| 5475 | 5475 |
type: "string" |
| 5476 | 5476 |
required: true |
| 5477 |
- tags: |
|
| 5478 |
- - "Image" |
|
| 5477 |
+ tags: ["Image"] |
|
| 5479 | 5478 |
/images/get: |
| 5480 | 5479 |
get: |
| 5481 | 5480 |
summary: "Export several images" |
| ... | ... |
@@ -5484,8 +5496,8 @@ paths: |
| 5484 | 5484 |
|
| 5485 | 5485 |
For each value of the `names` parameter: if it is a specific name and tag (e.g. `ubuntu:latest`), then only that image (and its parents) are returned; if it is an image ID, similarly only that image (and its parents) are returned and there would be no names referenced in the 'repositories' file for this image ID. |
| 5486 | 5486 |
|
| 5487 |
- For details on the format, see [the export image endpoint](#operation/GetImage). |
|
| 5488 |
- operationId: "GetImageSaveAll" |
|
| 5487 |
+ For details on the format, see [the export image endpoint](#operation/ImageGet). |
|
| 5488 |
+ operationId: "ImageGetAll" |
|
| 5489 | 5489 |
produces: |
| 5490 | 5490 |
- "application/x-tar" |
| 5491 | 5491 |
responses: |
| ... | ... |
@@ -5505,16 +5517,15 @@ paths: |
| 5505 | 5505 |
type: "array" |
| 5506 | 5506 |
items: |
| 5507 | 5507 |
type: "string" |
| 5508 |
- tags: |
|
| 5509 |
- - "Image" |
|
| 5508 |
+ tags: ["Image"] |
|
| 5510 | 5509 |
/images/load: |
| 5511 | 5510 |
post: |
| 5512 | 5511 |
summary: "Import images" |
| 5513 | 5512 |
description: | |
| 5514 | 5513 |
Load a set of images and tags into a repository. |
| 5515 | 5514 |
|
| 5516 |
- For details on the format, see [the export image endpoint](#operation/GetImage). |
|
| 5517 |
- operationId: "PostImageLoad" |
|
| 5515 |
+ For details on the format, see [the export image endpoint](#operation/ImageGet). |
|
| 5516 |
+ operationId: "ImageLoad" |
|
| 5518 | 5517 |
consumes: |
| 5519 | 5518 |
- "application/x-tar" |
| 5520 | 5519 |
produces: |
| ... | ... |
@@ -5538,13 +5549,12 @@ paths: |
| 5538 | 5538 |
description: "Suppress progress details during load." |
| 5539 | 5539 |
type: "boolean" |
| 5540 | 5540 |
default: false |
| 5541 |
- tags: |
|
| 5542 |
- - "Image" |
|
| 5541 |
+ tags: ["Image"] |
|
| 5543 | 5542 |
/containers/{id}/exec:
|
| 5544 | 5543 |
post: |
| 5545 | 5544 |
summary: "Create an exec instance" |
| 5546 | 5545 |
description: "Run a command inside a running container." |
| 5547 |
- operationId: "PostContainerExec" |
|
| 5546 |
+ operationId: "ContainerExec" |
|
| 5548 | 5547 |
consumes: |
| 5549 | 5548 |
- "application/json" |
| 5550 | 5549 |
produces: |
| ... | ... |
@@ -5625,13 +5635,12 @@ paths: |
| 5625 | 5625 |
description: "ID or name of container" |
| 5626 | 5626 |
type: "string" |
| 5627 | 5627 |
required: true |
| 5628 |
- tags: |
|
| 5629 |
- - "Exec" |
|
| 5628 |
+ tags: ["Exec"] |
|
| 5630 | 5629 |
/exec/{id}/start:
|
| 5631 | 5630 |
post: |
| 5632 | 5631 |
summary: "Start an exec instance" |
| 5633 | 5632 |
description: "Starts a previously set up exec instance. If detach is true, this endpoint returns immediately after starting the command. Otherwise, it sets up an interactive session with the command." |
| 5634 |
- operationId: "PostExecStart" |
|
| 5633 |
+ operationId: "ExecStart" |
|
| 5635 | 5634 |
consumes: |
| 5636 | 5635 |
- "application/json" |
| 5637 | 5636 |
produces: |
| ... | ... |
@@ -5667,13 +5676,12 @@ paths: |
| 5667 | 5667 |
description: "Exec instance ID" |
| 5668 | 5668 |
required: true |
| 5669 | 5669 |
type: "string" |
| 5670 |
- tags: |
|
| 5671 |
- - "Exec" |
|
| 5670 |
+ tags: ["Exec"] |
|
| 5672 | 5671 |
/exec/{id}/resize:
|
| 5673 | 5672 |
post: |
| 5674 | 5673 |
summary: "Resize an exec instance" |
| 5675 | 5674 |
description: "Resize the TTY session used by an exec instance. This endpoint only works if `tty` was specified as part of creating and starting the exec instance." |
| 5676 |
- operationId: "PostExecResize" |
|
| 5675 |
+ operationId: "ExecResize" |
|
| 5677 | 5676 |
responses: |
| 5678 | 5677 |
201: |
| 5679 | 5678 |
description: "No error" |
| ... | ... |
@@ -5695,13 +5703,12 @@ paths: |
| 5695 | 5695 |
in: "query" |
| 5696 | 5696 |
description: "Width of the TTY session in characters" |
| 5697 | 5697 |
type: "integer" |
| 5698 |
- tags: |
|
| 5699 |
- - "Exec" |
|
| 5698 |
+ tags: ["Exec"] |
|
| 5700 | 5699 |
/exec/{id}/json:
|
| 5701 | 5700 |
get: |
| 5702 | 5701 |
summary: "Inspect an exec instance" |
| 5703 | 5702 |
description: "Return low-level information about an exec instance." |
| 5704 |
- operationId: "PostExecInspect" |
|
| 5703 |
+ operationId: "ExecInspect" |
|
| 5705 | 5704 |
produces: |
| 5706 | 5705 |
- "application/json" |
| 5707 | 5706 |
responses: |
| ... | ... |
@@ -5763,13 +5770,12 @@ paths: |
| 5763 | 5763 |
description: "Exec instance ID" |
| 5764 | 5764 |
required: true |
| 5765 | 5765 |
type: "string" |
| 5766 |
- tags: |
|
| 5767 |
- - "Exec" |
|
| 5766 |
+ tags: ["Exec"] |
|
| 5768 | 5767 |
|
| 5769 | 5768 |
/volumes: |
| 5770 | 5769 |
get: |
| 5771 | 5770 |
summary: "List volumes" |
| 5772 |
- operationId: "VolumesList" |
|
| 5771 |
+ operationId: "VolumeList" |
|
| 5773 | 5772 |
produces: ["application/json"] |
| 5774 | 5773 |
responses: |
| 5775 | 5774 |
200: |
| ... | ... |
@@ -5831,7 +5837,7 @@ paths: |
| 5831 | 5831 |
/volumes/create: |
| 5832 | 5832 |
post: |
| 5833 | 5833 |
summary: "Create a volume" |
| 5834 |
- operationId: "VolumesCreate" |
|
| 5834 |
+ operationId: "VolumeCreate" |
|
| 5835 | 5835 |
consumes: ["application/json"] |
| 5836 | 5836 |
produces: ["application/json"] |
| 5837 | 5837 |
responses: |
| ... | ... |
@@ -5881,7 +5887,7 @@ paths: |
| 5881 | 5881 |
/volumes/{name}:
|
| 5882 | 5882 |
get: |
| 5883 | 5883 |
summary: "Inspect a volume" |
| 5884 |
- operationId: "VolumesInspect" |
|
| 5884 |
+ operationId: "VolumeInspect" |
|
| 5885 | 5885 |
produces: ["application/json"] |
| 5886 | 5886 |
responses: |
| 5887 | 5887 |
200: |
| ... | ... |
@@ -5907,7 +5913,7 @@ paths: |
| 5907 | 5907 |
delete: |
| 5908 | 5908 |
summary: "Remove a volume" |
| 5909 | 5909 |
description: "Instruct the driver to remove the volume." |
| 5910 |
- operationId: "VolumesDelete" |
|
| 5910 |
+ operationId: "VolumeDelete" |
|
| 5911 | 5911 |
responses: |
| 5912 | 5912 |
204: |
| 5913 | 5913 |
description: "The volume was removed" |
| ... | ... |
@@ -5962,12 +5968,11 @@ paths: |
| 5962 | 5962 |
description: "Server error" |
| 5963 | 5963 |
schema: |
| 5964 | 5964 |
$ref: "#/definitions/ErrorResponse" |
| 5965 |
- tags: |
|
| 5966 |
- - "Volume" |
|
| 5965 |
+ tags: ["Volume"] |
|
| 5967 | 5966 |
/networks: |
| 5968 | 5967 |
get: |
| 5969 | 5968 |
summary: "List networks" |
| 5970 |
- operationId: "NetworksList" |
|
| 5969 |
+ operationId: "NetworkList" |
|
| 5971 | 5970 |
produces: |
| 5972 | 5971 |
- "application/json" |
| 5973 | 5972 |
responses: |
| ... | ... |
@@ -6049,7 +6054,7 @@ paths: |
| 6049 | 6049 |
/networks/{id}:
|
| 6050 | 6050 |
get: |
| 6051 | 6051 |
summary: "Inspect a network" |
| 6052 |
- operationId: "NetworksInspect" |
|
| 6052 |
+ operationId: "NetworkInspect" |
|
| 6053 | 6053 |
produces: |
| 6054 | 6054 |
- "application/json" |
| 6055 | 6055 |
responses: |
| ... | ... |
@@ -6071,7 +6076,7 @@ paths: |
| 6071 | 6071 |
|
| 6072 | 6072 |
delete: |
| 6073 | 6073 |
summary: "Remove a network" |
| 6074 |
- operationId: "DeleteNetworks" |
|
| 6074 |
+ operationId: "NetworkDelete" |
|
| 6075 | 6075 |
responses: |
| 6076 | 6076 |
204: |
| 6077 | 6077 |
description: "No error" |
| ... | ... |
@@ -6094,7 +6099,7 @@ paths: |
| 6094 | 6094 |
/networks/create: |
| 6095 | 6095 |
post: |
| 6096 | 6096 |
summary: "Create a network" |
| 6097 |
- operationId: "NetworksCreate" |
|
| 6097 |
+ operationId: "NetworkCreate" |
|
| 6098 | 6098 |
consumes: |
| 6099 | 6099 |
- "application/json" |
| 6100 | 6100 |
produces: |
| ... | ... |
@@ -6190,7 +6195,7 @@ paths: |
| 6190 | 6190 |
/networks/{id}/connect:
|
| 6191 | 6191 |
post: |
| 6192 | 6192 |
summary: "Connect a container to a network" |
| 6193 |
- operationId: "NetworksConnect" |
|
| 6193 |
+ operationId: "NetworkConnect" |
|
| 6194 | 6194 |
consumes: |
| 6195 | 6195 |
- "application/octet-stream" |
| 6196 | 6196 |
responses: |
| ... | ... |
@@ -6236,7 +6241,7 @@ paths: |
| 6236 | 6236 |
/networks/{id}/disconnect:
|
| 6237 | 6237 |
post: |
| 6238 | 6238 |
summary: "Disconnect a container from a network" |
| 6239 |
- operationId: "NetworksDisconnect" |
|
| 6239 |
+ operationId: "NetworkDisconnect" |
|
| 6240 | 6240 |
consumes: |
| 6241 | 6241 |
- "application/json" |
| 6242 | 6242 |
responses: |
| ... | ... |
@@ -6296,12 +6301,11 @@ paths: |
| 6296 | 6296 |
description: "Server error" |
| 6297 | 6297 |
schema: |
| 6298 | 6298 |
$ref: "#/definitions/ErrorResponse" |
| 6299 |
- tags: |
|
| 6300 |
- - "Network" |
|
| 6299 |
+ tags: ["Network"] |
|
| 6301 | 6300 |
/plugins: |
| 6302 | 6301 |
get: |
| 6303 | 6302 |
summary: "List plugins" |
| 6304 |
- operationId: "PluginsList" |
|
| 6303 |
+ operationId: "PluginList" |
|
| 6305 | 6304 |
description: "Returns information about installed plugins." |
| 6306 | 6305 |
produces: ["application/json"] |
| 6307 | 6306 |
responses: |
| ... | ... |
@@ -6390,14 +6394,14 @@ paths: |
| 6390 | 6390 |
description: "Server error" |
| 6391 | 6391 |
schema: |
| 6392 | 6392 |
$ref: "#/definitions/ErrorResponse" |
| 6393 |
- tags: ["Plugins"] |
|
| 6393 |
+ tags: ["Plugin"] |
|
| 6394 | 6394 |
|
| 6395 | 6395 |
/plugins/pull: |
| 6396 | 6396 |
post: |
| 6397 | 6397 |
summary: "Install a plugin" |
| 6398 |
- operationId: "PostPluginsPull" |
|
| 6398 |
+ operationId: "PluginPull" |
|
| 6399 | 6399 |
description: | |
| 6400 |
- Pulls and installs a plugin. After the plugin is installed, it can be enabled using the [`POST /plugins/{name}/enable` endpoint](#operation/PostPluginsEnable).
|
|
| 6400 |
+ Pulls and installs a plugin. After the plugin is installed, it can be enabled using the [`POST /plugins/{name}/enable` endpoint](#operation/PluginEnable).
|
|
| 6401 | 6401 |
produces: |
| 6402 | 6402 |
- "application/json" |
| 6403 | 6403 |
responses: |
| ... | ... |
@@ -6447,12 +6451,11 @@ paths: |
| 6447 | 6447 |
in: "header" |
| 6448 | 6448 |
description: "A base64-encoded auth configuration to use when pulling a plugin from a registry. [See the authentication section for details.](#section/Authentication)" |
| 6449 | 6449 |
type: "string" |
| 6450 |
- tags: |
|
| 6451 |
- - "Plugins" |
|
| 6450 |
+ tags: ["Plugin"] |
|
| 6452 | 6451 |
/plugins/{name}:
|
| 6453 | 6452 |
get: |
| 6454 | 6453 |
summary: "Inspect a plugin" |
| 6455 |
- operationId: "GetPluginsInspect" |
|
| 6454 |
+ operationId: "PluginInspect" |
|
| 6456 | 6455 |
responses: |
| 6457 | 6456 |
200: |
| 6458 | 6457 |
description: "no error" |
| ... | ... |
@@ -6472,11 +6475,10 @@ paths: |
| 6472 | 6472 |
description: "The name of the plugin. The `:latest` tag is optional, and is the default if omitted." |
| 6473 | 6473 |
required: true |
| 6474 | 6474 |
type: "string" |
| 6475 |
- tags: |
|
| 6476 |
- - "Plugins" |
|
| 6475 |
+ tags: ["Plugin"] |
|
| 6477 | 6476 |
delete: |
| 6478 | 6477 |
summary: "Remove a plugin" |
| 6479 |
- operationId: "DeletePlugins" |
|
| 6478 |
+ operationId: "PluginDelete" |
|
| 6480 | 6479 |
responses: |
| 6481 | 6480 |
200: |
| 6482 | 6481 |
description: "no error" |
| ... | ... |
@@ -6501,12 +6503,11 @@ paths: |
| 6501 | 6501 |
description: "Disable the plugin before removing. This may result in issues if the plugin is in use by a container." |
| 6502 | 6502 |
type: "boolean" |
| 6503 | 6503 |
default: false |
| 6504 |
- tags: |
|
| 6505 |
- - "Plugins" |
|
| 6504 |
+ tags: ["Plugin"] |
|
| 6506 | 6505 |
/plugins/{name}/enable:
|
| 6507 | 6506 |
post: |
| 6508 | 6507 |
summary: "Enable a plugin" |
| 6509 |
- operationId: "PostPluginsEnable" |
|
| 6508 |
+ operationId: "PluginEnable" |
|
| 6510 | 6509 |
responses: |
| 6511 | 6510 |
200: |
| 6512 | 6511 |
description: "no error" |
| ... | ... |
@@ -6525,12 +6526,11 @@ paths: |
| 6525 | 6525 |
description: "Set the HTTP client timeout (in seconds)" |
| 6526 | 6526 |
type: "integer" |
| 6527 | 6527 |
default: 0 |
| 6528 |
- tags: |
|
| 6529 |
- - "Plugins" |
|
| 6528 |
+ tags: ["Plugin"] |
|
| 6530 | 6529 |
/plugins/{name}/disable:
|
| 6531 | 6530 |
post: |
| 6532 | 6531 |
summary: "Disable a plugin" |
| 6533 |
- operationId: "PostPluginsDisable" |
|
| 6532 |
+ operationId: "PluginDisable" |
|
| 6534 | 6533 |
responses: |
| 6535 | 6534 |
200: |
| 6536 | 6535 |
description: "no error" |
| ... | ... |
@@ -6544,12 +6544,11 @@ paths: |
| 6544 | 6544 |
description: "The name of the plugin. The `:latest` tag is optional, and is the default if omitted." |
| 6545 | 6545 |
required: true |
| 6546 | 6546 |
type: "string" |
| 6547 |
- tags: |
|
| 6548 |
- - "Plugins" |
|
| 6547 |
+ tags: ["Plugin"] |
|
| 6549 | 6548 |
/plugins/create: |
| 6550 | 6549 |
post: |
| 6551 | 6550 |
summary: "Create a plugin" |
| 6552 |
- operationId: "PostPluginsCreate" |
|
| 6551 |
+ operationId: "PluginCreate" |
|
| 6553 | 6552 |
consumes: |
| 6554 | 6553 |
- "application/x-tar" |
| 6555 | 6554 |
responses: |
| ... | ... |
@@ -6571,8 +6570,7 @@ paths: |
| 6571 | 6571 |
schema: |
| 6572 | 6572 |
type: "string" |
| 6573 | 6573 |
format: "binary" |
| 6574 |
- tags: |
|
| 6575 |
- - "Plugins" |
|
| 6574 |
+ tags: ["Plugin"] |
|
| 6576 | 6575 |
/plugins/{name}/push:
|
| 6577 | 6576 |
post: |
| 6578 | 6577 |
summary: "Push a plugin" |
| ... | ... |
@@ -6596,12 +6594,11 @@ paths: |
| 6596 | 6596 |
description: "server error" |
| 6597 | 6597 |
schema: |
| 6598 | 6598 |
$ref: "#/definitions/ErrorResponse" |
| 6599 |
- tags: |
|
| 6600 |
- - "Plugins" |
|
| 6599 |
+ tags: ["Plugin"] |
|
| 6601 | 6600 |
/plugins/{name}/set:
|
| 6602 | 6601 |
post: |
| 6603 | 6602 |
summary: "Configure a plugin" |
| 6604 |
- operationId: "PostPluginsSet" |
|
| 6603 |
+ operationId: "PluginSet" |
|
| 6605 | 6604 |
consumes: |
| 6606 | 6605 |
- "application/json" |
| 6607 | 6606 |
parameters: |
| ... | ... |
@@ -6628,12 +6625,11 @@ paths: |
| 6628 | 6628 |
description: "Server error" |
| 6629 | 6629 |
schema: |
| 6630 | 6630 |
$ref: "#/definitions/ErrorResponse" |
| 6631 |
- tags: |
|
| 6632 |
- - "Plugins" |
|
| 6631 |
+ tags: ["Plugin"] |
|
| 6633 | 6632 |
/nodes: |
| 6634 | 6633 |
get: |
| 6635 | 6634 |
summary: "List nodes" |
| 6636 |
- operationId: "GetNodesList" |
|
| 6635 |
+ operationId: "NodeList" |
|
| 6637 | 6636 |
responses: |
| 6638 | 6637 |
200: |
| 6639 | 6638 |
description: "no error" |
| ... | ... |
@@ -6658,12 +6654,11 @@ paths: |
| 6658 | 6658 |
- `name=<node name>` |
| 6659 | 6659 |
- `role=`(`manager`|`worker`)` |
| 6660 | 6660 |
type: "string" |
| 6661 |
- tags: |
|
| 6662 |
- - "Nodes" |
|
| 6661 |
+ tags: ["Node"] |
|
| 6663 | 6662 |
/nodes/{id}:
|
| 6664 | 6663 |
get: |
| 6665 | 6664 |
summary: "Inspect a node" |
| 6666 |
- operationId: "GetNodesInspect" |
|
| 6665 |
+ operationId: "NodeInspect" |
|
| 6667 | 6666 |
responses: |
| 6668 | 6667 |
200: |
| 6669 | 6668 |
description: "no error" |
| ... | ... |
@@ -6683,11 +6678,10 @@ paths: |
| 6683 | 6683 |
description: "The ID or name of the node" |
| 6684 | 6684 |
type: "string" |
| 6685 | 6685 |
required: true |
| 6686 |
- tags: |
|
| 6687 |
- - "Nodes" |
|
| 6686 |
+ tags: ["Node"] |
|
| 6688 | 6687 |
delete: |
| 6689 | 6688 |
summary: "Delete a node" |
| 6690 |
- operationId: "DeleteNodes" |
|
| 6689 |
+ operationId: "NodeDelete" |
|
| 6691 | 6690 |
responses: |
| 6692 | 6691 |
200: |
| 6693 | 6692 |
description: "no error" |
| ... | ... |
@@ -6710,12 +6704,11 @@ paths: |
| 6710 | 6710 |
description: "Force remove a node from the swarm" |
| 6711 | 6711 |
default: false |
| 6712 | 6712 |
type: "boolean" |
| 6713 |
- tags: |
|
| 6714 |
- - "Nodes" |
|
| 6713 |
+ tags: ["Node"] |
|
| 6715 | 6714 |
/nodes/{id}/update:
|
| 6716 | 6715 |
post: |
| 6717 | 6716 |
summary: "Update a node" |
| 6718 |
- operationId: "PostNodesUpdate" |
|
| 6717 |
+ operationId: "NodeUpdate" |
|
| 6719 | 6718 |
responses: |
| 6720 | 6719 |
200: |
| 6721 | 6720 |
description: "no error" |
| ... | ... |
@@ -6743,12 +6736,11 @@ paths: |
| 6743 | 6743 |
type: "integer" |
| 6744 | 6744 |
format: "int64" |
| 6745 | 6745 |
required: true |
| 6746 |
- tags: |
|
| 6747 |
- - "Nodes" |
|
| 6746 |
+ tags: ["Node"] |
|
| 6748 | 6747 |
/swarm: |
| 6749 | 6748 |
get: |
| 6750 | 6749 |
summary: "Inspect swarm" |
| 6751 |
- operationId: "GetSwarmInspect" |
|
| 6750 |
+ operationId: "SwarmInspect" |
|
| 6752 | 6751 |
responses: |
| 6753 | 6752 |
200: |
| 6754 | 6753 |
description: "no error" |
| ... | ... |
@@ -6796,12 +6788,11 @@ paths: |
| 6796 | 6796 |
description: "server error" |
| 6797 | 6797 |
schema: |
| 6798 | 6798 |
$ref: "#/definitions/ErrorResponse" |
| 6799 |
- tags: |
|
| 6800 |
- - "Swarm" |
|
| 6799 |
+ tags: ["Swarm"] |
|
| 6801 | 6800 |
/swarm/init: |
| 6802 | 6801 |
post: |
| 6803 | 6802 |
summary: "Initialize a new swarm" |
| 6804 |
- operationId: "PostSwarmInit" |
|
| 6803 |
+ operationId: "SwarmInit" |
|
| 6805 | 6804 |
produces: |
| 6806 | 6805 |
- "application/json" |
| 6807 | 6806 |
- "text/plain" |
| ... | ... |
@@ -6853,12 +6844,11 @@ paths: |
| 6853 | 6853 |
CAConfig: {}
|
| 6854 | 6854 |
EncryptionConfig: |
| 6855 | 6855 |
AutoLockManagers: false |
| 6856 |
- tags: |
|
| 6857 |
- - "Swarm" |
|
| 6856 |
+ tags: ["Swarm"] |
|
| 6858 | 6857 |
/swarm/join: |
| 6859 | 6858 |
post: |
| 6860 | 6859 |
summary: "Join an existing swarm" |
| 6861 |
- operationId: "PostSwarmJoin" |
|
| 6860 |
+ operationId: "SwarmJoin" |
|
| 6862 | 6861 |
responses: |
| 6863 | 6862 |
200: |
| 6864 | 6863 |
description: "no error" |
| ... | ... |
@@ -6899,12 +6889,11 @@ paths: |
| 6899 | 6899 |
RemoteAddrs: |
| 6900 | 6900 |
- "node1:2377" |
| 6901 | 6901 |
JoinToken: "SWMTKN-1-3pu6hszjas19xyp7ghgosyx9k8atbfcr8p2is99znpy26u2lkl-7p73s1dx5in4tatdymyhg9hu2" |
| 6902 |
- tags: |
|
| 6903 |
- - "Swarm" |
|
| 6902 |
+ tags: ["Swarm"] |
|
| 6904 | 6903 |
/swarm/leave: |
| 6905 | 6904 |
post: |
| 6906 | 6905 |
summary: "Leave a swarm" |
| 6907 |
- operationId: "PostSwarmLeave" |
|
| 6906 |
+ operationId: "SwarmLeave" |
|
| 6908 | 6907 |
responses: |
| 6909 | 6908 |
200: |
| 6910 | 6909 |
description: "no error" |
| ... | ... |
@@ -6922,12 +6911,11 @@ paths: |
| 6922 | 6922 |
in: "query" |
| 6923 | 6923 |
type: "boolean" |
| 6924 | 6924 |
default: false |
| 6925 |
- tags: |
|
| 6926 |
- - "Swarm" |
|
| 6925 |
+ tags: ["Swarm"] |
|
| 6927 | 6926 |
/swarm/update: |
| 6928 | 6927 |
post: |
| 6929 | 6928 |
summary: "Update a swarm" |
| 6930 |
- operationId: "PostSwarmUpdate" |
|
| 6929 |
+ operationId: "SwarmUpdate" |
|
| 6931 | 6930 |
responses: |
| 6932 | 6931 |
200: |
| 6933 | 6932 |
description: "no error" |
| ... | ... |
@@ -6970,8 +6958,7 @@ paths: |
| 6970 | 6970 |
description: "Rotate the manager unlock key." |
| 6971 | 6971 |
type: "boolean" |
| 6972 | 6972 |
default: false |
| 6973 |
- tags: |
|
| 6974 |
- - "Swarm" |
|
| 6973 |
+ tags: ["Swarm"] |
|
| 6975 | 6974 |
/swarm/unlockkey: |
| 6976 | 6975 |
get: |
| 6977 | 6976 |
summary: "Get the unlock key" |
| ... | ... |
@@ -6993,8 +6980,7 @@ paths: |
| 6993 | 6993 |
description: "server error" |
| 6994 | 6994 |
schema: |
| 6995 | 6995 |
$ref: "#/definitions/ErrorResponse" |
| 6996 |
- tags: |
|
| 6997 |
- - "Swarm" |
|
| 6996 |
+ tags: ["Swarm"] |
|
| 6998 | 6997 |
/swarm/unlock: |
| 6999 | 6998 |
post: |
| 7000 | 6999 |
summary: "Unlock a locked manager" |
| ... | ... |
@@ -7022,12 +7008,11 @@ paths: |
| 7022 | 7022 |
description: "server error" |
| 7023 | 7023 |
schema: |
| 7024 | 7024 |
$ref: "#/definitions/ErrorResponse" |
| 7025 |
- tags: |
|
| 7026 |
- - "Swarm" |
|
| 7025 |
+ tags: ["Swarm"] |
|
| 7027 | 7026 |
/services: |
| 7028 | 7027 |
get: |
| 7029 | 7028 |
summary: "List services" |
| 7030 |
- operationId: "GetServicesList" |
|
| 7029 |
+ operationId: "ServiceList" |
|
| 7031 | 7030 |
responses: |
| 7032 | 7031 |
200: |
| 7033 | 7032 |
description: "no error" |
| ... | ... |
@@ -7049,12 +7034,11 @@ paths: |
| 7049 | 7049 |
- `id=<service id>` |
| 7050 | 7050 |
- `name=<service name>` |
| 7051 | 7051 |
- `label=<service label>` |
| 7052 |
- tags: |
|
| 7053 |
- - "Services" |
|
| 7052 |
+ tags: ["Service"] |
|
| 7054 | 7053 |
/services/create: |
| 7055 | 7054 |
post: |
| 7056 | 7055 |
summary: "Create a service" |
| 7057 |
- operationId: "PostServicesCreate" |
|
| 7056 |
+ operationId: "ServiceCreate" |
|
| 7058 | 7057 |
consumes: |
| 7059 | 7058 |
- "application/json" |
| 7060 | 7059 |
produces: |
| ... | ... |
@@ -7147,12 +7131,11 @@ paths: |
| 7147 | 7147 |
in: "header" |
| 7148 | 7148 |
description: "A base64-encoded auth configuration for pulling from private registries. [See the authentication section for details.](#section/Authentication)" |
| 7149 | 7149 |
type: "string" |
| 7150 |
- tags: |
|
| 7151 |
- - "Services" |
|
| 7150 |
+ tags: ["Service"] |
|
| 7152 | 7151 |
/services/{id}:
|
| 7153 | 7152 |
get: |
| 7154 | 7153 |
summary: "Inspect a service" |
| 7155 |
- operationId: "GetServicesInspect" |
|
| 7154 |
+ operationId: "ServiceInspect" |
|
| 7156 | 7155 |
responses: |
| 7157 | 7156 |
200: |
| 7158 | 7157 |
description: "no error" |
| ... | ... |
@@ -7172,11 +7155,10 @@ paths: |
| 7172 | 7172 |
description: "ID or name of service." |
| 7173 | 7173 |
required: true |
| 7174 | 7174 |
type: "string" |
| 7175 |
- tags: |
|
| 7176 |
- - "Services" |
|
| 7175 |
+ tags: ["Service"] |
|
| 7177 | 7176 |
delete: |
| 7178 | 7177 |
summary: "Delete a service" |
| 7179 |
- operationId: "DeleteServices" |
|
| 7178 |
+ operationId: "ServiceDelete" |
|
| 7180 | 7179 |
responses: |
| 7181 | 7180 |
200: |
| 7182 | 7181 |
description: "no error" |
| ... | ... |
@@ -7194,8 +7176,7 @@ paths: |
| 7194 | 7194 |
description: "ID or name of service." |
| 7195 | 7195 |
required: true |
| 7196 | 7196 |
type: "string" |
| 7197 |
- tags: |
|
| 7198 |
- - "Services" |
|
| 7197 |
+ tags: ["Service"] |
|
| 7199 | 7198 |
/services/{id}/update:
|
| 7200 | 7199 |
post: |
| 7201 | 7200 |
summary: "Update a service" |
| ... | ... |
@@ -7270,7 +7251,7 @@ paths: |
| 7270 | 7270 |
description: "A base64-encoded auth configuration for pulling from private registries. [See the authentication section for details.](#section/Authentication)" |
| 7271 | 7271 |
type: "string" |
| 7272 | 7272 |
|
| 7273 |
- tags: ["Services"] |
|
| 7273 |
+ tags: ["Service"] |
|
| 7274 | 7274 |
/services/{id}/logs:
|
| 7275 | 7275 |
get: |
| 7276 | 7276 |
summary: "Get service logs" |
| ... | ... |
@@ -7319,7 +7300,7 @@ paths: |
| 7319 | 7319 |
description: | |
| 7320 | 7320 |
Return the logs as a stream. |
| 7321 | 7321 |
|
| 7322 |
- This will return a `101` HTTP response with a `Connection: upgrade` header, then hijack the HTTP connection to send raw output. For more information about hijacking and the stream format, [see the documentation for the attach endpoint](#operation/PostContainerAttach). |
|
| 7322 |
+ This will return a `101` HTTP response with a `Connection: upgrade` header, then hijack the HTTP connection to send raw output. For more information about hijacking and the stream format, [see the documentation for the attach endpoint](#operation/ContainerAttach). |
|
| 7323 | 7323 |
type: "boolean" |
| 7324 | 7324 |
default: false |
| 7325 | 7325 |
- name: "stdout" |
| ... | ... |
@@ -7347,12 +7328,11 @@ paths: |
| 7347 | 7347 |
description: "Only return this number of log lines from the end of the logs. Specify as an integer or `all` to output all log lines." |
| 7348 | 7348 |
type: "string" |
| 7349 | 7349 |
default: "all" |
| 7350 |
- tags: |
|
| 7351 |
- - "Services" |
|
| 7350 |
+ tags: ["Service"] |
|
| 7352 | 7351 |
/tasks: |
| 7353 | 7352 |
get: |
| 7354 | 7353 |
summary: "List tasks" |
| 7355 |
- operationId: "GetTasksList" |
|
| 7354 |
+ operationId: "TaskList" |
|
| 7356 | 7355 |
produces: |
| 7357 | 7356 |
- "application/json" |
| 7358 | 7357 |
responses: |
| ... | ... |
@@ -7491,12 +7471,11 @@ paths: |
| 7491 | 7491 |
- `node=<node id or name>` |
| 7492 | 7492 |
- `label=key` or `label="key=value"` |
| 7493 | 7493 |
- `desired-state=(running | shutdown | accepted)` |
| 7494 |
- tags: |
|
| 7495 |
- - "Tasks" |
|
| 7494 |
+ tags: ["Task"] |
|
| 7496 | 7495 |
/tasks/{id}:
|
| 7497 | 7496 |
get: |
| 7498 | 7497 |
summary: "Inspect a task" |
| 7499 |
- operationId: "GetTasksInspect" |
|
| 7498 |
+ operationId: "TaskInspect" |
|
| 7500 | 7499 |
produces: |
| 7501 | 7500 |
- "application/json" |
| 7502 | 7501 |
responses: |
| ... | ... |
@@ -7518,8 +7497,7 @@ paths: |
| 7518 | 7518 |
description: "ID of the task" |
| 7519 | 7519 |
required: true |
| 7520 | 7520 |
type: "string" |
| 7521 |
- tags: |
|
| 7522 |
- - "Tasks" |
|
| 7521 |
+ tags: ["Task"] |
|
| 7523 | 7522 |
/secrets: |
| 7524 | 7523 |
get: |
| 7525 | 7524 |
summary: "List secrets" |
| ... | ... |
@@ -7553,8 +7531,7 @@ paths: |
| 7553 | 7553 |
A JSON encoded value of the filters (a `map[string][]string`) to process on the secrets list. Available filters: |
| 7554 | 7554 |
|
| 7555 | 7555 |
- `names=<secret name>` |
| 7556 |
- tags: |
|
| 7557 |
- - "Secrets" |
|
| 7556 |
+ tags: ["Secret"] |
|
| 7558 | 7557 |
/secrets/create: |
| 7559 | 7558 |
post: |
| 7560 | 7559 |
summary: "Create a secret" |
| ... | ... |
@@ -7598,12 +7575,11 @@ paths: |
| 7598 | 7598 |
Labels: |
| 7599 | 7599 |
foo: "bar" |
| 7600 | 7600 |
Data: "VEhJUyBJUyBOT1QgQSBSRUFMIENFUlRJRklDQVRFCg==" |
| 7601 |
- tags: |
|
| 7602 |
- - "Secrets" |
|
| 7601 |
+ tags: ["Secret"] |
|
| 7603 | 7602 |
/secrets/{id}:
|
| 7604 | 7603 |
get: |
| 7605 | 7604 |
summary: "Inspect a secret" |
| 7606 |
- operationId: "SecretsInspect" |
|
| 7605 |
+ operationId: "SecretInspect" |
|
| 7607 | 7606 |
produces: |
| 7608 | 7607 |
- "application/json" |
| 7609 | 7608 |
responses: |
| ... | ... |
@@ -7637,11 +7613,10 @@ paths: |
| 7637 | 7637 |
required: true |
| 7638 | 7638 |
type: "string" |
| 7639 | 7639 |
description: "ID of the secret" |
| 7640 |
- tags: |
|
| 7641 |
- - "Secrets" |
|
| 7640 |
+ tags: ["Secret"] |
|
| 7642 | 7641 |
delete: |
| 7643 | 7642 |
summary: "Delete a secret" |
| 7644 |
- operationId: "SecretsDelete" |
|
| 7643 |
+ operationId: "SecretDelete" |
|
| 7645 | 7644 |
produces: |
| 7646 | 7645 |
- "application/json" |
| 7647 | 7646 |
responses: |
| ... | ... |
@@ -7661,5 +7636,4 @@ paths: |
| 7661 | 7661 |
required: true |
| 7662 | 7662 |
type: "string" |
| 7663 | 7663 |
description: "ID of the secret" |
| 7664 |
- tags: |
|
| 7665 |
- - "Secrets" |
|
| 7664 |
+ tags: ["Secret"] |
| ... | ... |
@@ -71,14 +71,20 @@ func env(b *Builder, args []string, attributes map[string]bool, original string) |
| 71 | 71 |
if len(args[j]) == 0 {
|
| 72 | 72 |
return errBlankCommandNames("ENV")
|
| 73 | 73 |
} |
| 74 |
- |
|
| 75 | 74 |
newVar := args[j] + "=" + args[j+1] + "" |
| 76 | 75 |
commitStr += " " + newVar |
| 77 | 76 |
|
| 78 | 77 |
gotOne := false |
| 79 | 78 |
for i, envVar := range b.runConfig.Env {
|
| 80 | 79 |
envParts := strings.SplitN(envVar, "=", 2) |
| 81 |
- if envParts[0] == args[j] {
|
|
| 80 |
+ compareFrom := envParts[0] |
|
| 81 |
+ compareTo := args[j] |
|
| 82 |
+ if runtime.GOOS == "windows" {
|
|
| 83 |
+ // Case insensitive environment variables on Windows |
|
| 84 |
+ compareFrom = strings.ToUpper(compareFrom) |
|
| 85 |
+ compareTo = strings.ToUpper(compareTo) |
|
| 86 |
+ } |
|
| 87 |
+ if compareFrom == compareTo {
|
|
| 82 | 88 |
b.runConfig.Env[i] = newVar |
| 83 | 89 |
gotOne = true |
| 84 | 90 |
break |
| ... | ... |
@@ -1,112 +1,116 @@ |
| 1 |
-hello | hello |
|
| 2 |
-he'll'o | hello |
|
| 3 |
-he'llo | hello |
|
| 4 |
-he\'llo | he'llo |
|
| 5 |
-he\\'llo | he\llo |
|
| 6 |
-abc\tdef | abctdef |
|
| 7 |
-"abc\tdef" | abc\tdef |
|
| 8 |
-'abc\tdef' | abc\tdef |
|
| 9 |
-hello\ | hello |
|
| 10 |
-hello\\ | hello\ |
|
| 11 |
-"hello | hello |
|
| 12 |
-"hello\" | hello" |
|
| 13 |
-"hel'lo" | hel'lo |
|
| 14 |
-'hello | hello |
|
| 15 |
-'hello\' | hello\ |
|
| 16 |
-"''" | '' |
|
| 17 |
-$. | $. |
|
| 18 |
-$1 | |
|
| 19 |
-he$1x | hex |
|
| 20 |
-he$.x | he$.x |
|
| 21 |
-he$pwd. | he. |
|
| 22 |
-he$PWD | he/home |
|
| 23 |
-he\$PWD | he$PWD |
|
| 24 |
-he\\$PWD | he\/home |
|
| 25 |
-he\${} | he${}
|
|
| 26 |
-he\${}xx | he${}xx
|
|
| 27 |
-he${} | he
|
|
| 28 |
-he${}xx | hexx
|
|
| 29 |
-he${hi} | he
|
|
| 30 |
-he${hi}xx | hexx
|
|
| 31 |
-he${PWD} | he/home
|
|
| 32 |
-he${.} | error
|
|
| 33 |
-he${XXX:-000}xx | he000xx
|
|
| 34 |
-he${PWD:-000}xx | he/homexx
|
|
| 35 |
-he${XXX:-$PWD}xx | he/homexx
|
|
| 36 |
-he${XXX:-${PWD:-yyy}}xx | he/homexx
|
|
| 37 |
-he${XXX:-${YYY:-yyy}}xx | heyyyxx
|
|
| 38 |
-he${XXX:YYY} | error
|
|
| 39 |
-he${XXX:+${PWD}}xx | hexx
|
|
| 40 |
-he${PWD:+${XXX}}xx | hexx
|
|
| 41 |
-he${PWD:+${SHELL}}xx | hebashxx
|
|
| 42 |
-he${XXX:+000}xx | hexx
|
|
| 43 |
-he${PWD:+000}xx | he000xx
|
|
| 44 |
-'he${XX}' | he${XX}
|
|
| 45 |
-"he${PWD}" | he/home
|
|
| 46 |
-"he'$PWD'" | he'/home' |
|
| 47 |
-"$PWD" | /home |
|
| 48 |
-'$PWD' | $PWD |
|
| 49 |
-'\$PWD' | \$PWD |
|
| 50 |
-'"hello"' | "hello" |
|
| 51 |
-he\$PWD | he$PWD |
|
| 52 |
-"he\$PWD" | he$PWD |
|
| 53 |
-'he\$PWD' | he\$PWD |
|
| 54 |
-he${PWD | error
|
|
| 55 |
-he${PWD:=000}xx | error
|
|
| 56 |
-he${PWD:+${PWD}:}xx | he/home:xx
|
|
| 57 |
-he${XXX:-\$PWD:}xx | he$PWD:xx
|
|
| 58 |
-he${XXX:-\${PWD}z}xx | he${PWDz}xx
|
|
| 59 |
-안녕하세요 | 안녕하세요 |
|
| 60 |
-안'녕'하세요 | 안녕하세요 |
|
| 61 |
-안'녕하세요 | 안녕하세요 |
|
| 62 |
-안녕\'하세요 | 안녕'하세요 |
|
| 63 |
-안\\'녕하세요 | 안\녕하세요 |
|
| 64 |
-안녕\t하세요 | 안녕t하세요 |
|
| 65 |
-"안녕\t하세요" | 안녕\t하세요 |
|
| 66 |
-'안녕\t하세요 | 안녕\t하세요 |
|
| 67 |
-안녕하세요\ | 안녕하세요 |
|
| 68 |
-안녕하세요\\ | 안녕하세요\ |
|
| 69 |
-"안녕하세요 | 안녕하세요 |
|
| 70 |
-"안녕하세요\" | 안녕하세요" |
|
| 71 |
-"안녕'하세요" | 안녕'하세요 |
|
| 72 |
-'안녕하세요 | 안녕하세요 |
|
| 73 |
-'안녕하세요\' | 안녕하세요\ |
|
| 74 |
-안녕$1x | 안녕x |
|
| 75 |
-안녕$.x | 안녕$.x |
|
| 76 |
-안녕$pwd. | 안녕. |
|
| 77 |
-안녕$PWD | 안녕/home |
|
| 78 |
-안녕\$PWD | 안녕$PWD |
|
| 79 |
-안녕\\$PWD | 안녕\/home |
|
| 80 |
-안녕\${} | 안녕${}
|
|
| 81 |
-안녕\${}xx | 안녕${}xx
|
|
| 82 |
-안녕${} | 안녕
|
|
| 83 |
-안녕${}xx | 안녕xx
|
|
| 84 |
-안녕${hi} | 안녕
|
|
| 85 |
-안녕${hi}xx | 안녕xx
|
|
| 86 |
-안녕${PWD} | 안녕/home
|
|
| 87 |
-안녕${.} | error
|
|
| 88 |
-안녕${XXX:-000}xx | 안녕000xx
|
|
| 89 |
-안녕${PWD:-000}xx | 안녕/homexx
|
|
| 90 |
-안녕${XXX:-$PWD}xx | 안녕/homexx
|
|
| 91 |
-안녕${XXX:-${PWD:-yyy}}xx | 안녕/homexx
|
|
| 92 |
-안녕${XXX:-${YYY:-yyy}}xx | 안녕yyyxx
|
|
| 93 |
-안녕${XXX:YYY} | error
|
|
| 94 |
-안녕${XXX:+${PWD}}xx | 안녕xx
|
|
| 95 |
-안녕${PWD:+${XXX}}xx | 안녕xx
|
|
| 96 |
-안녕${PWD:+${SHELL}}xx | 안녕bashxx
|
|
| 97 |
-안녕${XXX:+000}xx | 안녕xx
|
|
| 98 |
-안녕${PWD:+000}xx | 안녕000xx
|
|
| 99 |
-'안녕${XX}' | 안녕${XX}
|
|
| 100 |
-"안녕${PWD}" | 안녕/home
|
|
| 101 |
-"안녕'$PWD'" | 안녕'/home' |
|
| 102 |
-'"안녕"' | "안녕" |
|
| 103 |
-안녕\$PWD | 안녕$PWD |
|
| 104 |
-"안녕\$PWD" | 안녕$PWD |
|
| 105 |
-'안녕\$PWD' | 안녕\$PWD |
|
| 106 |
-안녕${PWD | error
|
|
| 107 |
-안녕${PWD:=000}xx | error
|
|
| 108 |
-안녕${PWD:+${PWD}:}xx | 안녕/home:xx
|
|
| 109 |
-안녕${XXX:-\$PWD:}xx | 안녕$PWD:xx
|
|
| 110 |
-안녕${XXX:-\${PWD}z}xx | 안녕${PWDz}xx
|
|
| 111 |
-$KOREAN | 한êµì–´ |
|
| 112 |
-안녕$KOREAN | 안녕한êµì–´ |
|
| 1 |
+A|hello | hello |
|
| 2 |
+A|he'll'o | hello |
|
| 3 |
+A|he'llo | hello |
|
| 4 |
+A|he\'llo | he'llo |
|
| 5 |
+A|he\\'llo | he\llo |
|
| 6 |
+A|abc\tdef | abctdef |
|
| 7 |
+A|"abc\tdef" | abc\tdef |
|
| 8 |
+A|'abc\tdef' | abc\tdef |
|
| 9 |
+A|hello\ | hello |
|
| 10 |
+A|hello\\ | hello\ |
|
| 11 |
+A|"hello | hello |
|
| 12 |
+A|"hello\" | hello" |
|
| 13 |
+A|"hel'lo" | hel'lo |
|
| 14 |
+A|'hello | hello |
|
| 15 |
+A|'hello\' | hello\ |
|
| 16 |
+A|"''" | '' |
|
| 17 |
+A|$. | $. |
|
| 18 |
+A|$1 | |
|
| 19 |
+A|he$1x | hex |
|
| 20 |
+A|he$.x | he$.x |
|
| 21 |
+# Next one is different on Windows as $pwd==$PWD |
|
| 22 |
+U|he$pwd. | he. |
|
| 23 |
+W|he$pwd. | he/home. |
|
| 24 |
+A|he$PWD | he/home |
|
| 25 |
+A|he\$PWD | he$PWD |
|
| 26 |
+A|he\\$PWD | he\/home |
|
| 27 |
+A|he\${} | he${}
|
|
| 28 |
+A|he\${}xx | he${}xx
|
|
| 29 |
+A|he${} | he
|
|
| 30 |
+A|he${}xx | hexx
|
|
| 31 |
+A|he${hi} | he
|
|
| 32 |
+A|he${hi}xx | hexx
|
|
| 33 |
+A|he${PWD} | he/home
|
|
| 34 |
+A|he${.} | error
|
|
| 35 |
+A|he${XXX:-000}xx | he000xx
|
|
| 36 |
+A|he${PWD:-000}xx | he/homexx
|
|
| 37 |
+A|he${XXX:-$PWD}xx | he/homexx
|
|
| 38 |
+A|he${XXX:-${PWD:-yyy}}xx | he/homexx
|
|
| 39 |
+A|he${XXX:-${YYY:-yyy}}xx | heyyyxx
|
|
| 40 |
+A|he${XXX:YYY} | error
|
|
| 41 |
+A|he${XXX:+${PWD}}xx | hexx
|
|
| 42 |
+A|he${PWD:+${XXX}}xx | hexx
|
|
| 43 |
+A|he${PWD:+${SHELL}}xx | hebashxx
|
|
| 44 |
+A|he${XXX:+000}xx | hexx
|
|
| 45 |
+A|he${PWD:+000}xx | he000xx
|
|
| 46 |
+A|'he${XX}' | he${XX}
|
|
| 47 |
+A|"he${PWD}" | he/home
|
|
| 48 |
+A|"he'$PWD'" | he'/home' |
|
| 49 |
+A|"$PWD" | /home |
|
| 50 |
+A|'$PWD' | $PWD |
|
| 51 |
+A|'\$PWD' | \$PWD |
|
| 52 |
+A|'"hello"' | "hello" |
|
| 53 |
+A|he\$PWD | he$PWD |
|
| 54 |
+A|"he\$PWD" | he$PWD |
|
| 55 |
+A|'he\$PWD' | he\$PWD |
|
| 56 |
+A|he${PWD | error
|
|
| 57 |
+A|he${PWD:=000}xx | error
|
|
| 58 |
+A|he${PWD:+${PWD}:}xx | he/home:xx
|
|
| 59 |
+A|he${XXX:-\$PWD:}xx | he$PWD:xx
|
|
| 60 |
+A|he${XXX:-\${PWD}z}xx | he${PWDz}xx
|
|
| 61 |
+A|안녕하세요 | 안녕하세요 |
|
| 62 |
+A|안'녕'하세요 | 안녕하세요 |
|
| 63 |
+A|안'녕하세요 | 안녕하세요 |
|
| 64 |
+A|안녕\'하세요 | 안녕'하세요 |
|
| 65 |
+A|안\\'녕하세요 | 안\녕하세요 |
|
| 66 |
+A|안녕\t하세요 | 안녕t하세요 |
|
| 67 |
+A|"안녕\t하세요" | 안녕\t하세요 |
|
| 68 |
+A|'안녕\t하세요 | 안녕\t하세요 |
|
| 69 |
+A|안녕하세요\ | 안녕하세요 |
|
| 70 |
+A|안녕하세요\\ | 안녕하세요\ |
|
| 71 |
+A|"안녕하세요 | 안녕하세요 |
|
| 72 |
+A|"안녕하세요\" | 안녕하세요" |
|
| 73 |
+A|"안녕'하세요" | 안녕'하세요 |
|
| 74 |
+A|'안녕하세요 | 안녕하세요 |
|
| 75 |
+A|'안녕하세요\' | 안녕하세요\ |
|
| 76 |
+A|안녕$1x | 안녕x |
|
| 77 |
+A|안녕$.x | 안녕$.x |
|
| 78 |
+# Next one is different on Windows as $pwd==$PWD |
|
| 79 |
+U|안녕$pwd. | 안녕. |
|
| 80 |
+W|안녕$pwd. | 안녕/home. |
|
| 81 |
+A|안녕$PWD | 안녕/home |
|
| 82 |
+A|안녕\$PWD | 안녕$PWD |
|
| 83 |
+A|안녕\\$PWD | 안녕\/home |
|
| 84 |
+A|안녕\${} | 안녕${}
|
|
| 85 |
+A|안녕\${}xx | 안녕${}xx
|
|
| 86 |
+A|안녕${} | 안녕
|
|
| 87 |
+A|안녕${}xx | 안녕xx
|
|
| 88 |
+A|안녕${hi} | 안녕
|
|
| 89 |
+A|안녕${hi}xx | 안녕xx
|
|
| 90 |
+A|안녕${PWD} | 안녕/home
|
|
| 91 |
+A|안녕${.} | error
|
|
| 92 |
+A|안녕${XXX:-000}xx | 안녕000xx
|
|
| 93 |
+A|안녕${PWD:-000}xx | 안녕/homexx
|
|
| 94 |
+A|안녕${XXX:-$PWD}xx | 안녕/homexx
|
|
| 95 |
+A|안녕${XXX:-${PWD:-yyy}}xx | 안녕/homexx
|
|
| 96 |
+A|안녕${XXX:-${YYY:-yyy}}xx | 안녕yyyxx
|
|
| 97 |
+A|안녕${XXX:YYY} | error
|
|
| 98 |
+A|안녕${XXX:+${PWD}}xx | 안녕xx
|
|
| 99 |
+A|안녕${PWD:+${XXX}}xx | 안녕xx
|
|
| 100 |
+A|안녕${PWD:+${SHELL}}xx | 안녕bashxx
|
|
| 101 |
+A|안녕${XXX:+000}xx | 안녕xx
|
|
| 102 |
+A|안녕${PWD:+000}xx | 안녕000xx
|
|
| 103 |
+A|'안녕${XX}' | 안녕${XX}
|
|
| 104 |
+A|"안녕${PWD}" | 안녕/home
|
|
| 105 |
+A|"안녕'$PWD'" | 안녕'/home' |
|
| 106 |
+A|'"안녕"' | "안녕" |
|
| 107 |
+A|안녕\$PWD | 안녕$PWD |
|
| 108 |
+A|"안녕\$PWD" | 안녕$PWD |
|
| 109 |
+A|'안녕\$PWD' | 안녕\$PWD |
|
| 110 |
+A|안녕${PWD | error
|
|
| 111 |
+A|안녕${PWD:=000}xx | error
|
|
| 112 |
+A|안녕${PWD:+${PWD}:}xx | 안녕/home:xx
|
|
| 113 |
+A|안녕${XXX:-\$PWD:}xx | 안녕$PWD:xx
|
|
| 114 |
+A|안녕${XXX:-\${PWD}z}xx | 안녕${PWDz}xx
|
|
| 115 |
+A|$KOREAN | 한êµì–´ |
|
| 116 |
+A|안녕$KOREAN | 안녕한êµì–´ |
| ... | ... |
@@ -8,6 +8,7 @@ package dockerfile |
| 8 | 8 |
|
| 9 | 9 |
import ( |
| 10 | 10 |
"fmt" |
| 11 |
+ "runtime" |
|
| 11 | 12 |
"strings" |
| 12 | 13 |
"text/scanner" |
| 13 | 14 |
"unicode" |
| ... | ... |
@@ -298,9 +299,16 @@ func (sw *shellWord) processName() string {
|
| 298 | 298 |
} |
| 299 | 299 |
|
| 300 | 300 |
func (sw *shellWord) getEnv(name string) string {
|
| 301 |
+ if runtime.GOOS == "windows" {
|
|
| 302 |
+ // Case-insensitive environment variables on Windows |
|
| 303 |
+ name = strings.ToUpper(name) |
|
| 304 |
+ } |
|
| 301 | 305 |
for _, env := range sw.envs {
|
| 302 | 306 |
i := strings.Index(env, "=") |
| 303 | 307 |
if i < 0 {
|
| 308 |
+ if runtime.GOOS == "windows" {
|
|
| 309 |
+ env = strings.ToUpper(env) |
|
| 310 |
+ } |
|
| 304 | 311 |
if name == env {
|
| 305 | 312 |
// Should probably never get here, but just in case treat |
| 306 | 313 |
// it like "var" and "var=" are the same |
| ... | ... |
@@ -308,7 +316,11 @@ func (sw *shellWord) getEnv(name string) string {
|
| 308 | 308 |
} |
| 309 | 309 |
continue |
| 310 | 310 |
} |
| 311 |
- if name != env[:i] {
|
|
| 311 |
+ compareName := env[:i] |
|
| 312 |
+ if runtime.GOOS == "windows" {
|
|
| 313 |
+ compareName = strings.ToUpper(compareName) |
|
| 314 |
+ } |
|
| 315 |
+ if name != compareName {
|
|
| 312 | 316 |
continue |
| 313 | 317 |
} |
| 314 | 318 |
return env[i+1:] |
| ... | ... |
@@ -3,12 +3,14 @@ package dockerfile |
| 3 | 3 |
import ( |
| 4 | 4 |
"bufio" |
| 5 | 5 |
"os" |
| 6 |
+ "runtime" |
|
| 6 | 7 |
"strings" |
| 7 | 8 |
"testing" |
| 8 | 9 |
) |
| 9 | 10 |
|
| 10 | 11 |
func TestShellParser4EnvVars(t *testing.T) {
|
| 11 | 12 |
fn := "envVarTest" |
| 13 |
+ lineCount := 0 |
|
| 12 | 14 |
|
| 13 | 15 |
file, err := os.Open(fn) |
| 14 | 16 |
if err != nil {
|
| ... | ... |
@@ -20,6 +22,7 @@ func TestShellParser4EnvVars(t *testing.T) {
|
| 20 | 20 |
envs := []string{"PWD=/home", "SHELL=bash", "KOREAN=한êµì–´"}
|
| 21 | 21 |
for scanner.Scan() {
|
| 22 | 22 |
line := scanner.Text() |
| 23 |
+ lineCount++ |
|
| 23 | 24 |
|
| 24 | 25 |
// Trim comments and blank lines |
| 25 | 26 |
i := strings.Index(line, "#") |
| ... | ... |
@@ -33,21 +36,30 @@ func TestShellParser4EnvVars(t *testing.T) {
|
| 33 | 33 |
} |
| 34 | 34 |
|
| 35 | 35 |
words := strings.Split(line, "|") |
| 36 |
- if len(words) != 2 {
|
|
| 36 |
+ if len(words) != 3 {
|
|
| 37 | 37 |
t.Fatalf("Error in '%s' - should be exactly one | in:%q", fn, line)
|
| 38 | 38 |
} |
| 39 | 39 |
|
| 40 | 40 |
words[0] = strings.TrimSpace(words[0]) |
| 41 | 41 |
words[1] = strings.TrimSpace(words[1]) |
| 42 |
+ words[2] = strings.TrimSpace(words[2]) |
|
| 42 | 43 |
|
| 43 |
- newWord, err := ProcessWord(words[0], envs, '\\') |
|
| 44 |
- |
|
| 45 |
- if err != nil {
|
|
| 46 |
- newWord = "error" |
|
| 44 |
+ // Key W=Windows; A=All; U=Unix |
|
| 45 |
+ if (words[0] != "W") && (words[0] != "A") && (words[0] != "U") {
|
|
| 46 |
+ t.Fatalf("Invalid tag %s at line %d of %s. Must be W, A or U", words[0], lineCount, fn)
|
|
| 47 | 47 |
} |
| 48 | 48 |
|
| 49 |
- if newWord != words[1] {
|
|
| 50 |
- t.Fatalf("Error. Src: %s Calc: %s Expected: %s", words[0], newWord, words[1])
|
|
| 49 |
+ if ((words[0] == "W" || words[0] == "A") && runtime.GOOS == "windows") || |
|
| 50 |
+ ((words[0] == "U" || words[0] == "A") && runtime.GOOS != "windows") {
|
|
| 51 |
+ newWord, err := ProcessWord(words[1], envs, '\\') |
|
| 52 |
+ |
|
| 53 |
+ if err != nil {
|
|
| 54 |
+ newWord = "error" |
|
| 55 |
+ } |
|
| 56 |
+ |
|
| 57 |
+ if newWord != words[2] {
|
|
| 58 |
+ t.Fatalf("Error. Src: %s Calc: %s Expected: %s at line %d", words[1], newWord, words[2], lineCount)
|
|
| 59 |
+ } |
|
| 51 | 60 |
} |
| 52 | 61 |
} |
| 53 | 62 |
} |
| ... | ... |
@@ -17,7 +17,6 @@ import ( |
| 17 | 17 |
|
| 18 | 18 |
type psOptions struct {
|
| 19 | 19 |
nodeIDs []string |
| 20 |
- all bool |
|
| 21 | 20 |
noResolve bool |
| 22 | 21 |
noTrunc bool |
| 23 | 22 |
filter opts.FilterOpt |
| ... | ... |
@@ -44,7 +43,6 @@ func newPsCommand(dockerCli *command.DockerCli) *cobra.Command {
|
| 44 | 44 |
flags.BoolVar(&opts.noTrunc, "no-trunc", false, "Do not truncate output") |
| 45 | 45 |
flags.BoolVar(&opts.noResolve, "no-resolve", false, "Do not map IDs to Names") |
| 46 | 46 |
flags.VarP(&opts.filter, "filter", "f", "Filter output based on conditions provided") |
| 47 |
- flags.BoolVarP(&opts.all, "all", "a", false, "Show all tasks (default shows tasks that are or will be running)") |
|
| 48 | 47 |
|
| 49 | 48 |
return cmd |
| 50 | 49 |
} |
| ... | ... |
@@ -74,11 +72,6 @@ func runPs(dockerCli *command.DockerCli, opts psOptions) error {
|
| 74 | 74 |
filter := opts.filter.Value() |
| 75 | 75 |
filter.Add("node", node.ID)
|
| 76 | 76 |
|
| 77 |
- if !opts.all && !filter.Include("desired-state") {
|
|
| 78 |
- filter.Add("desired-state", string(swarm.TaskStateRunning))
|
|
| 79 |
- filter.Add("desired-state", string(swarm.TaskStateAccepted))
|
|
| 80 |
- } |
|
| 81 |
- |
|
| 82 | 77 |
nodeTasks, err := client.TaskList(ctx, types.TaskListOptions{Filters: filter})
|
| 83 | 78 |
if err != nil {
|
| 84 | 79 |
errs = append(errs, err.Error()) |
| ... | ... |
@@ -1,12 +1,9 @@ |
| 1 | 1 |
package plugin |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
- "fmt" |
|
| 5 |
- |
|
| 6 | 4 |
"github.com/docker/docker/cli" |
| 7 | 5 |
"github.com/docker/docker/cli/command" |
| 8 | 6 |
"github.com/docker/docker/cli/command/inspect" |
| 9 |
- "github.com/docker/docker/reference" |
|
| 10 | 7 |
"github.com/spf13/cobra" |
| 11 | 8 |
"golang.org/x/net/context" |
| 12 | 9 |
) |
| ... | ... |
@@ -20,7 +17,7 @@ func newInspectCommand(dockerCli *command.DockerCli) *cobra.Command {
|
| 20 | 20 |
var opts inspectOptions |
| 21 | 21 |
|
| 22 | 22 |
cmd := &cobra.Command{
|
| 23 |
- Use: "inspect [OPTIONS] PLUGIN [PLUGIN...]", |
|
| 23 |
+ Use: "inspect [OPTIONS] PLUGIN|ID [PLUGIN|ID...]", |
|
| 24 | 24 |
Short: "Display detailed information on one or more plugins", |
| 25 | 25 |
Args: cli.RequiresMinArgs(1), |
| 26 | 26 |
RunE: func(cmd *cobra.Command, args []string) error {
|
| ... | ... |
@@ -37,20 +34,8 @@ func newInspectCommand(dockerCli *command.DockerCli) *cobra.Command {
|
| 37 | 37 |
func runInspect(dockerCli *command.DockerCli, opts inspectOptions) error {
|
| 38 | 38 |
client := dockerCli.Client() |
| 39 | 39 |
ctx := context.Background() |
| 40 |
- getRef := func(name string) (interface{}, []byte, error) {
|
|
| 41 |
- named, err := reference.ParseNamed(name) // FIXME: validate |
|
| 42 |
- if err != nil {
|
|
| 43 |
- return nil, nil, err |
|
| 44 |
- } |
|
| 45 |
- if reference.IsNameOnly(named) {
|
|
| 46 |
- named = reference.WithDefaultTag(named) |
|
| 47 |
- } |
|
| 48 |
- ref, ok := named.(reference.NamedTagged) |
|
| 49 |
- if !ok {
|
|
| 50 |
- return nil, nil, fmt.Errorf("invalid name: %s", named.String())
|
|
| 51 |
- } |
|
| 52 |
- |
|
| 53 |
- return client.PluginInspectWithRaw(ctx, ref.String()) |
|
| 40 |
+ getRef := func(ref string) (interface{}, []byte, error) {
|
|
| 41 |
+ return client.PluginInspectWithRaw(ctx, ref) |
|
| 54 | 42 |
} |
| 55 | 43 |
|
| 56 | 44 |
return inspect.Inspect(dockerCli.Out(), opts.pluginNames, opts.format, getRef) |
| ... | ... |
@@ -25,9 +25,9 @@ func newSecretCreateCommand(dockerCli *command.DockerCli) *cobra.Command {
|
| 25 | 25 |
} |
| 26 | 26 |
|
| 27 | 27 |
cmd := &cobra.Command{
|
| 28 |
- Use: "create [OPTIONS] SECRET [SECRET...]", |
|
| 28 |
+ Use: "create [OPTIONS] SECRET", |
|
| 29 | 29 |
Short: "Create a secret using stdin as content", |
| 30 |
- Args: cli.RequiresMinArgs(1), |
|
| 30 |
+ Args: cli.ExactArgs(1), |
|
| 31 | 31 |
RunE: func(cmd *cobra.Command, args []string) error {
|
| 32 | 32 |
createOpts.name = args[0] |
| 33 | 33 |
return runSecretCreate(dockerCli, createOpts) |
| ... | ... |
@@ -25,7 +25,7 @@ func newSecretInspectCommand(dockerCli *command.DockerCli) *cobra.Command {
|
| 25 | 25 |
}, |
| 26 | 26 |
} |
| 27 | 27 |
|
| 28 |
- cmd.Flags().StringVarP(&opts.format, "format", "f", "", "Format the output using the given go template") |
|
| 28 |
+ cmd.Flags().StringVarP(&opts.format, "format", "f", "", "Format the output using the given Go template") |
|
| 29 | 29 |
return cmd |
| 30 | 30 |
} |
| 31 | 31 |
|
| ... | ... |
@@ -21,9 +21,10 @@ func newSecretListCommand(dockerCli *command.DockerCli) *cobra.Command {
|
| 21 | 21 |
opts := listOptions{}
|
| 22 | 22 |
|
| 23 | 23 |
cmd := &cobra.Command{
|
| 24 |
- Use: "ls [OPTIONS]", |
|
| 25 |
- Short: "List secrets", |
|
| 26 |
- Args: cli.NoArgs, |
|
| 24 |
+ Use: "ls [OPTIONS]", |
|
| 25 |
+ Aliases: []string{"list"},
|
|
| 26 |
+ Short: "List secrets", |
|
| 27 |
+ Args: cli.NoArgs, |
|
| 27 | 28 |
RunE: func(cmd *cobra.Command, args []string) error {
|
| 28 | 29 |
return runSecretList(dockerCli, opts) |
| 29 | 30 |
}, |
| ... | ... |
@@ -16,9 +16,10 @@ type removeOptions struct {
|
| 16 | 16 |
|
| 17 | 17 |
func newSecretRemoveCommand(dockerCli *command.DockerCli) *cobra.Command {
|
| 18 | 18 |
return &cobra.Command{
|
| 19 |
- Use: "rm SECRET [SECRET...]", |
|
| 20 |
- Short: "Remove one or more secrets", |
|
| 21 |
- Args: cli.RequiresMinArgs(1), |
|
| 19 |
+ Use: "rm SECRET [SECRET...]", |
|
| 20 |
+ Aliases: []string{"remove"},
|
|
| 21 |
+ Short: "Remove one or more secrets", |
|
| 22 |
+ Args: cli.RequiresMinArgs(1), |
|
| 22 | 23 |
RunE: func(cmd *cobra.Command, args []string) error {
|
| 23 | 24 |
opts := removeOptions{
|
| 24 | 25 |
names: args, |
| ... | ... |
@@ -2,7 +2,6 @@ package service |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"github.com/docker/docker/api/types" |
| 5 |
- "github.com/docker/docker/api/types/swarm" |
|
| 6 | 5 |
"github.com/docker/docker/cli" |
| 7 | 6 |
"github.com/docker/docker/cli/command" |
| 8 | 7 |
"github.com/docker/docker/cli/command/idresolver" |
| ... | ... |
@@ -15,7 +14,6 @@ import ( |
| 15 | 15 |
|
| 16 | 16 |
type psOptions struct {
|
| 17 | 17 |
serviceID string |
| 18 |
- all bool |
|
| 19 | 18 |
quiet bool |
| 20 | 19 |
noResolve bool |
| 21 | 20 |
noTrunc bool |
| ... | ... |
@@ -39,7 +37,6 @@ func newPsCommand(dockerCli *command.DockerCli) *cobra.Command {
|
| 39 | 39 |
flags.BoolVar(&opts.noTrunc, "no-trunc", false, "Do not truncate output") |
| 40 | 40 |
flags.BoolVar(&opts.noResolve, "no-resolve", false, "Do not map IDs to Names") |
| 41 | 41 |
flags.VarP(&opts.filter, "filter", "f", "Filter output based on conditions provided") |
| 42 |
- flags.BoolVarP(&opts.all, "all", "a", false, "Show all tasks (default shows tasks that are or will be running)") |
|
| 43 | 42 |
|
| 44 | 43 |
return cmd |
| 45 | 44 |
} |
| ... | ... |
@@ -67,11 +64,6 @@ func runPS(dockerCli *command.DockerCli, opts psOptions) error {
|
| 67 | 67 |
} |
| 68 | 68 |
} |
| 69 | 69 |
|
| 70 |
- if !opts.all && !filter.Include("desired-state") {
|
|
| 71 |
- filter.Add("desired-state", string(swarm.TaskStateRunning))
|
|
| 72 |
- filter.Add("desired-state", string(swarm.TaskStateAccepted))
|
|
| 73 |
- } |
|
| 74 |
- |
|
| 75 | 70 |
tasks, err := client.TaskList(ctx, types.TaskListOptions{Filters: filter})
|
| 76 | 71 |
if err != nil {
|
| 77 | 72 |
return err |
| ... | ... |
@@ -22,6 +22,7 @@ import ( |
| 22 | 22 |
"github.com/docker/docker/cli" |
| 23 | 23 |
"github.com/docker/docker/cli/command" |
| 24 | 24 |
servicecmd "github.com/docker/docker/cli/command/service" |
| 25 |
+ dockerclient "github.com/docker/docker/client" |
|
| 25 | 26 |
"github.com/docker/docker/opts" |
| 26 | 27 |
runconfigopts "github.com/docker/docker/runconfig/opts" |
| 27 | 28 |
"github.com/docker/go-connections/nat" |
| ... | ... |
@@ -123,7 +124,10 @@ func deployCompose(ctx context.Context, dockerCli *command.DockerCli, opts deplo |
| 123 | 123 |
|
| 124 | 124 |
namespace := namespace{name: opts.namespace}
|
| 125 | 125 |
|
| 126 |
- networks := convertNetworks(namespace, config.Networks) |
|
| 126 |
+ networks, externalNetworks := convertNetworks(namespace, config.Networks) |
|
| 127 |
+ if err := validateExternalNetworks(ctx, dockerCli, externalNetworks); err != nil {
|
|
| 128 |
+ return err |
|
| 129 |
+ } |
|
| 127 | 130 |
if err := createNetworks(ctx, dockerCli, namespace, networks); err != nil {
|
| 128 | 131 |
return err |
| 129 | 132 |
} |
| ... | ... |
@@ -179,7 +183,7 @@ func getConfigFile(filename string) (*composetypes.ConfigFile, error) {
|
| 179 | 179 |
func convertNetworks( |
| 180 | 180 |
namespace namespace, |
| 181 | 181 |
networks map[string]composetypes.NetworkConfig, |
| 182 |
-) map[string]types.NetworkCreate {
|
|
| 182 |
+) (map[string]types.NetworkCreate, []string) {
|
|
| 183 | 183 |
if networks == nil {
|
| 184 | 184 |
networks = make(map[string]composetypes.NetworkConfig) |
| 185 | 185 |
} |
| ... | ... |
@@ -187,10 +191,12 @@ func convertNetworks( |
| 187 | 187 |
// TODO: only add default network if it's used |
| 188 | 188 |
networks["default"] = composetypes.NetworkConfig{}
|
| 189 | 189 |
|
| 190 |
+ externalNetworks := []string{}
|
|
| 190 | 191 |
result := make(map[string]types.NetworkCreate) |
| 191 | 192 |
|
| 192 | 193 |
for internalName, network := range networks {
|
| 193 |
- if network.External.Name != "" {
|
|
| 194 |
+ if network.External.External {
|
|
| 195 |
+ externalNetworks = append(externalNetworks, network.External.Name) |
|
| 194 | 196 |
continue |
| 195 | 197 |
} |
| 196 | 198 |
|
| ... | ... |
@@ -216,7 +222,29 @@ func convertNetworks( |
| 216 | 216 |
result[internalName] = createOpts |
| 217 | 217 |
} |
| 218 | 218 |
|
| 219 |
- return result |
|
| 219 |
+ return result, externalNetworks |
|
| 220 |
+} |
|
| 221 |
+ |
|
| 222 |
+func validateExternalNetworks( |
|
| 223 |
+ ctx context.Context, |
|
| 224 |
+ dockerCli *command.DockerCli, |
|
| 225 |
+ externalNetworks []string) error {
|
|
| 226 |
+ client := dockerCli.Client() |
|
| 227 |
+ |
|
| 228 |
+ for _, networkName := range externalNetworks {
|
|
| 229 |
+ network, err := client.NetworkInspect(ctx, networkName) |
|
| 230 |
+ if err != nil {
|
|
| 231 |
+ if dockerclient.IsErrNetworkNotFound(err) {
|
|
| 232 |
+ return fmt.Errorf("network %q is declared as external, but could not be found. You need to create the network before the stack is deployed (with overlay driver)", networkName)
|
|
| 233 |
+ } |
|
| 234 |
+ return err |
|
| 235 |
+ } |
|
| 236 |
+ if network.Scope != "swarm" {
|
|
| 237 |
+ return fmt.Errorf("network %q is declared as external, but it is not in the right scope: %q instead of %q", networkName, network.Scope, "swarm")
|
|
| 238 |
+ } |
|
| 239 |
+ } |
|
| 240 |
+ |
|
| 241 |
+ return nil |
|
| 220 | 242 |
} |
| 221 | 243 |
|
| 222 | 244 |
func createNetworks( |
| ... | ... |
@@ -227,7 +255,7 @@ func createNetworks( |
| 227 | 227 |
) error {
|
| 228 | 228 |
client := dockerCli.Client() |
| 229 | 229 |
|
| 230 |
- existingNetworks, err := getNetworks(ctx, client, namespace.name) |
|
| 230 |
+ existingNetworks, err := getStackNetworks(ctx, client, namespace.name) |
|
| 231 | 231 |
if err != nil {
|
| 232 | 232 |
return err |
| 233 | 233 |
} |
| ... | ... |
@@ -258,30 +286,39 @@ func createNetworks( |
| 258 | 258 |
|
| 259 | 259 |
func convertServiceNetworks( |
| 260 | 260 |
networks map[string]*composetypes.ServiceNetworkConfig, |
| 261 |
+ networkConfigs map[string]composetypes.NetworkConfig, |
|
| 261 | 262 |
namespace namespace, |
| 262 | 263 |
name string, |
| 263 |
-) []swarm.NetworkAttachmentConfig {
|
|
| 264 |
+) ([]swarm.NetworkAttachmentConfig, error) {
|
|
| 264 | 265 |
if len(networks) == 0 {
|
| 265 | 266 |
return []swarm.NetworkAttachmentConfig{
|
| 266 | 267 |
{
|
| 267 | 268 |
Target: namespace.scope("default"),
|
| 268 | 269 |
Aliases: []string{name},
|
| 269 | 270 |
}, |
| 270 |
- } |
|
| 271 |
+ }, nil |
|
| 271 | 272 |
} |
| 272 | 273 |
|
| 273 | 274 |
nets := []swarm.NetworkAttachmentConfig{}
|
| 274 | 275 |
for networkName, network := range networks {
|
| 276 |
+ networkConfig, ok := networkConfigs[networkName] |
|
| 277 |
+ if !ok {
|
|
| 278 |
+ return []swarm.NetworkAttachmentConfig{}, fmt.Errorf("invalid network: %s", networkName)
|
|
| 279 |
+ } |
|
| 275 | 280 |
var aliases []string |
| 276 | 281 |
if network != nil {
|
| 277 | 282 |
aliases = network.Aliases |
| 278 | 283 |
} |
| 284 |
+ target := namespace.scope(networkName) |
|
| 285 |
+ if networkConfig.External.External {
|
|
| 286 |
+ target = networkName |
|
| 287 |
+ } |
|
| 279 | 288 |
nets = append(nets, swarm.NetworkAttachmentConfig{
|
| 280 |
- Target: namespace.scope(networkName), |
|
| 289 |
+ Target: target, |
|
| 281 | 290 |
Aliases: append(aliases, name), |
| 282 | 291 |
}) |
| 283 | 292 |
} |
| 284 |
- return nets |
|
| 293 |
+ return nets, nil |
|
| 285 | 294 |
} |
| 286 | 295 |
|
| 287 | 296 |
func convertVolumes( |
| ... | ... |
@@ -472,9 +509,10 @@ func convertServices( |
| 472 | 472 |
|
| 473 | 473 |
services := config.Services |
| 474 | 474 |
volumes := config.Volumes |
| 475 |
+ networks := config.Networks |
|
| 475 | 476 |
|
| 476 | 477 |
for _, service := range services {
|
| 477 |
- serviceSpec, err := convertService(namespace, service, volumes) |
|
| 478 |
+ serviceSpec, err := convertService(namespace, service, networks, volumes) |
|
| 478 | 479 |
if err != nil {
|
| 479 | 480 |
return nil, err |
| 480 | 481 |
} |
| ... | ... |
@@ -487,6 +525,7 @@ func convertServices( |
| 487 | 487 |
func convertService( |
| 488 | 488 |
namespace namespace, |
| 489 | 489 |
service composetypes.ServiceConfig, |
| 490 |
+ networkConfigs map[string]composetypes.NetworkConfig, |
|
| 490 | 491 |
volumes map[string]composetypes.VolumeConfig, |
| 491 | 492 |
) (swarm.ServiceSpec, error) {
|
| 492 | 493 |
name := namespace.scope(service.Name) |
| ... | ... |
@@ -523,6 +562,11 @@ func convertService( |
| 523 | 523 |
return swarm.ServiceSpec{}, err
|
| 524 | 524 |
} |
| 525 | 525 |
|
| 526 |
+ networks, err := convertServiceNetworks(service.Networks, networkConfigs, namespace, service.Name) |
|
| 527 |
+ if err != nil {
|
|
| 528 |
+ return swarm.ServiceSpec{}, err
|
|
| 529 |
+ } |
|
| 530 |
+ |
|
| 526 | 531 |
serviceSpec := swarm.ServiceSpec{
|
| 527 | 532 |
Annotations: swarm.Annotations{
|
| 528 | 533 |
Name: name, |
| ... | ... |
@@ -553,7 +597,7 @@ func convertService( |
| 553 | 553 |
}, |
| 554 | 554 |
EndpointSpec: endpoint, |
| 555 | 555 |
Mode: mode, |
| 556 |
- Networks: convertServiceNetworks(service.Networks, namespace, service.Name), |
|
| 556 |
+ Networks: networks, |
|
| 557 | 557 |
UpdateConfig: convertUpdateConfig(service.Deploy.UpdateConfig), |
| 558 | 558 |
} |
| 559 | 559 |
|
| ... | ... |
@@ -135,7 +135,7 @@ func (c *Config) CopyToPipe(iop libcontainerd.IOPipe) {
|
| 135 | 135 |
go func() {
|
| 136 | 136 |
pools.Copy(iop.Stdin, stdin) |
| 137 | 137 |
if err := iop.Stdin.Close(); err != nil {
|
| 138 |
- logrus.Errorf("failed to close stdin: %+v", err)
|
|
| 138 |
+ logrus.Warnf("failed to close stdin: %+v", err)
|
|
| 139 | 139 |
} |
| 140 | 140 |
}() |
| 141 | 141 |
} |
| ... | ... |
@@ -123,7 +123,7 @@ __docker_complete_container_ids() {
|
| 123 | 123 |
COMPREPLY=( $(compgen -W "${containers[*]}" -- "$cur") )
|
| 124 | 124 |
} |
| 125 | 125 |
|
| 126 |
-__docker_complete_images() {
|
|
| 126 |
+__docker_images() {
|
|
| 127 | 127 |
local images_args="" |
| 128 | 128 |
|
| 129 | 129 |
case "$DOCKER_COMPLETION_SHOW_IMAGE_IDS" in |
| ... | ... |
@@ -152,8 +152,11 @@ __docker_complete_images() {
|
| 152 | 152 |
;; |
| 153 | 153 |
esac |
| 154 | 154 |
|
| 155 |
- local images=$(__docker_q images $images_args | awk "$awk_script") |
|
| 156 |
- COMPREPLY=( $(compgen -W "$images" -- "$cur") ) |
|
| 155 |
+ __docker_q images $images_args | awk "$awk_script" | grep -v '<none>$' |
|
| 156 |
+} |
|
| 157 |
+ |
|
| 158 |
+__docker_complete_images() {
|
|
| 159 |
+ COMPREPLY=( $(compgen -W "$(__docker_images)" -- "$cur") ) |
|
| 157 | 160 |
__ltrim_colon_completions "$cur" |
| 158 | 161 |
} |
| 159 | 162 |
|
| ... | ... |
@@ -168,13 +171,6 @@ __docker_complete_image_repos_and_tags() {
|
| 168 | 168 |
__ltrim_colon_completions "$cur" |
| 169 | 169 |
} |
| 170 | 170 |
|
| 171 |
-__docker_complete_containers_and_images() {
|
|
| 172 |
- __docker_complete_containers_all |
|
| 173 |
- local containers=( "${COMPREPLY[@]}" )
|
|
| 174 |
- __docker_complete_images |
|
| 175 |
- COMPREPLY+=( "${containers[@]}" )
|
|
| 176 |
-} |
|
| 177 |
- |
|
| 178 | 171 |
# __docker_networks returns a list of all networks. Additional options to |
| 179 | 172 |
# `docker network ls` may be specified in order to filter the list, e.g. |
| 180 | 173 |
# `__docker_networks --filter type=custom` |
| ... | ... |
@@ -315,6 +311,22 @@ __docker_complete_runtimes() {
|
| 315 | 315 |
COMPREPLY=( $(compgen -W "$(__docker_runtimes)" -- "$cur") ) |
| 316 | 316 |
} |
| 317 | 317 |
|
| 318 |
+# __docker_stacks returns a list of all stacks. |
|
| 319 |
+__docker_stacks() {
|
|
| 320 |
+ __docker_q stack ls | awk 'NR>1 {print $1}'
|
|
| 321 |
+} |
|
| 322 |
+ |
|
| 323 |
+# __docker_complete_stacks applies completion of stacks based on the current value |
|
| 324 |
+# of `$cur` or the value of the optional first option `--cur`, if given. |
|
| 325 |
+__docker_complete_stacks() {
|
|
| 326 |
+ local current="$cur" |
|
| 327 |
+ if [ "$1" = "--cur" ] ; then |
|
| 328 |
+ current="$2" |
|
| 329 |
+ shift 2 |
|
| 330 |
+ fi |
|
| 331 |
+ COMPREPLY=( $(compgen -W "$(__docker_stacks "$@")" -- "$current") ) |
|
| 332 |
+} |
|
| 333 |
+ |
|
| 318 | 334 |
# __docker_nodes returns a list of all nodes. Additional options to |
| 319 | 335 |
# `docker node ls` may be specified in order to filter the list, e.g. |
| 320 | 336 |
# `__docker_nodes --filter role=manager` |
| ... | ... |
@@ -397,6 +409,13 @@ __docker_append_to_completions() {
|
| 397 | 397 |
COMPREPLY=( ${COMPREPLY[@]/%/"$1"} )
|
| 398 | 398 |
} |
| 399 | 399 |
|
| 400 |
+# __docker_is_experimental tests whether the currently configured Docker daemon |
|
| 401 |
+# runs in experimental mode. If so, the function exits with 0 (true). |
|
| 402 |
+# Otherwise, or if the result cannot be determined, the exit value is 1 (false). |
|
| 403 |
+__docker_is_experimental() {
|
|
| 404 |
+ [ "$(__docker_q version -f '{{.Server.Experimental}}')" = "true" ]
|
|
| 405 |
+} |
|
| 406 |
+ |
|
| 400 | 407 |
# __docker_pos_first_nonflag finds the position of the first word that is neither |
| 401 | 408 |
# option nor an option's argument. If there are options that require arguments, |
| 402 | 409 |
# you should pass a glob describing those options, e.g. "--option1|-o|--option2" |
| ... | ... |
@@ -839,6 +858,7 @@ _docker_docker() {
|
| 839 | 839 |
*) |
| 840 | 840 |
local counter=$( __docker_pos_first_nonflag "$(__docker_to_extglob "$global_options_with_args")" ) |
| 841 | 841 |
if [ $cword -eq $counter ]; then |
| 842 |
+ __docker_is_experimental && commands+=(${experimental_commands[*]})
|
|
| 842 | 843 |
COMPREPLY=( $( compgen -W "${commands[*]} help" -- "$cur" ) )
|
| 843 | 844 |
fi |
| 844 | 845 |
;; |
| ... | ... |
@@ -1297,7 +1317,6 @@ _docker_container_run() {
|
| 1297 | 1297 |
--memory-swap |
| 1298 | 1298 |
--memory-swappiness |
| 1299 | 1299 |
--memory-reservation |
| 1300 |
- --mount |
|
| 1301 | 1300 |
--name |
| 1302 | 1301 |
--network |
| 1303 | 1302 |
--network-alias |
| ... | ... |
@@ -1863,6 +1882,10 @@ _docker_daemon() {
|
| 1863 | 1863 |
esac |
| 1864 | 1864 |
} |
| 1865 | 1865 |
|
| 1866 |
+_docker_deploy() {
|
|
| 1867 |
+ __docker_is_experimental && _docker_stack_deploy |
|
| 1868 |
+} |
|
| 1869 |
+ |
|
| 1866 | 1870 |
_docker_diff() {
|
| 1867 | 1871 |
_docker_container_diff |
| 1868 | 1872 |
} |
| ... | ... |
@@ -2253,7 +2276,7 @@ _docker_inspect() {
|
| 2253 | 2253 |
;; |
| 2254 | 2254 |
--type) |
| 2255 | 2255 |
if [ -z "$preselected_type" ] ; then |
| 2256 |
- COMPREPLY=( $( compgen -W "image container" -- "$cur" ) ) |
|
| 2256 |
+ COMPREPLY=( $( compgen -W "container image network node service volume" -- "$cur" ) ) |
|
| 2257 | 2257 |
return |
| 2258 | 2258 |
fi |
| 2259 | 2259 |
;; |
| ... | ... |
@@ -2270,7 +2293,14 @@ _docker_inspect() {
|
| 2270 | 2270 |
*) |
| 2271 | 2271 |
case "$type" in |
| 2272 | 2272 |
'') |
| 2273 |
- __docker_complete_containers_and_images |
|
| 2273 |
+ COMPREPLY=( $( compgen -W " |
|
| 2274 |
+ $(__docker_containers --all) |
|
| 2275 |
+ $(__docker_images) |
|
| 2276 |
+ $(__docker_networks) |
|
| 2277 |
+ $(__docker_nodes) |
|
| 2278 |
+ $(__docker_services) |
|
| 2279 |
+ $(__docker_volumes) |
|
| 2280 |
+ " -- "$cur" ) ) |
|
| 2274 | 2281 |
;; |
| 2275 | 2282 |
container) |
| 2276 | 2283 |
__docker_complete_containers_all |
| ... | ... |
@@ -2278,6 +2308,18 @@ _docker_inspect() {
|
| 2278 | 2278 |
image) |
| 2279 | 2279 |
__docker_complete_images |
| 2280 | 2280 |
;; |
| 2281 |
+ network) |
|
| 2282 |
+ __docker_complete_networks |
|
| 2283 |
+ ;; |
|
| 2284 |
+ node) |
|
| 2285 |
+ __docker_complete_nodes |
|
| 2286 |
+ ;; |
|
| 2287 |
+ service) |
|
| 2288 |
+ __docker_complete_services |
|
| 2289 |
+ ;; |
|
| 2290 |
+ volume) |
|
| 2291 |
+ __docker_complete_volumes |
|
| 2292 |
+ ;; |
|
| 2281 | 2293 |
esac |
| 2282 | 2294 |
esac |
| 2283 | 2295 |
} |
| ... | ... |
@@ -2623,7 +2665,7 @@ _docker_service_ps() {
|
| 2623 | 2623 |
|
| 2624 | 2624 |
case "$cur" in |
| 2625 | 2625 |
-*) |
| 2626 |
- COMPREPLY=( $( compgen -W "--all -a --filter -f --help --no-resolve --no-trunc --quiet -q" -- "$cur" ) ) |
|
| 2626 |
+ COMPREPLY=( $( compgen -W "--filter -f --help --no-resolve --no-trunc --quiet -q" -- "$cur" ) ) |
|
| 2627 | 2627 |
;; |
| 2628 | 2628 |
*) |
| 2629 | 2629 |
local counter=$(__docker_pos_first_nonflag '--filter|-f') |
| ... | ... |
@@ -3318,6 +3360,166 @@ _docker_search() {
|
| 3318 | 3318 |
esac |
| 3319 | 3319 |
} |
| 3320 | 3320 |
|
| 3321 |
+ |
|
| 3322 |
+_docker_stack() {
|
|
| 3323 |
+ local subcommands=" |
|
| 3324 |
+ deploy |
|
| 3325 |
+ ls |
|
| 3326 |
+ ps |
|
| 3327 |
+ rm |
|
| 3328 |
+ services |
|
| 3329 |
+ " |
|
| 3330 |
+ local aliases=" |
|
| 3331 |
+ down |
|
| 3332 |
+ list |
|
| 3333 |
+ remove |
|
| 3334 |
+ up |
|
| 3335 |
+ " |
|
| 3336 |
+ __docker_subcommands "$subcommands $aliases" && return |
|
| 3337 |
+ |
|
| 3338 |
+ case "$cur" in |
|
| 3339 |
+ -*) |
|
| 3340 |
+ COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) |
|
| 3341 |
+ ;; |
|
| 3342 |
+ *) |
|
| 3343 |
+ COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) ) |
|
| 3344 |
+ ;; |
|
| 3345 |
+ esac |
|
| 3346 |
+} |
|
| 3347 |
+ |
|
| 3348 |
+_docker_stack_deploy() {
|
|
| 3349 |
+ case "$prev" in |
|
| 3350 |
+ --bundle-file) |
|
| 3351 |
+ _filedir dab |
|
| 3352 |
+ return |
|
| 3353 |
+ ;; |
|
| 3354 |
+ --compose-file|-c) |
|
| 3355 |
+ _filedir yml |
|
| 3356 |
+ return |
|
| 3357 |
+ ;; |
|
| 3358 |
+ esac |
|
| 3359 |
+ |
|
| 3360 |
+ case "$cur" in |
|
| 3361 |
+ -*) |
|
| 3362 |
+ COMPREPLY=( $( compgen -W "--bundle-file --compose-file -c --help --with-registry-auth" -- "$cur" ) ) |
|
| 3363 |
+ ;; |
|
| 3364 |
+ esac |
|
| 3365 |
+} |
|
| 3366 |
+ |
|
| 3367 |
+_docker_stack_down() {
|
|
| 3368 |
+ _docker_stack_rm |
|
| 3369 |
+} |
|
| 3370 |
+ |
|
| 3371 |
+_docker_stack_list() {
|
|
| 3372 |
+ _docker_stack_ls |
|
| 3373 |
+} |
|
| 3374 |
+ |
|
| 3375 |
+_docker_stack_ls() {
|
|
| 3376 |
+ case "$cur" in |
|
| 3377 |
+ -*) |
|
| 3378 |
+ COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) |
|
| 3379 |
+ ;; |
|
| 3380 |
+ esac |
|
| 3381 |
+} |
|
| 3382 |
+ |
|
| 3383 |
+_docker_stack_ps() {
|
|
| 3384 |
+ local key=$(__docker_map_key_of_current_option '--filter|-f') |
|
| 3385 |
+ case "$key" in |
|
| 3386 |
+ desired-state) |
|
| 3387 |
+ COMPREPLY=( $( compgen -W "accepted running" -- "${cur##*=}" ) )
|
|
| 3388 |
+ return |
|
| 3389 |
+ ;; |
|
| 3390 |
+ id) |
|
| 3391 |
+ __docker_complete_stacks --cur "${cur##*=}" --id
|
|
| 3392 |
+ return |
|
| 3393 |
+ ;; |
|
| 3394 |
+ name) |
|
| 3395 |
+ __docker_complete_stacks --cur "${cur##*=}" --name
|
|
| 3396 |
+ return |
|
| 3397 |
+ ;; |
|
| 3398 |
+ esac |
|
| 3399 |
+ |
|
| 3400 |
+ case "$prev" in |
|
| 3401 |
+ --filter|-f) |
|
| 3402 |
+ COMPREPLY=( $( compgen -S = -W "id name desired-state" -- "$cur" ) ) |
|
| 3403 |
+ __docker_nospace |
|
| 3404 |
+ return |
|
| 3405 |
+ ;; |
|
| 3406 |
+ esac |
|
| 3407 |
+ |
|
| 3408 |
+ case "$cur" in |
|
| 3409 |
+ -*) |
|
| 3410 |
+ COMPREPLY=( $( compgen -W "--all -a --filter -f --help --no-resolve --no-trunc" -- "$cur" ) ) |
|
| 3411 |
+ ;; |
|
| 3412 |
+ *) |
|
| 3413 |
+ local counter=$(__docker_pos_first_nonflag '--filter|-f') |
|
| 3414 |
+ if [ $cword -eq $counter ]; then |
|
| 3415 |
+ __docker_complete_stacks |
|
| 3416 |
+ fi |
|
| 3417 |
+ ;; |
|
| 3418 |
+ esac |
|
| 3419 |
+} |
|
| 3420 |
+ |
|
| 3421 |
+_docker_stack_remove() {
|
|
| 3422 |
+ _docker_stack_rm |
|
| 3423 |
+} |
|
| 3424 |
+ |
|
| 3425 |
+_docker_stack_rm() {
|
|
| 3426 |
+ case "$cur" in |
|
| 3427 |
+ -*) |
|
| 3428 |
+ COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) |
|
| 3429 |
+ ;; |
|
| 3430 |
+ *) |
|
| 3431 |
+ local counter=$(__docker_pos_first_nonflag) |
|
| 3432 |
+ if [ $cword -eq $counter ]; then |
|
| 3433 |
+ __docker_complete_stacks |
|
| 3434 |
+ fi |
|
| 3435 |
+ ;; |
|
| 3436 |
+ esac |
|
| 3437 |
+} |
|
| 3438 |
+ |
|
| 3439 |
+_docker_stack_services() {
|
|
| 3440 |
+ local key=$(__docker_map_key_of_current_option '--filter|-f') |
|
| 3441 |
+ case "$key" in |
|
| 3442 |
+ id) |
|
| 3443 |
+ __docker_complete_services --cur "${cur##*=}" --id
|
|
| 3444 |
+ return |
|
| 3445 |
+ ;; |
|
| 3446 |
+ label) |
|
| 3447 |
+ return |
|
| 3448 |
+ ;; |
|
| 3449 |
+ name) |
|
| 3450 |
+ __docker_complete_services --cur "${cur##*=}" --name
|
|
| 3451 |
+ return |
|
| 3452 |
+ ;; |
|
| 3453 |
+ esac |
|
| 3454 |
+ |
|
| 3455 |
+ case "$prev" in |
|
| 3456 |
+ --filter|-f) |
|
| 3457 |
+ COMPREPLY=( $( compgen -S = -W "id label name" -- "$cur" ) ) |
|
| 3458 |
+ __docker_nospace |
|
| 3459 |
+ return |
|
| 3460 |
+ ;; |
|
| 3461 |
+ esac |
|
| 3462 |
+ |
|
| 3463 |
+ case "$cur" in |
|
| 3464 |
+ -*) |
|
| 3465 |
+ COMPREPLY=( $( compgen -W "--filter -f --help --quiet -q" -- "$cur" ) ) |
|
| 3466 |
+ ;; |
|
| 3467 |
+ *) |
|
| 3468 |
+ local counter=$(__docker_pos_first_nonflag '--filter|-f') |
|
| 3469 |
+ if [ $cword -eq $counter ]; then |
|
| 3470 |
+ __docker_complete_stacks |
|
| 3471 |
+ fi |
|
| 3472 |
+ ;; |
|
| 3473 |
+ esac |
|
| 3474 |
+} |
|
| 3475 |
+ |
|
| 3476 |
+_docker_stack_up() {
|
|
| 3477 |
+ _docker_stack_deploy |
|
| 3478 |
+} |
|
| 3479 |
+ |
|
| 3480 |
+ |
|
| 3321 | 3481 |
_docker_start() {
|
| 3322 | 3482 |
_docker_container_start |
| 3323 | 3483 |
} |
| ... | ... |
@@ -3651,6 +3853,7 @@ _docker() {
|
| 3651 | 3651 |
save |
| 3652 | 3652 |
search |
| 3653 | 3653 |
service |
| 3654 |
+ stack |
|
| 3654 | 3655 |
start |
| 3655 | 3656 |
stats |
| 3656 | 3657 |
stop |
| ... | ... |
@@ -3665,6 +3868,10 @@ _docker() {
|
| 3665 | 3665 |
wait |
| 3666 | 3666 |
) |
| 3667 | 3667 |
|
| 3668 |
+ local experimental_commands=( |
|
| 3669 |
+ deploy |
|
| 3670 |
+ ) |
|
| 3671 |
+ |
|
| 3668 | 3672 |
# These options are valid as global options for all client commands |
| 3669 | 3673 |
# and valid as command options for `docker daemon` |
| 3670 | 3674 |
local global_boolean_options=" |
| ... | ... |
@@ -137,7 +137,6 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l link -d 'Add |
| 137 | 137 |
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s m -l memory -d 'Memory limit (format: <number>[<unit>], where unit = b, k, m or g)' |
| 138 | 138 |
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l mac-address -d 'Container MAC address (e.g. 92:d0:c6:0a:29:33)' |
| 139 | 139 |
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l memory-swap -d "Total memory usage (memory + swap), set '-1' to disable swap (format: <number>[<unit>], where unit = b, k, m or g)" |
| 140 |
-complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l mount -d 'Attach a filesystem mount to the container' |
|
| 141 | 140 |
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l name -d 'Assign a name to the container' |
| 142 | 141 |
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l net -d 'Set the Network mode for the container' |
| 143 | 142 |
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s P -l publish-all -d 'Publish all exposed ports to random ports on the host interfaces' |
| ... | ... |
@@ -329,7 +328,6 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l link -d 'Add li |
| 329 | 329 |
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s m -l memory -d 'Memory limit (format: <number>[<unit>], where unit = b, k, m or g)' |
| 330 | 330 |
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l mac-address -d 'Container MAC address (e.g. 92:d0:c6:0a:29:33)' |
| 331 | 331 |
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l memory-swap -d "Total memory usage (memory + swap), set '-1' to disable swap (format: <number>[<unit>], where unit = b, k, m or g)" |
| 332 |
-complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l mount -d 'Attach a filesystem mount to the container' |
|
| 333 | 332 |
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l name -d 'Assign a name to the container' |
| 334 | 333 |
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l net -d 'Set the Network mode for the container' |
| 335 | 334 |
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s P -l publish-all -d 'Publish all exposed ports to random ports on the host interfaces' |
| ... | ... |
@@ -551,7 +551,6 @@ __docker_container_subcommand() {
|
| 551 | 551 |
"($help)--log-driver=[Default driver for container logs]:logging driver:__docker_complete_log_drivers" |
| 552 | 552 |
"($help)*--log-opt=[Log driver specific options]:log driver options:__docker_complete_log_options" |
| 553 | 553 |
"($help)--mac-address=[Container MAC address]:MAC address: " |
| 554 |
- "($help)*--mount=[Attach a filesystem mount to the container]:mount: " |
|
| 555 | 554 |
"($help)--name=[Container name]:name: " |
| 556 | 555 |
"($help)--network=[Connect a container to a network]:network mode:(bridge none container host)" |
| 557 | 556 |
"($help)*--network-alias=[Add network-scoped alias for the container]:alias: " |
| ... | ... |
@@ -1883,6 +1882,147 @@ __docker_service_subcommand() {
|
| 1883 | 1883 |
|
| 1884 | 1884 |
# EO service |
| 1885 | 1885 |
|
| 1886 |
+# BO stack |
|
| 1887 |
+ |
|
| 1888 |
+__docker_stack_complete_ps_filters() {
|
|
| 1889 |
+ [[ $PREFIX = -* ]] && return 1 |
|
| 1890 |
+ integer ret=1 |
|
| 1891 |
+ |
|
| 1892 |
+ if compset -P '*='; then |
|
| 1893 |
+ case "${${words[-1]%=*}#*=}" in
|
|
| 1894 |
+ (desired-state) |
|
| 1895 |
+ state_opts=('accepted' 'running')
|
|
| 1896 |
+ _describe -t state-opts "desired state options" state_opts && ret=0 |
|
| 1897 |
+ ;; |
|
| 1898 |
+ *) |
|
| 1899 |
+ _message 'value' && ret=0 |
|
| 1900 |
+ ;; |
|
| 1901 |
+ esac |
|
| 1902 |
+ else |
|
| 1903 |
+ opts=('desired-state' 'id' 'name')
|
|
| 1904 |
+ _describe -t filter-opts "filter options" opts -qS "=" && ret=0 |
|
| 1905 |
+ fi |
|
| 1906 |
+ |
|
| 1907 |
+ return ret |
|
| 1908 |
+} |
|
| 1909 |
+ |
|
| 1910 |
+__docker_stack_complete_services_filters() {
|
|
| 1911 |
+ [[ $PREFIX = -* ]] && return 1 |
|
| 1912 |
+ integer ret=1 |
|
| 1913 |
+ |
|
| 1914 |
+ if compset -P '*='; then |
|
| 1915 |
+ case "${${words[-1]%=*}#*=}" in
|
|
| 1916 |
+ *) |
|
| 1917 |
+ _message 'value' && ret=0 |
|
| 1918 |
+ ;; |
|
| 1919 |
+ esac |
|
| 1920 |
+ else |
|
| 1921 |
+ opts=('id' 'label' 'name')
|
|
| 1922 |
+ _describe -t filter-opts "filter options" opts -qS "=" && ret=0 |
|
| 1923 |
+ fi |
|
| 1924 |
+ |
|
| 1925 |
+ return ret |
|
| 1926 |
+} |
|
| 1927 |
+ |
|
| 1928 |
+__docker_stacks() {
|
|
| 1929 |
+ [[ $PREFIX = -* ]] && return 1 |
|
| 1930 |
+ integer ret=1 |
|
| 1931 |
+ local line s |
|
| 1932 |
+ declare -a lines stacks |
|
| 1933 |
+ |
|
| 1934 |
+ lines=(${(f)${:-"$(_call_program commands docker $docker_options stack ls)"$'\n'}})
|
|
| 1935 |
+ |
|
| 1936 |
+ # Parse header line to find columns |
|
| 1937 |
+ local i=1 j=1 k header=${lines[1]}
|
|
| 1938 |
+ declare -A begin end |
|
| 1939 |
+ while (( j < ${#header} - 1 )); do
|
|
| 1940 |
+ i=$(( j + ${${header[$j,-1]}[(i)[^ ]]} - 1 ))
|
|
| 1941 |
+ j=$(( i + ${${header[$i,-1]}[(i) ]} - 1 ))
|
|
| 1942 |
+ k=$(( j + ${${header[$j,-1]}[(i)[^ ]]} - 2 ))
|
|
| 1943 |
+ begin[${header[$i,$((j-1))]}]=$i
|
|
| 1944 |
+ end[${header[$i,$((j-1))]}]=$k
|
|
| 1945 |
+ done |
|
| 1946 |
+ end[${header[$i,$((j-1))]}]=-1
|
|
| 1947 |
+ lines=(${lines[2,-1]})
|
|
| 1948 |
+ |
|
| 1949 |
+ # Service ID |
|
| 1950 |
+ for line in $lines; do |
|
| 1951 |
+ s="${line[${begin[ID]},${end[ID]}]%% ##}"
|
|
| 1952 |
+ stacks=($stacks $s) |
|
| 1953 |
+ done |
|
| 1954 |
+ |
|
| 1955 |
+ _describe -t stacks-list "stacks" stacks "$@" && ret=0 |
|
| 1956 |
+ return ret |
|
| 1957 |
+} |
|
| 1958 |
+ |
|
| 1959 |
+__docker_complete_stacks() {
|
|
| 1960 |
+ [[ $PREFIX = -* ]] && return 1 |
|
| 1961 |
+ __docker_stacks "$@" |
|
| 1962 |
+} |
|
| 1963 |
+ |
|
| 1964 |
+__docker_stack_commands() {
|
|
| 1965 |
+ local -a _docker_stack_subcommands |
|
| 1966 |
+ _docker_stack_subcommands=( |
|
| 1967 |
+ "deploy:Deploy a new stack or update an existing stack" |
|
| 1968 |
+ "ls:List stacks" |
|
| 1969 |
+ "ps:List the tasks in the stack" |
|
| 1970 |
+ "rm:Remove the stack" |
|
| 1971 |
+ "services:List the services in the stack" |
|
| 1972 |
+ ) |
|
| 1973 |
+ _describe -t docker-stack-commands "docker stack command" _docker_stack_subcommands |
|
| 1974 |
+} |
|
| 1975 |
+ |
|
| 1976 |
+__docker_stack_subcommand() {
|
|
| 1977 |
+ local -a _command_args opts_help |
|
| 1978 |
+ local expl help="--help" |
|
| 1979 |
+ integer ret=1 |
|
| 1980 |
+ |
|
| 1981 |
+ opts_help=("(: -)--help[Print usage]")
|
|
| 1982 |
+ |
|
| 1983 |
+ case "$words[1]" in |
|
| 1984 |
+ (deploy|up) |
|
| 1985 |
+ _arguments $(__docker_arguments) \ |
|
| 1986 |
+ $opts_help \ |
|
| 1987 |
+ "($help)--bundle-file=[Path to a Distributed Application Bundle file]:dab:_files -g \"*.dab\"" \ |
|
| 1988 |
+ "($help -c --compose-file)"{-c=,--compose-file=}"[Path to a Compose file]:compose file:_files -g \"*.(yml|yaml)\"" \
|
|
| 1989 |
+ "($help)--with-registry-auth[Send registry authentication details to Swarm agents]" \ |
|
| 1990 |
+ "($help -):stack:__docker_complete_stacks" && ret=0 |
|
| 1991 |
+ ;; |
|
| 1992 |
+ (ls|list) |
|
| 1993 |
+ _arguments $(__docker_arguments) \ |
|
| 1994 |
+ $opts_help && ret=0 |
|
| 1995 |
+ ;; |
|
| 1996 |
+ (ps) |
|
| 1997 |
+ _arguments $(__docker_arguments) \ |
|
| 1998 |
+ $opts_help \ |
|
| 1999 |
+ "($help -a --all)"{-a,--all}"[Display all tasks]" \
|
|
| 2000 |
+ "($help)*"{-f=,--filter=}"[Filter output based on conditions provided]:filter:__docker_stack_complete_ps_filters" \
|
|
| 2001 |
+ "($help)--no-resolve[Do not map IDs to Names]" \ |
|
| 2002 |
+ "($help)--no-trunc[Do not truncate output]" \ |
|
| 2003 |
+ "($help -):stack:__docker_complete_stacks" && ret=0 |
|
| 2004 |
+ ;; |
|
| 2005 |
+ (rm|remove|down) |
|
| 2006 |
+ _arguments $(__docker_arguments) \ |
|
| 2007 |
+ $opts_help \ |
|
| 2008 |
+ "($help -):stack:__docker_complete_stacks" && ret=0 |
|
| 2009 |
+ ;; |
|
| 2010 |
+ (services) |
|
| 2011 |
+ _arguments $(__docker_arguments) \ |
|
| 2012 |
+ $opts_help \ |
|
| 2013 |
+ "($help)*"{-f=,--filter=}"[Filter output based on conditions provided]:filter:__docker_stack_complete_services_filters" \
|
|
| 2014 |
+ "($help -q --quiet)"{-q,--quiet}"[Only display IDs]" \
|
|
| 2015 |
+ "($help -):stack:__docker_complete_stacks" && ret=0 |
|
| 2016 |
+ ;; |
|
| 2017 |
+ (help) |
|
| 2018 |
+ _arguments $(__docker_arguments) ":subcommand:__docker_stack_commands" && ret=0 |
|
| 2019 |
+ ;; |
|
| 2020 |
+ esac |
|
| 2021 |
+ |
|
| 2022 |
+ return ret |
|
| 2023 |
+} |
|
| 2024 |
+ |
|
| 2025 |
+# EO stack |
|
| 2026 |
+ |
|
| 1886 | 2027 |
# BO swarm |
| 1887 | 2028 |
|
| 1888 | 2029 |
__docker_swarm_commands() {
|
| ... | ... |
@@ -2451,6 +2591,23 @@ __docker_subcommand() {
|
| 2451 | 2451 |
;; |
| 2452 | 2452 |
esac |
| 2453 | 2453 |
;; |
| 2454 |
+ (stack) |
|
| 2455 |
+ local curcontext="$curcontext" state |
|
| 2456 |
+ _arguments $(__docker_arguments) \ |
|
| 2457 |
+ $opts_help \ |
|
| 2458 |
+ "($help -): :->command" \ |
|
| 2459 |
+ "($help -)*:: :->option-or-argument" && ret=0 |
|
| 2460 |
+ |
|
| 2461 |
+ case $state in |
|
| 2462 |
+ (command) |
|
| 2463 |
+ __docker_stack_commands && ret=0 |
|
| 2464 |
+ ;; |
|
| 2465 |
+ (option-or-argument) |
|
| 2466 |
+ curcontext=${curcontext%:*:*}:docker-${words[-1]}:
|
|
| 2467 |
+ __docker_stack_subcommand && ret=0 |
|
| 2468 |
+ ;; |
|
| 2469 |
+ esac |
|
| 2470 |
+ ;; |
|
| 2454 | 2471 |
(swarm) |
| 2455 | 2472 |
local curcontext="$curcontext" state |
| 2456 | 2473 |
_arguments $(__docker_arguments) \ |
| ... | ... |
@@ -16,6 +16,7 @@ import ( |
| 16 | 16 |
"time" |
| 17 | 17 |
|
| 18 | 18 |
"github.com/Sirupsen/logrus" |
| 19 |
+ "github.com/docker/distribution/digest" |
|
| 19 | 20 |
distreference "github.com/docker/distribution/reference" |
| 20 | 21 |
apierrors "github.com/docker/docker/api/errors" |
| 21 | 22 |
apitypes "github.com/docker/docker/api/types" |
| ... | ... |
@@ -1024,6 +1025,9 @@ func (c *Cluster) GetServices(options apitypes.ServiceListOptions) ([]types.Serv |
| 1024 | 1024 |
// TODO(nishanttotla): After the packages converge, the function must |
| 1025 | 1025 |
// convert distreference.Named -> distreference.Canonical, and the logic simplified. |
| 1026 | 1026 |
func (c *Cluster) imageWithDigestString(ctx context.Context, image string, authConfig *apitypes.AuthConfig) (string, error) {
|
| 1027 |
+ if _, err := digest.ParseDigest(image); err == nil {
|
|
| 1028 |
+ return "", errors.New("image reference is an image ID")
|
|
| 1029 |
+ } |
|
| 1027 | 1030 |
ref, err := distreference.ParseNamed(image) |
| 1028 | 1031 |
if err != nil {
|
| 1029 | 1032 |
return "", err |
| ... | ... |
@@ -64,6 +64,13 @@ func containerSpecFromGRPC(c *swarmapi.ContainerSpec) types.ContainerSpec {
|
| 64 | 64 |
} |
| 65 | 65 |
} |
| 66 | 66 |
} |
| 67 |
+ |
|
| 68 |
+ if m.TmpfsOptions != nil {
|
|
| 69 |
+ mount.TmpfsOptions = &mounttypes.TmpfsOptions{
|
|
| 70 |
+ SizeBytes: m.TmpfsOptions.SizeBytes, |
|
| 71 |
+ Mode: m.TmpfsOptions.Mode, |
|
| 72 |
+ } |
|
| 73 |
+ } |
|
| 67 | 74 |
containerSpec.Mounts = append(containerSpec.Mounts, mount) |
| 68 | 75 |
} |
| 69 | 76 |
|
| ... | ... |
@@ -174,9 +181,7 @@ func containerToGRPC(c types.ContainerSpec) (*swarmapi.ContainerSpec, error) {
|
| 174 | 174 |
mount.BindOptions = &swarmapi.Mount_BindOptions{Propagation: swarmapi.Mount_BindOptions_MountPropagation(mountPropagation)}
|
| 175 | 175 |
} else if string(m.BindOptions.Propagation) != "" {
|
| 176 | 176 |
return nil, fmt.Errorf("invalid MountPropagation: %q", m.BindOptions.Propagation)
|
| 177 |
- |
|
| 178 | 177 |
} |
| 179 |
- |
|
| 180 | 178 |
} |
| 181 | 179 |
|
| 182 | 180 |
if m.VolumeOptions != nil {
|
| ... | ... |
@@ -192,6 +197,13 @@ func containerToGRPC(c types.ContainerSpec) (*swarmapi.ContainerSpec, error) {
|
| 192 | 192 |
} |
| 193 | 193 |
} |
| 194 | 194 |
|
| 195 |
+ if m.TmpfsOptions != nil {
|
|
| 196 |
+ mount.TmpfsOptions = &swarmapi.Mount_TmpfsOptions{
|
|
| 197 |
+ SizeBytes: m.TmpfsOptions.SizeBytes, |
|
| 198 |
+ Mode: m.TmpfsOptions.Mode, |
|
| 199 |
+ } |
|
| 200 |
+ } |
|
| 201 |
+ |
|
| 195 | 202 |
containerSpec.Mounts = append(containerSpec.Mounts, mount) |
| 196 | 203 |
} |
| 197 | 204 |
|
| ... | ... |
@@ -10,6 +10,7 @@ import ( |
| 10 | 10 |
"time" |
| 11 | 11 |
|
| 12 | 12 |
"github.com/Sirupsen/logrus" |
| 13 |
+ "github.com/docker/distribution/digest" |
|
| 13 | 14 |
"github.com/docker/docker/api/server/httputils" |
| 14 | 15 |
"github.com/docker/docker/api/types" |
| 15 | 16 |
"github.com/docker/docker/api/types/backend" |
| ... | ... |
@@ -53,6 +54,11 @@ func newContainerAdapter(b executorpkg.Backend, task *api.Task, secrets exec.Sec |
| 53 | 53 |
func (c *containerAdapter) pullImage(ctx context.Context) error {
|
| 54 | 54 |
spec := c.container.spec() |
| 55 | 55 |
|
| 56 |
+ // Skip pulling if the image is referenced by image ID. |
|
| 57 |
+ if _, err := digest.ParseDigest(spec.Image); err == nil {
|
|
| 58 |
+ return nil |
|
| 59 |
+ } |
|
| 60 |
+ |
|
| 56 | 61 |
// Skip pulling if the image is referenced by digest and already |
| 57 | 62 |
// exists locally. |
| 58 | 63 |
named, err := reference.ParseNamed(spec.Image) |
| ... | ... |
@@ -46,6 +46,11 @@ func merge(userConf, imageConf *containertypes.Config) error {
|
| 46 | 46 |
imageEnvKey := strings.Split(imageEnv, "=")[0] |
| 47 | 47 |
for _, userEnv := range userConf.Env {
|
| 48 | 48 |
userEnvKey := strings.Split(userEnv, "=")[0] |
| 49 |
+ if runtime.GOOS == "windows" {
|
|
| 50 |
+ // Case insensitive environment variables on Windows |
|
| 51 |
+ imageEnvKey = strings.ToUpper(imageEnvKey) |
|
| 52 |
+ userEnvKey = strings.ToUpper(userEnvKey) |
|
| 53 |
+ } |
|
| 49 | 54 |
if imageEnvKey == userEnvKey {
|
| 50 | 55 |
found = true |
| 51 | 56 |
break |
| ... | ... |
@@ -268,11 +268,11 @@ func (daemon *Daemon) verifyContainerSettings(hostConfig *containertypes.HostCon |
| 268 | 268 |
switch p.Name {
|
| 269 | 269 |
case "always", "unless-stopped", "no": |
| 270 | 270 |
if p.MaximumRetryCount != 0 {
|
| 271 |
- return nil, fmt.Errorf("maximum restart count not valid with restart policy of '%s'", p.Name)
|
|
| 271 |
+ return nil, fmt.Errorf("maximum retry count cannot be used with restart policy '%s'", p.Name)
|
|
| 272 | 272 |
} |
| 273 | 273 |
case "on-failure": |
| 274 |
- if p.MaximumRetryCount < 1 {
|
|
| 275 |
- return nil, fmt.Errorf("maximum restart count must be a positive integer")
|
|
| 274 |
+ if p.MaximumRetryCount < 0 {
|
|
| 275 |
+ return nil, fmt.Errorf("maximum retry count cannot be negative")
|
|
| 276 | 276 |
} |
| 277 | 277 |
case "": |
| 278 | 278 |
// do nothing |
| ... | ... |
@@ -40,7 +40,6 @@ import ( |
| 40 | 40 |
"github.com/docker/docker/libcontainerd" |
| 41 | 41 |
"github.com/docker/docker/migrate/v1" |
| 42 | 42 |
"github.com/docker/docker/pkg/fileutils" |
| 43 |
- "github.com/docker/docker/pkg/graphdb" |
|
| 44 | 43 |
"github.com/docker/docker/pkg/idtools" |
| 45 | 44 |
"github.com/docker/docker/pkg/plugingetter" |
| 46 | 45 |
"github.com/docker/docker/pkg/progress" |
| ... | ... |
@@ -158,7 +157,6 @@ func (daemon *Daemon) restore() error {
|
| 158 | 158 |
} |
| 159 | 159 |
} |
| 160 | 160 |
|
| 161 |
- var migrateLegacyLinks bool |
|
| 162 | 161 |
removeContainers := make(map[string]*container.Container) |
| 163 | 162 |
restartContainers := make(map[*container.Container]chan struct{})
|
| 164 | 163 |
activeSandboxes := make(map[string]interface{})
|
| ... | ... |
@@ -190,6 +188,8 @@ func (daemon *Daemon) restore() error {
|
| 190 | 190 |
} |
| 191 | 191 |
} |
| 192 | 192 |
} |
| 193 |
+ |
|
| 194 |
+ var migrateLegacyLinks bool // Not relevant on Windows |
|
| 193 | 195 |
var wg sync.WaitGroup |
| 194 | 196 |
var mapLock sync.Mutex |
| 195 | 197 |
for _, c := range containers {
|
| ... | ... |
@@ -265,24 +265,15 @@ func (daemon *Daemon) restore() error {
|
| 265 | 265 |
return fmt.Errorf("Error initializing network controller: %v", err)
|
| 266 | 266 |
} |
| 267 | 267 |
|
| 268 |
- // migrate any legacy links from sqlite |
|
| 269 |
- linkdbFile := filepath.Join(daemon.root, "linkgraph.db") |
|
| 270 |
- var legacyLinkDB *graphdb.Database |
|
| 268 |
+ // Perform migration of legacy sqlite links (no-op on Windows) |
|
| 271 | 269 |
if migrateLegacyLinks {
|
| 272 |
- legacyLinkDB, err = graphdb.NewSqliteConn(linkdbFile) |
|
| 273 |
- if err != nil {
|
|
| 274 |
- return fmt.Errorf("error connecting to legacy link graph DB %s, container links may be lost: %v", linkdbFile, err)
|
|
| 270 |
+ if err := daemon.sqliteMigration(containers); err != nil {
|
|
| 271 |
+ return err |
|
| 275 | 272 |
} |
| 276 |
- defer legacyLinkDB.Close() |
|
| 277 | 273 |
} |
| 278 | 274 |
|
| 279 | 275 |
// Now that all the containers are registered, register the links |
| 280 | 276 |
for _, c := range containers {
|
| 281 |
- if migrateLegacyLinks {
|
|
| 282 |
- if err := daemon.migrateLegacySqliteLinks(legacyLinkDB, c); err != nil {
|
|
| 283 |
- return err |
|
| 284 |
- } |
|
| 285 |
- } |
|
| 286 | 277 |
if err := daemon.registerLinks(c, c.HostConfig); err != nil {
|
| 287 | 278 |
logrus.Errorf("failed to register link for container %s: %v", c.ID, err)
|
| 288 | 279 |
} |
| ... | ... |
@@ -692,7 +683,11 @@ func NewDaemon(config *Config, registryService registry.Service, containerdRemot |
| 692 | 692 |
|
| 693 | 693 |
// set up SIGUSR1 handler on Unix-like systems, or a Win32 global event |
| 694 | 694 |
// on Windows to dump Go routine stacks |
| 695 |
- d.setupDumpStackTrap(config.Root) |
|
| 695 |
+ stackDumpDir := config.Root |
|
| 696 |
+ if execRoot := config.GetExecRoot(); execRoot != "" {
|
|
| 697 |
+ stackDumpDir = execRoot |
|
| 698 |
+ } |
|
| 699 |
+ d.setupDumpStackTrap(stackDumpDir) |
|
| 696 | 700 |
|
| 697 | 701 |
return d, nil |
| 698 | 702 |
} |
| ... | ... |
@@ -792,7 +787,13 @@ func (daemon *Daemon) Shutdown() error {
|
| 792 | 792 |
}) |
| 793 | 793 |
} |
| 794 | 794 |
|
| 795 |
- // Shutdown plugins after containers. Dont change the order. |
|
| 795 |
+ if daemon.layerStore != nil {
|
|
| 796 |
+ if err := daemon.layerStore.Cleanup(); err != nil {
|
|
| 797 |
+ logrus.Errorf("Error during layer Store.Cleanup(): %v", err)
|
|
| 798 |
+ } |
|
| 799 |
+ } |
|
| 800 |
+ |
|
| 801 |
+ // Shutdown plugins after containers and layerstore. Don't change the order. |
|
| 796 | 802 |
daemon.pluginShutdown() |
| 797 | 803 |
|
| 798 | 804 |
// trigger libnetwork Stop only if it's initialized |
| ... | ... |
@@ -800,12 +801,6 @@ func (daemon *Daemon) Shutdown() error {
|
| 800 | 800 |
daemon.netController.Stop() |
| 801 | 801 |
} |
| 802 | 802 |
|
| 803 |
- if daemon.layerStore != nil {
|
|
| 804 |
- if err := daemon.layerStore.Cleanup(); err != nil {
|
|
| 805 |
- logrus.Errorf("Error during layer Store.Cleanup(): %v", err)
|
|
| 806 |
- } |
|
| 807 |
- } |
|
| 808 |
- |
|
| 809 | 803 |
if err := daemon.cleanupMounts(); err != nil {
|
| 810 | 804 |
return err |
| 811 | 805 |
} |
| ... | ... |
@@ -1,12 +1,9 @@ |
| 1 | 1 |
package daemon |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
- "strings" |
|
| 5 | 4 |
"sync" |
| 6 | 5 |
|
| 7 |
- "github.com/Sirupsen/logrus" |
|
| 8 | 6 |
"github.com/docker/docker/container" |
| 9 |
- "github.com/docker/docker/pkg/graphdb" |
|
| 10 | 7 |
) |
| 11 | 8 |
|
| 12 | 9 |
// linkIndex stores link relationships between containers, including their specified alias |
| ... | ... |
@@ -88,41 +85,3 @@ func (l *linkIndex) delete(container *container.Container) {
|
| 88 | 88 |
delete(l.childIdx, container) |
| 89 | 89 |
l.mu.Unlock() |
| 90 | 90 |
} |
| 91 |
- |
|
| 92 |
-// migrateLegacySqliteLinks migrates sqlite links to use links from HostConfig |
|
| 93 |
-// when sqlite links were used, hostConfig.Links was set to nil |
|
| 94 |
-func (daemon *Daemon) migrateLegacySqliteLinks(db *graphdb.Database, container *container.Container) error {
|
|
| 95 |
- // if links is populated (or an empty slice), then this isn't using sqlite links and can be skipped |
|
| 96 |
- if container.HostConfig == nil || container.HostConfig.Links != nil {
|
|
| 97 |
- return nil |
|
| 98 |
- } |
|
| 99 |
- |
|
| 100 |
- logrus.Debugf("migrating legacy sqlite link info for container: %s", container.ID)
|
|
| 101 |
- |
|
| 102 |
- fullName := container.Name |
|
| 103 |
- if fullName[0] != '/' {
|
|
| 104 |
- fullName = "/" + fullName |
|
| 105 |
- } |
|
| 106 |
- |
|
| 107 |
- // don't use a nil slice, this ensures that the check above will skip once the migration has completed |
|
| 108 |
- links := []string{}
|
|
| 109 |
- children, err := db.Children(fullName, 0) |
|
| 110 |
- if err != nil {
|
|
| 111 |
- if !strings.Contains(err.Error(), "Cannot find child for") {
|
|
| 112 |
- return err |
|
| 113 |
- } |
|
| 114 |
- // else continue... it's ok if we didn't find any children, it'll just be nil and we can continue the migration |
|
| 115 |
- } |
|
| 116 |
- |
|
| 117 |
- for _, child := range children {
|
|
| 118 |
- c, err := daemon.GetContainer(child.Entity.ID()) |
|
| 119 |
- if err != nil {
|
|
| 120 |
- return err |
|
| 121 |
- } |
|
| 122 |
- |
|
| 123 |
- links = append(links, c.Name+":"+child.Edge.Name) |
|
| 124 |
- } |
|
| 125 |
- |
|
| 126 |
- container.HostConfig.Links = links |
|
| 127 |
- return container.WriteHostConfig() |
|
| 128 |
-} |
| 129 | 91 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,72 @@ |
| 0 |
+package daemon |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "fmt" |
|
| 4 |
+ "path/filepath" |
|
| 5 |
+ "strings" |
|
| 6 |
+ |
|
| 7 |
+ "github.com/Sirupsen/logrus" |
|
| 8 |
+ "github.com/docker/docker/container" |
|
| 9 |
+ "github.com/docker/docker/pkg/graphdb" |
|
| 10 |
+) |
|
| 11 |
+ |
|
| 12 |
+// migrateLegacySqliteLinks migrates sqlite links to use links from HostConfig |
|
| 13 |
+// when sqlite links were used, hostConfig.Links was set to nil |
|
| 14 |
+func (daemon *Daemon) migrateLegacySqliteLinks(db *graphdb.Database, container *container.Container) error {
|
|
| 15 |
+ // if links is populated (or an empty slice), then this isn't using sqlite links and can be skipped |
|
| 16 |
+ if container.HostConfig == nil || container.HostConfig.Links != nil {
|
|
| 17 |
+ return nil |
|
| 18 |
+ } |
|
| 19 |
+ |
|
| 20 |
+ logrus.Debugf("migrating legacy sqlite link info for container: %s", container.ID)
|
|
| 21 |
+ |
|
| 22 |
+ fullName := container.Name |
|
| 23 |
+ if fullName[0] != '/' {
|
|
| 24 |
+ fullName = "/" + fullName |
|
| 25 |
+ } |
|
| 26 |
+ |
|
| 27 |
+ // don't use a nil slice, this ensures that the check above will skip once the migration has completed |
|
| 28 |
+ links := []string{}
|
|
| 29 |
+ children, err := db.Children(fullName, 0) |
|
| 30 |
+ if err != nil {
|
|
| 31 |
+ if !strings.Contains(err.Error(), "Cannot find child for") {
|
|
| 32 |
+ return err |
|
| 33 |
+ } |
|
| 34 |
+ // else continue... it's ok if we didn't find any children, it'll just be nil and we can continue the migration |
|
| 35 |
+ } |
|
| 36 |
+ |
|
| 37 |
+ for _, child := range children {
|
|
| 38 |
+ c, err := daemon.GetContainer(child.Entity.ID()) |
|
| 39 |
+ if err != nil {
|
|
| 40 |
+ return err |
|
| 41 |
+ } |
|
| 42 |
+ |
|
| 43 |
+ links = append(links, c.Name+":"+child.Edge.Name) |
|
| 44 |
+ } |
|
| 45 |
+ |
|
| 46 |
+ container.HostConfig.Links = links |
|
| 47 |
+ return container.WriteHostConfig() |
|
| 48 |
+} |
|
| 49 |
+ |
|
| 50 |
+// sqliteMigration performs the link graph DB migration. |
|
| 51 |
+func (daemon *Daemon) sqliteMigration(containers map[string]*container.Container) error {
|
|
| 52 |
+ // migrate any legacy links from sqlite |
|
| 53 |
+ linkdbFile := filepath.Join(daemon.root, "linkgraph.db") |
|
| 54 |
+ var ( |
|
| 55 |
+ legacyLinkDB *graphdb.Database |
|
| 56 |
+ err error |
|
| 57 |
+ ) |
|
| 58 |
+ |
|
| 59 |
+ legacyLinkDB, err = graphdb.NewSqliteConn(linkdbFile) |
|
| 60 |
+ if err != nil {
|
|
| 61 |
+ return fmt.Errorf("error connecting to legacy link graph DB %s, container links may be lost: %v", linkdbFile, err)
|
|
| 62 |
+ } |
|
| 63 |
+ defer legacyLinkDB.Close() |
|
| 64 |
+ |
|
| 65 |
+ for _, c := range containers {
|
|
| 66 |
+ if err := daemon.migrateLegacySqliteLinks(legacyLinkDB, c); err != nil {
|
|
| 67 |
+ return err |
|
| 68 |
+ } |
|
| 69 |
+ } |
|
| 70 |
+ return nil |
|
| 71 |
+} |
| 0 | 72 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,98 @@ |
| 0 |
+package daemon |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "encoding/json" |
|
| 4 |
+ "io/ioutil" |
|
| 5 |
+ "os" |
|
| 6 |
+ "path" |
|
| 7 |
+ "path/filepath" |
|
| 8 |
+ "testing" |
|
| 9 |
+ |
|
| 10 |
+ containertypes "github.com/docker/docker/api/types/container" |
|
| 11 |
+ "github.com/docker/docker/container" |
|
| 12 |
+ "github.com/docker/docker/pkg/graphdb" |
|
| 13 |
+ "github.com/docker/docker/pkg/stringid" |
|
| 14 |
+) |
|
| 15 |
+ |
|
| 16 |
+func TestMigrateLegacySqliteLinks(t *testing.T) {
|
|
| 17 |
+ tmpDir, err := ioutil.TempDir("", "legacy-qlite-links-test")
|
|
| 18 |
+ if err != nil {
|
|
| 19 |
+ t.Fatal(err) |
|
| 20 |
+ } |
|
| 21 |
+ defer os.RemoveAll(tmpDir) |
|
| 22 |
+ |
|
| 23 |
+ name1 := "test1" |
|
| 24 |
+ c1 := &container.Container{
|
|
| 25 |
+ CommonContainer: container.CommonContainer{
|
|
| 26 |
+ ID: stringid.GenerateNonCryptoID(), |
|
| 27 |
+ Name: name1, |
|
| 28 |
+ HostConfig: &containertypes.HostConfig{},
|
|
| 29 |
+ }, |
|
| 30 |
+ } |
|
| 31 |
+ c1.Root = tmpDir |
|
| 32 |
+ |
|
| 33 |
+ name2 := "test2" |
|
| 34 |
+ c2 := &container.Container{
|
|
| 35 |
+ CommonContainer: container.CommonContainer{
|
|
| 36 |
+ ID: stringid.GenerateNonCryptoID(), |
|
| 37 |
+ Name: name2, |
|
| 38 |
+ }, |
|
| 39 |
+ } |
|
| 40 |
+ |
|
| 41 |
+ store := container.NewMemoryStore() |
|
| 42 |
+ store.Add(c1.ID, c1) |
|
| 43 |
+ store.Add(c2.ID, c2) |
|
| 44 |
+ |
|
| 45 |
+ d := &Daemon{root: tmpDir, containers: store}
|
|
| 46 |
+ db, err := graphdb.NewSqliteConn(filepath.Join(d.root, "linkgraph.db")) |
|
| 47 |
+ if err != nil {
|
|
| 48 |
+ t.Fatal(err) |
|
| 49 |
+ } |
|
| 50 |
+ |
|
| 51 |
+ if _, err := db.Set("/"+name1, c1.ID); err != nil {
|
|
| 52 |
+ t.Fatal(err) |
|
| 53 |
+ } |
|
| 54 |
+ |
|
| 55 |
+ if _, err := db.Set("/"+name2, c2.ID); err != nil {
|
|
| 56 |
+ t.Fatal(err) |
|
| 57 |
+ } |
|
| 58 |
+ |
|
| 59 |
+ alias := "hello" |
|
| 60 |
+ if _, err := db.Set(path.Join(c1.Name, alias), c2.ID); err != nil {
|
|
| 61 |
+ t.Fatal(err) |
|
| 62 |
+ } |
|
| 63 |
+ |
|
| 64 |
+ if err := d.migrateLegacySqliteLinks(db, c1); err != nil {
|
|
| 65 |
+ t.Fatal(err) |
|
| 66 |
+ } |
|
| 67 |
+ |
|
| 68 |
+ if len(c1.HostConfig.Links) != 1 {
|
|
| 69 |
+ t.Fatal("expected links to be populated but is empty")
|
|
| 70 |
+ } |
|
| 71 |
+ |
|
| 72 |
+ expected := name2 + ":" + alias |
|
| 73 |
+ actual := c1.HostConfig.Links[0] |
|
| 74 |
+ if actual != expected {
|
|
| 75 |
+ t.Fatalf("got wrong link value, expected: %q, got: %q", expected, actual)
|
|
| 76 |
+ } |
|
| 77 |
+ |
|
| 78 |
+ // ensure this is persisted |
|
| 79 |
+ b, err := ioutil.ReadFile(filepath.Join(c1.Root, "hostconfig.json")) |
|
| 80 |
+ if err != nil {
|
|
| 81 |
+ t.Fatal(err) |
|
| 82 |
+ } |
|
| 83 |
+ type hc struct {
|
|
| 84 |
+ Links []string |
|
| 85 |
+ } |
|
| 86 |
+ var cfg hc |
|
| 87 |
+ if err := json.Unmarshal(b, &cfg); err != nil {
|
|
| 88 |
+ t.Fatal(err) |
|
| 89 |
+ } |
|
| 90 |
+ |
|
| 91 |
+ if len(cfg.Links) != 1 {
|
|
| 92 |
+ t.Fatalf("expected one entry in links, got: %d", len(cfg.Links))
|
|
| 93 |
+ } |
|
| 94 |
+ if cfg.Links[0] != expected { // same expected as above
|
|
| 95 |
+ t.Fatalf("got wrong link value, expected: %q, got: %q", expected, cfg.Links[0])
|
|
| 96 |
+ } |
|
| 97 |
+} |
| 0 | 98 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,10 @@ |
| 0 |
+// +build !linux |
|
| 1 |
+ |
|
| 2 |
+package daemon |
|
| 3 |
+ |
|
| 4 |
+import "github.com/docker/docker/container" |
|
| 5 |
+ |
|
| 6 |
+// sqliteMigration performs the link graph DB migration. No-op on platforms other than Linux |
|
| 7 |
+func (daemon *Daemon) sqliteMigration(_ map[string]*container.Container) error {
|
|
| 8 |
+ return nil |
|
| 9 |
+} |
| 0 | 10 |
deleted file mode 100644 |
| ... | ... |
@@ -1,98 +0,0 @@ |
| 1 |
-package daemon |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "encoding/json" |
|
| 5 |
- "io/ioutil" |
|
| 6 |
- "os" |
|
| 7 |
- "path" |
|
| 8 |
- "path/filepath" |
|
| 9 |
- "testing" |
|
| 10 |
- |
|
| 11 |
- containertypes "github.com/docker/docker/api/types/container" |
|
| 12 |
- "github.com/docker/docker/container" |
|
| 13 |
- "github.com/docker/docker/pkg/graphdb" |
|
| 14 |
- "github.com/docker/docker/pkg/stringid" |
|
| 15 |
-) |
|
| 16 |
- |
|
| 17 |
-func TestMigrateLegacySqliteLinks(t *testing.T) {
|
|
| 18 |
- tmpDir, err := ioutil.TempDir("", "legacy-qlite-links-test")
|
|
| 19 |
- if err != nil {
|
|
| 20 |
- t.Fatal(err) |
|
| 21 |
- } |
|
| 22 |
- defer os.RemoveAll(tmpDir) |
|
| 23 |
- |
|
| 24 |
- name1 := "test1" |
|
| 25 |
- c1 := &container.Container{
|
|
| 26 |
- CommonContainer: container.CommonContainer{
|
|
| 27 |
- ID: stringid.GenerateNonCryptoID(), |
|
| 28 |
- Name: name1, |
|
| 29 |
- HostConfig: &containertypes.HostConfig{},
|
|
| 30 |
- }, |
|
| 31 |
- } |
|
| 32 |
- c1.Root = tmpDir |
|
| 33 |
- |
|
| 34 |
- name2 := "test2" |
|
| 35 |
- c2 := &container.Container{
|
|
| 36 |
- CommonContainer: container.CommonContainer{
|
|
| 37 |
- ID: stringid.GenerateNonCryptoID(), |
|
| 38 |
- Name: name2, |
|
| 39 |
- }, |
|
| 40 |
- } |
|
| 41 |
- |
|
| 42 |
- store := container.NewMemoryStore() |
|
| 43 |
- store.Add(c1.ID, c1) |
|
| 44 |
- store.Add(c2.ID, c2) |
|
| 45 |
- |
|
| 46 |
- d := &Daemon{root: tmpDir, containers: store}
|
|
| 47 |
- db, err := graphdb.NewSqliteConn(filepath.Join(d.root, "linkgraph.db")) |
|
| 48 |
- if err != nil {
|
|
| 49 |
- t.Fatal(err) |
|
| 50 |
- } |
|
| 51 |
- |
|
| 52 |
- if _, err := db.Set("/"+name1, c1.ID); err != nil {
|
|
| 53 |
- t.Fatal(err) |
|
| 54 |
- } |
|
| 55 |
- |
|
| 56 |
- if _, err := db.Set("/"+name2, c2.ID); err != nil {
|
|
| 57 |
- t.Fatal(err) |
|
| 58 |
- } |
|
| 59 |
- |
|
| 60 |
- alias := "hello" |
|
| 61 |
- if _, err := db.Set(path.Join(c1.Name, alias), c2.ID); err != nil {
|
|
| 62 |
- t.Fatal(err) |
|
| 63 |
- } |
|
| 64 |
- |
|
| 65 |
- if err := d.migrateLegacySqliteLinks(db, c1); err != nil {
|
|
| 66 |
- t.Fatal(err) |
|
| 67 |
- } |
|
| 68 |
- |
|
| 69 |
- if len(c1.HostConfig.Links) != 1 {
|
|
| 70 |
- t.Fatal("expected links to be populated but is empty")
|
|
| 71 |
- } |
|
| 72 |
- |
|
| 73 |
- expected := name2 + ":" + alias |
|
| 74 |
- actual := c1.HostConfig.Links[0] |
|
| 75 |
- if actual != expected {
|
|
| 76 |
- t.Fatalf("got wrong link value, expected: %q, got: %q", expected, actual)
|
|
| 77 |
- } |
|
| 78 |
- |
|
| 79 |
- // ensure this is persisted |
|
| 80 |
- b, err := ioutil.ReadFile(filepath.Join(c1.Root, "hostconfig.json")) |
|
| 81 |
- if err != nil {
|
|
| 82 |
- t.Fatal(err) |
|
| 83 |
- } |
|
| 84 |
- type hc struct {
|
|
| 85 |
- Links []string |
|
| 86 |
- } |
|
| 87 |
- var cfg hc |
|
| 88 |
- if err := json.Unmarshal(b, &cfg); err != nil {
|
|
| 89 |
- t.Fatal(err) |
|
| 90 |
- } |
|
| 91 |
- |
|
| 92 |
- if len(cfg.Links) != 1 {
|
|
| 93 |
- t.Fatalf("expected one entry in links, got: %d", len(cfg.Links))
|
|
| 94 |
- } |
|
| 95 |
- if cfg.Links[0] != expected { // same expected as above
|
|
| 96 |
- t.Fatalf("got wrong link value, expected: %q, got: %q", expected, cfg.Links[0])
|
|
| 97 |
- } |
|
| 98 |
-} |
| 56 | 56 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,26 @@ |
| 0 |
+package logger |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "reflect" |
|
| 4 |
+ "testing" |
|
| 5 |
+ "time" |
|
| 6 |
+) |
|
| 7 |
+ |
|
| 8 |
+func TestCopyMessage(t *testing.T) {
|
|
| 9 |
+ msg := &Message{
|
|
| 10 |
+ Line: []byte("test line."),
|
|
| 11 |
+ Source: "stdout", |
|
| 12 |
+ Timestamp: time.Now(), |
|
| 13 |
+ Attrs: LogAttributes{
|
|
| 14 |
+ "key1": "val1", |
|
| 15 |
+ "key2": "val2", |
|
| 16 |
+ "key3": "val3", |
|
| 17 |
+ }, |
|
| 18 |
+ Partial: true, |
|
| 19 |
+ } |
|
| 20 |
+ |
|
| 21 |
+ m := CopyMessage(msg) |
|
| 22 |
+ if !reflect.DeepEqual(m, msg) {
|
|
| 23 |
+ t.Fatalf("CopyMessage failed to copy message")
|
|
| 24 |
+ } |
|
| 25 |
+} |
| ... | ... |
@@ -6,6 +6,7 @@ import ( |
| 6 | 6 |
"syscall" |
| 7 | 7 |
|
| 8 | 8 |
"github.com/Sirupsen/logrus" |
| 9 |
+ "github.com/docker/distribution" |
|
| 9 | 10 |
"github.com/docker/distribution/registry/api/errcode" |
| 10 | 11 |
"github.com/docker/distribution/registry/api/v2" |
| 11 | 12 |
"github.com/docker/distribution/registry/client" |
| ... | ... |
@@ -139,6 +140,9 @@ func retryOnError(err error) error {
|
| 139 | 139 |
case *client.UnexpectedHTTPResponseError: |
| 140 | 140 |
return xfer.DoNotRetry{Err: err}
|
| 141 | 141 |
case error: |
| 142 |
+ if err == distribution.ErrBlobUnknown {
|
|
| 143 |
+ return xfer.DoNotRetry{Err: err}
|
|
| 144 |
+ } |
|
| 142 | 145 |
if strings.Contains(err.Error(), strings.ToLower(syscall.ENOSPC.Error())) {
|
| 143 | 146 |
return xfer.DoNotRetry{Err: err}
|
| 144 | 147 |
} |
| ... | ... |
@@ -189,9 +189,6 @@ func (ld *v2LayerDescriptor) Download(ctx context.Context, progressOutput progre |
| 189 | 189 |
layerDownload, err := ld.open(ctx) |
| 190 | 190 |
if err != nil {
|
| 191 | 191 |
logrus.Errorf("Error initiating layer download: %v", err)
|
| 192 |
- if err == distribution.ErrBlobUnknown {
|
|
| 193 |
- return nil, 0, xfer.DoNotRetry{Err: err}
|
|
| 194 |
- } |
|
| 195 | 192 |
return nil, 0, retryOnError(err) |
| 196 | 193 |
} |
| 197 | 194 |
|
| ... | ... |
@@ -523,6 +523,7 @@ func (pd *v2PushDescriptor) layerAlreadyExists( |
| 523 | 523 |
layerDigests = append(layerDigests, meta.Digest) |
| 524 | 524 |
} |
| 525 | 525 |
|
| 526 |
+attempts: |
|
| 526 | 527 |
for _, dgst := range layerDigests {
|
| 527 | 528 |
meta := digestToMetadata[dgst] |
| 528 | 529 |
logrus.Debugf("Checking for presence of layer %s (%s) in %s", diffID, dgst, pd.repoInfo.FullName())
|
| ... | ... |
@@ -541,15 +542,14 @@ func (pd *v2PushDescriptor) layerAlreadyExists( |
| 541 | 541 |
} |
| 542 | 542 |
desc.MediaType = schema2.MediaTypeLayer |
| 543 | 543 |
exists = true |
| 544 |
- break |
|
| 544 |
+ break attempts |
|
| 545 | 545 |
case distribution.ErrBlobUnknown: |
| 546 | 546 |
if meta.SourceRepository == pd.repoInfo.FullName() {
|
| 547 | 547 |
// remove the mapping to the target repository |
| 548 | 548 |
pd.v2MetadataService.Remove(*meta) |
| 549 | 549 |
} |
| 550 | 550 |
default: |
| 551 |
- progress.Update(progressOutput, pd.ID(), "Image push failed") |
|
| 552 |
- return desc, false, retryOnError(err) |
|
| 551 |
+ logrus.WithError(err).Debugf("Failed to check for presence of layer %s (%s) in %s", diffID, dgst, pd.repoInfo.FullName())
|
|
| 553 | 552 |
} |
| 554 | 553 |
} |
| 555 | 554 |
|
| ... | ... |
@@ -180,7 +180,7 @@ func TestLayerAlreadyExists(t *testing.T) {
|
| 180 | 180 |
maxExistenceChecks: 1, |
| 181 | 181 |
metadata: []metadata.V2Metadata{{Digest: digest.Digest("apple"), SourceRepository: "docker.io/library/busybox"}},
|
| 182 | 182 |
remoteErrors: map[digest.Digest]error{digest.Digest("apple"): distribution.ErrAccessDenied},
|
| 183 |
- expectedError: distribution.ErrAccessDenied, |
|
| 183 |
+ expectedError: nil, |
|
| 184 | 184 |
expectedRequests: []string{"apple"},
|
| 185 | 185 |
}, |
| 186 | 186 |
{
|
| ... | ... |
@@ -310,7 +310,7 @@ func TestLayerAlreadyExists(t *testing.T) {
|
| 310 | 310 |
expectedRemovals: []metadata.V2Metadata{taggedMetadata("key3", "apple", "docker.io/library/busybox")},
|
| 311 | 311 |
}, |
| 312 | 312 |
{
|
| 313 |
- name: "stop on first error", |
|
| 313 |
+ name: "don't stop on first error", |
|
| 314 | 314 |
targetRepo: "user/app", |
| 315 | 315 |
hmacKey: "key", |
| 316 | 316 |
metadata: []metadata.V2Metadata{
|
| ... | ... |
@@ -321,9 +321,12 @@ func TestLayerAlreadyExists(t *testing.T) {
|
| 321 | 321 |
maxExistenceChecks: 3, |
| 322 | 322 |
remoteErrors: map[digest.Digest]error{"orange": distribution.ErrAccessDenied},
|
| 323 | 323 |
remoteBlobs: map[digest.Digest]distribution.Descriptor{digest.Digest("apple"): {}},
|
| 324 |
- expectedError: distribution.ErrAccessDenied, |
|
| 325 |
- expectedRequests: []string{"plum", "orange"},
|
|
| 326 |
- expectedRemovals: []metadata.V2Metadata{taggedMetadata("key", "plum", "docker.io/user/app")},
|
|
| 324 |
+ expectedError: nil, |
|
| 325 |
+ expectedRequests: []string{"plum", "orange", "banana"},
|
|
| 326 |
+ expectedRemovals: []metadata.V2Metadata{
|
|
| 327 |
+ taggedMetadata("key", "plum", "docker.io/user/app"),
|
|
| 328 |
+ taggedMetadata("key", "banana", "docker.io/user/app"),
|
|
| 329 |
+ }, |
|
| 327 | 330 |
}, |
| 328 | 331 |
{
|
| 329 | 332 |
name: "remove outdated metadata", |
| ... | ... |
@@ -16,9 +16,7 @@ redirect_from: |
| 16 | 16 |
will be rejected. |
| 17 | 17 |
--> |
| 18 | 18 |
|
| 19 |
-# Docker Engine API v1.18 |
|
| 20 |
- |
|
| 21 |
-# 1. Brief introduction |
|
| 19 |
+## 1. Brief introduction |
|
| 22 | 20 |
|
| 23 | 21 |
- The daemon listens on `unix:///var/run/docker.sock` but you can |
| 24 | 22 |
[Bind Docker to another host/port or a Unix socket](../commandline/dockerd.md#bind-docker-to-another-host-port-or-a-unix-socket). |
| ... | ... |
@@ -26,11 +24,11 @@ redirect_from: |
| 26 | 26 |
or `pull`, the HTTP connection is hijacked to transport `STDOUT`, |
| 27 | 27 |
`STDIN` and `STDERR`. |
| 28 | 28 |
|
| 29 |
-# 2. Endpoints |
|
| 29 |
+## 2. Endpoints |
|
| 30 | 30 |
|
| 31 |
-## 2.1 Containers |
|
| 31 |
+### 2.1 Containers |
|
| 32 | 32 |
|
| 33 |
-### List containers |
|
| 33 |
+#### List containers |
|
| 34 | 34 |
|
| 35 | 35 |
`GET /containers/json` |
| 36 | 36 |
|
| ... | ... |
@@ -123,7 +121,7 @@ List containers |
| 123 | 123 |
- **400** – bad parameter |
| 124 | 124 |
- **500** – server error |
| 125 | 125 |
|
| 126 |
-### Create a container |
|
| 126 |
+#### Create a container |
|
| 127 | 127 |
|
| 128 | 128 |
`POST /containers/create` |
| 129 | 129 |
|
| ... | ... |
@@ -310,7 +308,7 @@ Create a container |
| 310 | 310 |
- **409** – conflict |
| 311 | 311 |
- **500** – server error |
| 312 | 312 |
|
| 313 |
-### Inspect a container |
|
| 313 |
+#### Inspect a container |
|
| 314 | 314 |
|
| 315 | 315 |
`GET /containers/(id or name)/json` |
| 316 | 316 |
|
| ... | ... |
@@ -443,7 +441,7 @@ Return low-level information on the container `id` |
| 443 | 443 |
- **404** – no such container |
| 444 | 444 |
- **500** – server error |
| 445 | 445 |
|
| 446 |
-### List processes running inside a container |
|
| 446 |
+#### List processes running inside a container |
|
| 447 | 447 |
|
| 448 | 448 |
`GET /containers/(id or name)/top` |
| 449 | 449 |
|
| ... | ... |
@@ -507,7 +505,7 @@ supported on Windows. |
| 507 | 507 |
- **404** – no such container |
| 508 | 508 |
- **500** – server error |
| 509 | 509 |
|
| 510 |
-### Get container logs |
|
| 510 |
+#### Get container logs |
|
| 511 | 511 |
|
| 512 | 512 |
`GET /containers/(id or name)/logs` |
| 513 | 513 |
|
| ... | ... |
@@ -547,7 +545,7 @@ Get `stdout` and `stderr` logs from the container ``id`` |
| 547 | 547 |
- **404** – no such container |
| 548 | 548 |
- **500** – server error |
| 549 | 549 |
|
| 550 |
-### Inspect changes on a container's filesystem |
|
| 550 |
+#### Inspect changes on a container's filesystem |
|
| 551 | 551 |
|
| 552 | 552 |
`GET /containers/(id or name)/changes` |
| 553 | 553 |
|
| ... | ... |
@@ -589,7 +587,7 @@ Values for `Kind`: |
| 589 | 589 |
- **404** – no such container |
| 590 | 590 |
- **500** – server error |
| 591 | 591 |
|
| 592 |
-### Export a container |
|
| 592 |
+#### Export a container |
|
| 593 | 593 |
|
| 594 | 594 |
`GET /containers/(id or name)/export` |
| 595 | 595 |
|
| ... | ... |
@@ -614,7 +612,7 @@ Export the contents of container `id` |
| 614 | 614 |
- **404** – no such container |
| 615 | 615 |
- **500** – server error |
| 616 | 616 |
|
| 617 |
-### Get container stats based on resource usage |
|
| 617 |
+#### Get container stats based on resource usage |
|
| 618 | 618 |
|
| 619 | 619 |
`GET /containers/(id or name)/stats` |
| 620 | 620 |
|
| ... | ... |
@@ -702,7 +700,7 @@ This endpoint returns a live stream of a container's resource usage statistics. |
| 702 | 702 |
- **404** – no such container |
| 703 | 703 |
- **500** – server error |
| 704 | 704 |
|
| 705 |
-### Resize a container TTY |
|
| 705 |
+#### Resize a container TTY |
|
| 706 | 706 |
|
| 707 | 707 |
`POST /containers/(id or name)/resize?h=<height>&w=<width>` |
| 708 | 708 |
|
| ... | ... |
@@ -729,7 +727,7 @@ Resize the TTY for container with `id`. You must restart the container for the |
| 729 | 729 |
- **404** – No such container |
| 730 | 730 |
- **500** – Cannot resize container |
| 731 | 731 |
|
| 732 |
-### Start a container |
|
| 732 |
+#### Start a container |
|
| 733 | 733 |
|
| 734 | 734 |
`POST /containers/(id or name)/start` |
| 735 | 735 |
|
| ... | ... |
@@ -754,7 +752,7 @@ Start the container `id` |
| 754 | 754 |
- **404** – no such container |
| 755 | 755 |
- **500** – server error |
| 756 | 756 |
|
| 757 |
-### Stop a container |
|
| 757 |
+#### Stop a container |
|
| 758 | 758 |
|
| 759 | 759 |
`POST /containers/(id or name)/stop` |
| 760 | 760 |
|
| ... | ... |
@@ -779,7 +777,7 @@ Stop the container `id` |
| 779 | 779 |
- **404** – no such container |
| 780 | 780 |
- **500** – server error |
| 781 | 781 |
|
| 782 |
-### Restart a container |
|
| 782 |
+#### Restart a container |
|
| 783 | 783 |
|
| 784 | 784 |
`POST /containers/(id or name)/restart` |
| 785 | 785 |
|
| ... | ... |
@@ -803,7 +801,7 @@ Restart the container `id` |
| 803 | 803 |
- **404** – no such container |
| 804 | 804 |
- **500** – server error |
| 805 | 805 |
|
| 806 |
-### Kill a container |
|
| 806 |
+#### Kill a container |
|
| 807 | 807 |
|
| 808 | 808 |
`POST /containers/(id or name)/kill` |
| 809 | 809 |
|
| ... | ... |
@@ -828,7 +826,7 @@ Kill the container `id` |
| 828 | 828 |
- **404** – no such container |
| 829 | 829 |
- **500** – server error |
| 830 | 830 |
|
| 831 |
-### Rename a container |
|
| 831 |
+#### Rename a container |
|
| 832 | 832 |
|
| 833 | 833 |
`POST /containers/(id or name)/rename` |
| 834 | 834 |
|
| ... | ... |
@@ -853,7 +851,7 @@ Rename the container `id` to a `new_name` |
| 853 | 853 |
- **409** - conflict name already assigned |
| 854 | 854 |
- **500** – server error |
| 855 | 855 |
|
| 856 |
-### Pause a container |
|
| 856 |
+#### Pause a container |
|
| 857 | 857 |
|
| 858 | 858 |
`POST /containers/(id or name)/pause` |
| 859 | 859 |
|
| ... | ... |
@@ -873,7 +871,7 @@ Pause the container `id` |
| 873 | 873 |
- **404** – no such container |
| 874 | 874 |
- **500** – server error |
| 875 | 875 |
|
| 876 |
-### Unpause a container |
|
| 876 |
+#### Unpause a container |
|
| 877 | 877 |
|
| 878 | 878 |
`POST /containers/(id or name)/unpause` |
| 879 | 879 |
|
| ... | ... |
@@ -893,7 +891,7 @@ Unpause the container `id` |
| 893 | 893 |
- **404** – no such container |
| 894 | 894 |
- **500** – server error |
| 895 | 895 |
|
| 896 |
-### Attach to a container |
|
| 896 |
+#### Attach to a container |
|
| 897 | 897 |
|
| 898 | 898 |
`POST /containers/(id or name)/attach` |
| 899 | 899 |
|
| ... | ... |
@@ -978,7 +976,7 @@ The simplest way to implement the Attach protocol is the following: |
| 978 | 978 |
4. Read the extracted size and output it on the correct output. |
| 979 | 979 |
5. Goto 1. |
| 980 | 980 |
|
| 981 |
-### Attach to a container (websocket) |
|
| 981 |
+#### Attach to a container (websocket) |
|
| 982 | 982 |
|
| 983 | 983 |
`GET /containers/(id or name)/attach/ws` |
| 984 | 984 |
|
| ... | ... |
@@ -1015,7 +1013,7 @@ Implements websocket protocol handshake according to [RFC 6455](http://tools.iet |
| 1015 | 1015 |
- **404** – no such container |
| 1016 | 1016 |
- **500** – server error |
| 1017 | 1017 |
|
| 1018 |
-### Wait a container |
|
| 1018 |
+#### Wait a container |
|
| 1019 | 1019 |
|
| 1020 | 1020 |
`POST /containers/(id or name)/wait` |
| 1021 | 1021 |
|
| ... | ... |
@@ -1038,7 +1036,7 @@ Block until container `id` stops, then returns the exit code |
| 1038 | 1038 |
- **404** – no such container |
| 1039 | 1039 |
- **500** – server error |
| 1040 | 1040 |
|
| 1041 |
-### Remove a container |
|
| 1041 |
+#### Remove a container |
|
| 1042 | 1042 |
|
| 1043 | 1043 |
`DELETE /containers/(id or name)` |
| 1044 | 1044 |
|
| ... | ... |
@@ -1067,7 +1065,7 @@ Remove the container `id` from the filesystem |
| 1067 | 1067 |
- **409** – conflict |
| 1068 | 1068 |
- **500** – server error |
| 1069 | 1069 |
|
| 1070 |
-### Copy files or folders from a container |
|
| 1070 |
+#### Copy files or folders from a container |
|
| 1071 | 1071 |
|
| 1072 | 1072 |
`POST /containers/(id or name)/copy` |
| 1073 | 1073 |
|
| ... | ... |
@@ -1097,9 +1095,9 @@ Copy files or folders of container `id` |
| 1097 | 1097 |
- **404** – no such container |
| 1098 | 1098 |
- **500** – server error |
| 1099 | 1099 |
|
| 1100 |
-## 2.2 Images |
|
| 1100 |
+### 2.2 Images |
|
| 1101 | 1101 |
|
| 1102 |
-### List Images |
|
| 1102 |
+#### List Images |
|
| 1103 | 1103 |
|
| 1104 | 1104 |
`GET /images/json` |
| 1105 | 1105 |
|
| ... | ... |
@@ -1185,7 +1183,7 @@ references on the command line. |
| 1185 | 1185 |
- `label=key` or `label="key=value"` of an image label |
| 1186 | 1186 |
- **filter** - only return images with the specified name |
| 1187 | 1187 |
|
| 1188 |
-### Build image from a Dockerfile |
|
| 1188 |
+#### Build image from a Dockerfile |
|
| 1189 | 1189 |
|
| 1190 | 1190 |
`POST /build` |
| 1191 | 1191 |
|
| ... | ... |
@@ -1256,7 +1254,7 @@ or being killed. |
| 1256 | 1256 |
- **200** – no error |
| 1257 | 1257 |
- **500** – server error |
| 1258 | 1258 |
|
| 1259 |
-### Create an image |
|
| 1259 |
+#### Create an image |
|
| 1260 | 1260 |
|
| 1261 | 1261 |
`POST /images/create` |
| 1262 | 1262 |
|
| ... | ... |
@@ -1300,7 +1298,7 @@ a base64-encoded AuthConfig object. |
| 1300 | 1300 |
|
| 1301 | 1301 |
|
| 1302 | 1302 |
|
| 1303 |
-### Inspect an image |
|
| 1303 |
+#### Inspect an image |
|
| 1304 | 1304 |
|
| 1305 | 1305 |
`GET /images/(name)/json` |
| 1306 | 1306 |
|
| ... | ... |
@@ -1351,7 +1349,7 @@ Return low-level information on the image `name` |
| 1351 | 1351 |
- **404** – no such image |
| 1352 | 1352 |
- **500** – server error |
| 1353 | 1353 |
|
| 1354 |
-### Get the history of an image |
|
| 1354 |
+#### Get the history of an image |
|
| 1355 | 1355 |
|
| 1356 | 1356 |
`GET /images/(name)/history` |
| 1357 | 1357 |
|
| ... | ... |
@@ -1385,7 +1383,7 @@ Return the history of the image `name` |
| 1385 | 1385 |
- **404** – no such image |
| 1386 | 1386 |
- **500** – server error |
| 1387 | 1387 |
|
| 1388 |
-### Push an image on the registry |
|
| 1388 |
+#### Push an image on the registry |
|
| 1389 | 1389 |
|
| 1390 | 1390 |
`POST /images/(name)/push` |
| 1391 | 1391 |
|
| ... | ... |
@@ -1428,7 +1426,7 @@ then be used in the URL. This duplicates the command line's flow. |
| 1428 | 1428 |
- **404** – no such image |
| 1429 | 1429 |
- **500** – server error |
| 1430 | 1430 |
|
| 1431 |
-### Tag an image into a repository |
|
| 1431 |
+#### Tag an image into a repository |
|
| 1432 | 1432 |
|
| 1433 | 1433 |
`POST /images/(name)/tag` |
| 1434 | 1434 |
|
| ... | ... |
@@ -1456,7 +1454,7 @@ Tag the image `name` into a repository |
| 1456 | 1456 |
- **409** – conflict |
| 1457 | 1457 |
- **500** – server error |
| 1458 | 1458 |
|
| 1459 |
-### Remove an image |
|
| 1459 |
+#### Remove an image |
|
| 1460 | 1460 |
|
| 1461 | 1461 |
`DELETE /images/(name)` |
| 1462 | 1462 |
|
| ... | ... |
@@ -1489,7 +1487,7 @@ Remove the image `name` from the filesystem |
| 1489 | 1489 |
- **409** – conflict |
| 1490 | 1490 |
- **500** – server error |
| 1491 | 1491 |
|
| 1492 |
-### Search images |
|
| 1492 |
+#### Search images |
|
| 1493 | 1493 |
|
| 1494 | 1494 |
`GET /images/search` |
| 1495 | 1495 |
|
| ... | ... |
@@ -1542,9 +1540,9 @@ Search for an image on [Docker Hub](https://hub.docker.com). |
| 1542 | 1542 |
- **200** – no error |
| 1543 | 1543 |
- **500** – server error |
| 1544 | 1544 |
|
| 1545 |
-## 2.3 Misc |
|
| 1545 |
+### 2.3 Misc |
|
| 1546 | 1546 |
|
| 1547 |
-### Check auth configuration |
|
| 1547 |
+#### Check auth configuration |
|
| 1548 | 1548 |
|
| 1549 | 1549 |
`POST /auth` |
| 1550 | 1550 |
|
| ... | ... |
@@ -1572,7 +1570,7 @@ Get the default username and email |
| 1572 | 1572 |
- **204** – no error |
| 1573 | 1573 |
- **500** – server error |
| 1574 | 1574 |
|
| 1575 |
-### Display system-wide information |
|
| 1575 |
+#### Display system-wide information |
|
| 1576 | 1576 |
|
| 1577 | 1577 |
`GET /info` |
| 1578 | 1578 |
|
| ... | ... |
@@ -1637,7 +1635,7 @@ Display system-wide information |
| 1637 | 1637 |
- **200** – no error |
| 1638 | 1638 |
- **500** – server error |
| 1639 | 1639 |
|
| 1640 |
-### Show the docker version information |
|
| 1640 |
+#### Show the docker version information |
|
| 1641 | 1641 |
|
| 1642 | 1642 |
`GET /version` |
| 1643 | 1643 |
|
| ... | ... |
@@ -1667,7 +1665,7 @@ Show the docker version information |
| 1667 | 1667 |
- **200** – no error |
| 1668 | 1668 |
- **500** – server error |
| 1669 | 1669 |
|
| 1670 |
-### Ping the docker server |
|
| 1670 |
+#### Ping the docker server |
|
| 1671 | 1671 |
|
| 1672 | 1672 |
`GET /_ping` |
| 1673 | 1673 |
|
| ... | ... |
@@ -1689,7 +1687,7 @@ Ping the docker server |
| 1689 | 1689 |
- **200** - no error |
| 1690 | 1690 |
- **500** - server error |
| 1691 | 1691 |
|
| 1692 |
-### Create a new image from a container's changes |
|
| 1692 |
+#### Create a new image from a container's changes |
|
| 1693 | 1693 |
|
| 1694 | 1694 |
`POST /commit` |
| 1695 | 1695 |
|
| ... | ... |
@@ -1751,7 +1749,7 @@ Create a new image from a container's changes |
| 1751 | 1751 |
- **404** – no such container |
| 1752 | 1752 |
- **500** – server error |
| 1753 | 1753 |
|
| 1754 |
-### Monitor Docker's events |
|
| 1754 |
+#### Monitor Docker's events |
|
| 1755 | 1755 |
|
| 1756 | 1756 |
`GET /events` |
| 1757 | 1757 |
|
| ... | ... |
@@ -1793,7 +1791,7 @@ Docker images report the following events: |
| 1793 | 1793 |
- **200** – no error |
| 1794 | 1794 |
- **500** – server error |
| 1795 | 1795 |
|
| 1796 |
-### Get a tarball containing all images in a repository |
|
| 1796 |
+#### Get a tarball containing all images in a repository |
|
| 1797 | 1797 |
|
| 1798 | 1798 |
`GET /images/(name)/get` |
| 1799 | 1799 |
|
| ... | ... |
@@ -1823,7 +1821,7 @@ See the [image tarball format](#image-tarball-format) for more details. |
| 1823 | 1823 |
- **200** – no error |
| 1824 | 1824 |
- **500** – server error |
| 1825 | 1825 |
|
| 1826 |
-### Get a tarball containing all images |
|
| 1826 |
+#### Get a tarball containing all images |
|
| 1827 | 1827 |
|
| 1828 | 1828 |
`GET /images/get` |
| 1829 | 1829 |
|
| ... | ... |
@@ -1852,7 +1850,7 @@ See the [image tarball format](#image-tarball-format) for more details. |
| 1852 | 1852 |
- **200** – no error |
| 1853 | 1853 |
- **500** – server error |
| 1854 | 1854 |
|
| 1855 |
-### Load a tarball with a set of images and tags into docker |
|
| 1855 |
+#### Load a tarball with a set of images and tags into docker |
|
| 1856 | 1856 |
|
| 1857 | 1857 |
`POST /images/load` |
| 1858 | 1858 |
|
| ... | ... |
@@ -1875,7 +1873,7 @@ See the [image tarball format](#image-tarball-format) for more details. |
| 1875 | 1875 |
- **200** – no error |
| 1876 | 1876 |
- **500** – server error |
| 1877 | 1877 |
|
| 1878 |
-### Image tarball format |
|
| 1878 |
+#### Image tarball format |
|
| 1879 | 1879 |
|
| 1880 | 1880 |
An image tarball contains one directory per image layer (named using its long ID), |
| 1881 | 1881 |
each containing these files: |
| ... | ... |
@@ -1896,7 +1894,7 @@ the root that contains a list of repository and tag names mapped to layer IDs. |
| 1896 | 1896 |
} |
| 1897 | 1897 |
``` |
| 1898 | 1898 |
|
| 1899 |
-### Exec Create |
|
| 1899 |
+#### Exec Create |
|
| 1900 | 1900 |
|
| 1901 | 1901 |
`POST /containers/(id or name)/exec` |
| 1902 | 1902 |
|
| ... | ... |
@@ -1939,7 +1937,7 @@ Sets up an exec instance in a running container `id` |
| 1939 | 1939 |
- **201** – no error |
| 1940 | 1940 |
- **404** – no such container |
| 1941 | 1941 |
|
| 1942 |
-### Exec Start |
|
| 1942 |
+#### Exec Start |
|
| 1943 | 1943 |
|
| 1944 | 1944 |
`POST /exec/(id)/start` |
| 1945 | 1945 |
|
| ... | ... |
@@ -1980,7 +1978,7 @@ interactive session with the `exec` command. |
| 1980 | 1980 |
|
| 1981 | 1981 |
Similar to the stream behavior of `POST /containers/(id or name)/attach` API |
| 1982 | 1982 |
|
| 1983 |
-### Exec Resize |
|
| 1983 |
+#### Exec Resize |
|
| 1984 | 1984 |
|
| 1985 | 1985 |
`POST /exec/(id)/resize` |
| 1986 | 1986 |
|
| ... | ... |
@@ -2007,7 +2005,7 @@ This API is valid only if `tty` was specified as part of creating and starting t |
| 2007 | 2007 |
- **201** – no error |
| 2008 | 2008 |
- **404** – no such exec instance |
| 2009 | 2009 |
|
| 2010 |
-### Exec Inspect |
|
| 2010 |
+#### Exec Inspect |
|
| 2011 | 2011 |
|
| 2012 | 2012 |
`GET /exec/(id)/json` |
| 2013 | 2013 |
|
| ... | ... |
@@ -2112,9 +2110,9 @@ Return low-level information about the `exec` command `id`. |
| 2112 | 2112 |
- **404** – no such exec instance |
| 2113 | 2113 |
- **500** - server error |
| 2114 | 2114 |
|
| 2115 |
-# 3. Going further |
|
| 2115 |
+## 3. Going further |
|
| 2116 | 2116 |
|
| 2117 |
-## 3.1 Inside `docker run` |
|
| 2117 |
+### 3.1 Inside `docker run` |
|
| 2118 | 2118 |
|
| 2119 | 2119 |
As an example, the `docker run` command line makes the following API calls: |
| 2120 | 2120 |
|
| ... | ... |
@@ -2132,7 +2130,7 @@ As an example, the `docker run` command line makes the following API calls: |
| 2132 | 2132 |
|
| 2133 | 2133 |
- If in detached mode or only `stdin` is attached, display the container's id. |
| 2134 | 2134 |
|
| 2135 |
-## 3.2 Hijacking |
|
| 2135 |
+### 3.2 Hijacking |
|
| 2136 | 2136 |
|
| 2137 | 2137 |
In this version of the API, `/attach`, uses hijacking to transport `stdin`, |
| 2138 | 2138 |
`stdout`, and `stderr` on the same socket. |
| ... | ... |
@@ -2148,7 +2146,7 @@ from **200 OK** to **101 UPGRADED** and resends the same headers. |
| 2148 | 2148 |
|
| 2149 | 2149 |
This might change in the future. |
| 2150 | 2150 |
|
| 2151 |
-## 3.3 CORS Requests |
|
| 2151 |
+### 3.3 CORS Requests |
|
| 2152 | 2152 |
|
| 2153 | 2153 |
To set cross origin requests to the Engine API please give values to |
| 2154 | 2154 |
`--api-cors-header` when running Docker in daemon mode. Set * (asterisk) allows all, |
| ... | ... |
@@ -16,8 +16,6 @@ redirect_from: |
| 16 | 16 |
will be rejected. |
| 17 | 17 |
--> |
| 18 | 18 |
|
| 19 |
-# Docker Engine API v1.19 |
|
| 20 |
- |
|
| 21 | 19 |
## 1. Brief introduction |
| 22 | 20 |
|
| 23 | 21 |
- The daemon listens on `unix:///var/run/docker.sock` but you can |
| ... | ... |
@@ -28,11 +26,11 @@ redirect_from: |
| 28 | 28 |
- When the client API version is newer than the daemon's, these calls return an HTTP |
| 29 | 29 |
`400 Bad Request` error message. |
| 30 | 30 |
|
| 31 |
-# 2. Endpoints |
|
| 31 |
+## 2. Endpoints |
|
| 32 | 32 |
|
| 33 |
-## 2.1 Containers |
|
| 33 |
+### 2.1 Containers |
|
| 34 | 34 |
|
| 35 |
-### List containers |
|
| 35 |
+#### List containers |
|
| 36 | 36 |
|
| 37 | 37 |
`GET /containers/json` |
| 38 | 38 |
|
| ... | ... |
@@ -125,7 +123,7 @@ List containers |
| 125 | 125 |
- **400** – bad parameter |
| 126 | 126 |
- **500** – server error |
| 127 | 127 |
|
| 128 |
-### Create a container |
|
| 128 |
+#### Create a container |
|
| 129 | 129 |
|
| 130 | 130 |
`POST /containers/create` |
| 131 | 131 |
|
| ... | ... |
@@ -322,7 +320,7 @@ Create a container |
| 322 | 322 |
- **409** – conflict |
| 323 | 323 |
- **500** – server error |
| 324 | 324 |
|
| 325 |
-### Inspect a container |
|
| 325 |
+#### Inspect a container |
|
| 326 | 326 |
|
| 327 | 327 |
`GET /containers/(id or name)/json` |
| 328 | 328 |
|
| ... | ... |
@@ -459,7 +457,7 @@ Return low-level information on the container `id` |
| 459 | 459 |
- **404** – no such container |
| 460 | 460 |
- **500** – server error |
| 461 | 461 |
|
| 462 |
-### List processes running inside a container |
|
| 462 |
+#### List processes running inside a container |
|
| 463 | 463 |
|
| 464 | 464 |
`GET /containers/(id or name)/top` |
| 465 | 465 |
|
| ... | ... |
@@ -523,7 +521,7 @@ supported on Windows. |
| 523 | 523 |
- **404** – no such container |
| 524 | 524 |
- **500** – server error |
| 525 | 525 |
|
| 526 |
-### Get container logs |
|
| 526 |
+#### Get container logs |
|
| 527 | 527 |
|
| 528 | 528 |
`GET /containers/(id or name)/logs` |
| 529 | 529 |
|
| ... | ... |
@@ -565,7 +563,7 @@ Get `stdout` and `stderr` logs from the container ``id`` |
| 565 | 565 |
- **404** – no such container |
| 566 | 566 |
- **500** – server error |
| 567 | 567 |
|
| 568 |
-### Inspect changes on a container's filesystem |
|
| 568 |
+#### Inspect changes on a container's filesystem |
|
| 569 | 569 |
|
| 570 | 570 |
`GET /containers/(id or name)/changes` |
| 571 | 571 |
|
| ... | ... |
@@ -607,7 +605,7 @@ Values for `Kind`: |
| 607 | 607 |
- **404** – no such container |
| 608 | 608 |
- **500** – server error |
| 609 | 609 |
|
| 610 |
-### Export a container |
|
| 610 |
+#### Export a container |
|
| 611 | 611 |
|
| 612 | 612 |
`GET /containers/(id or name)/export` |
| 613 | 613 |
|
| ... | ... |
@@ -632,7 +630,7 @@ Export the contents of container `id` |
| 632 | 632 |
- **404** – no such container |
| 633 | 633 |
- **500** – server error |
| 634 | 634 |
|
| 635 |
-### Get container stats based on resource usage |
|
| 635 |
+#### Get container stats based on resource usage |
|
| 636 | 636 |
|
| 637 | 637 |
`GET /containers/(id or name)/stats` |
| 638 | 638 |
|
| ... | ... |
@@ -741,7 +739,7 @@ The precpu_stats is the cpu statistic of last read, which is used for calculatin |
| 741 | 741 |
- **404** – no such container |
| 742 | 742 |
- **500** – server error |
| 743 | 743 |
|
| 744 |
-### Resize a container TTY |
|
| 744 |
+#### Resize a container TTY |
|
| 745 | 745 |
|
| 746 | 746 |
`POST /containers/(id or name)/resize?h=<height>&w=<width>` |
| 747 | 747 |
|
| ... | ... |
@@ -768,7 +766,7 @@ Resize the TTY for container with `id`. You must restart the container for the |
| 768 | 768 |
- **404** – No such container |
| 769 | 769 |
- **500** – Cannot resize container |
| 770 | 770 |
|
| 771 |
-### Start a container |
|
| 771 |
+#### Start a container |
|
| 772 | 772 |
|
| 773 | 773 |
`POST /containers/(id or name)/start` |
| 774 | 774 |
|
| ... | ... |
@@ -793,7 +791,7 @@ Start the container `id` |
| 793 | 793 |
- **404** – no such container |
| 794 | 794 |
- **500** – server error |
| 795 | 795 |
|
| 796 |
-### Stop a container |
|
| 796 |
+#### Stop a container |
|
| 797 | 797 |
|
| 798 | 798 |
`POST /containers/(id or name)/stop` |
| 799 | 799 |
|
| ... | ... |
@@ -818,7 +816,7 @@ Stop the container `id` |
| 818 | 818 |
- **404** – no such container |
| 819 | 819 |
- **500** – server error |
| 820 | 820 |
|
| 821 |
-### Restart a container |
|
| 821 |
+#### Restart a container |
|
| 822 | 822 |
|
| 823 | 823 |
`POST /containers/(id or name)/restart` |
| 824 | 824 |
|
| ... | ... |
@@ -842,7 +840,7 @@ Restart the container `id` |
| 842 | 842 |
- **404** – no such container |
| 843 | 843 |
- **500** – server error |
| 844 | 844 |
|
| 845 |
-### Kill a container |
|
| 845 |
+#### Kill a container |
|
| 846 | 846 |
|
| 847 | 847 |
`POST /containers/(id or name)/kill` |
| 848 | 848 |
|
| ... | ... |
@@ -867,7 +865,7 @@ Kill the container `id` |
| 867 | 867 |
- **404** – no such container |
| 868 | 868 |
- **500** – server error |
| 869 | 869 |
|
| 870 |
-### Rename a container |
|
| 870 |
+#### Rename a container |
|
| 871 | 871 |
|
| 872 | 872 |
`POST /containers/(id or name)/rename` |
| 873 | 873 |
|
| ... | ... |
@@ -892,7 +890,7 @@ Rename the container `id` to a `new_name` |
| 892 | 892 |
- **409** - conflict name already assigned |
| 893 | 893 |
- **500** – server error |
| 894 | 894 |
|
| 895 |
-### Pause a container |
|
| 895 |
+#### Pause a container |
|
| 896 | 896 |
|
| 897 | 897 |
`POST /containers/(id or name)/pause` |
| 898 | 898 |
|
| ... | ... |
@@ -912,7 +910,7 @@ Pause the container `id` |
| 912 | 912 |
- **404** – no such container |
| 913 | 913 |
- **500** – server error |
| 914 | 914 |
|
| 915 |
-### Unpause a container |
|
| 915 |
+#### Unpause a container |
|
| 916 | 916 |
|
| 917 | 917 |
`POST /containers/(id or name)/unpause` |
| 918 | 918 |
|
| ... | ... |
@@ -932,7 +930,7 @@ Unpause the container `id` |
| 932 | 932 |
- **404** – no such container |
| 933 | 933 |
- **500** – server error |
| 934 | 934 |
|
| 935 |
-### Attach to a container |
|
| 935 |
+#### Attach to a container |
|
| 936 | 936 |
|
| 937 | 937 |
`POST /containers/(id or name)/attach` |
| 938 | 938 |
|
| ... | ... |
@@ -1017,7 +1015,7 @@ The simplest way to implement the Attach protocol is the following: |
| 1017 | 1017 |
4. Read the extracted size and output it on the correct output. |
| 1018 | 1018 |
5. Goto 1. |
| 1019 | 1019 |
|
| 1020 |
-### Attach to a container (websocket) |
|
| 1020 |
+#### Attach to a container (websocket) |
|
| 1021 | 1021 |
|
| 1022 | 1022 |
`GET /containers/(id or name)/attach/ws` |
| 1023 | 1023 |
|
| ... | ... |
@@ -1054,7 +1052,7 @@ Implements websocket protocol handshake according to [RFC 6455](http://tools.iet |
| 1054 | 1054 |
- **404** – no such container |
| 1055 | 1055 |
- **500** – server error |
| 1056 | 1056 |
|
| 1057 |
-### Wait a container |
|
| 1057 |
+#### Wait a container |
|
| 1058 | 1058 |
|
| 1059 | 1059 |
`POST /containers/(id or name)/wait` |
| 1060 | 1060 |
|
| ... | ... |
@@ -1077,7 +1075,7 @@ Block until container `id` stops, then returns the exit code |
| 1077 | 1077 |
- **404** – no such container |
| 1078 | 1078 |
- **500** – server error |
| 1079 | 1079 |
|
| 1080 |
-### Remove a container |
|
| 1080 |
+#### Remove a container |
|
| 1081 | 1081 |
|
| 1082 | 1082 |
`DELETE /containers/(id or name)` |
| 1083 | 1083 |
|
| ... | ... |
@@ -1106,7 +1104,7 @@ Remove the container `id` from the filesystem |
| 1106 | 1106 |
- **409** – conflict |
| 1107 | 1107 |
- **500** – server error |
| 1108 | 1108 |
|
| 1109 |
-### Copy files or folders from a container |
|
| 1109 |
+#### Copy files or folders from a container |
|
| 1110 | 1110 |
|
| 1111 | 1111 |
`POST /containers/(id or name)/copy` |
| 1112 | 1112 |
|
| ... | ... |
@@ -1136,9 +1134,9 @@ Copy files or folders of container `id` |
| 1136 | 1136 |
- **404** – no such container |
| 1137 | 1137 |
- **500** – server error |
| 1138 | 1138 |
|
| 1139 |
-## 2.2 Images |
|
| 1139 |
+### 2.2 Images |
|
| 1140 | 1140 |
|
| 1141 |
-### List Images |
|
| 1141 |
+#### List Images |
|
| 1142 | 1142 |
|
| 1143 | 1143 |
`GET /images/json` |
| 1144 | 1144 |
|
| ... | ... |
@@ -1229,7 +1227,7 @@ references on the command line. |
| 1229 | 1229 |
- `label=key` or `label="key=value"` of an image label |
| 1230 | 1230 |
- **filter** - only return images with the specified name |
| 1231 | 1231 |
|
| 1232 |
-### Build image from a Dockerfile |
|
| 1232 |
+#### Build image from a Dockerfile |
|
| 1233 | 1233 |
|
| 1234 | 1234 |
`POST /build` |
| 1235 | 1235 |
|
| ... | ... |
@@ -1302,7 +1300,7 @@ or being killed. |
| 1302 | 1302 |
- **200** – no error |
| 1303 | 1303 |
- **500** – server error |
| 1304 | 1304 |
|
| 1305 |
-### Create an image |
|
| 1305 |
+#### Create an image |
|
| 1306 | 1306 |
|
| 1307 | 1307 |
`POST /images/create` |
| 1308 | 1308 |
|
| ... | ... |
@@ -1346,7 +1344,7 @@ a base64-encoded AuthConfig object. |
| 1346 | 1346 |
|
| 1347 | 1347 |
|
| 1348 | 1348 |
|
| 1349 |
-### Inspect an image |
|
| 1349 |
+#### Inspect an image |
|
| 1350 | 1350 |
|
| 1351 | 1351 |
`GET /images/(name)/json` |
| 1352 | 1352 |
|
| ... | ... |
@@ -1397,7 +1395,7 @@ Return low-level information on the image `name` |
| 1397 | 1397 |
- **404** – no such image |
| 1398 | 1398 |
- **500** – server error |
| 1399 | 1399 |
|
| 1400 |
-### Get the history of an image |
|
| 1400 |
+#### Get the history of an image |
|
| 1401 | 1401 |
|
| 1402 | 1402 |
`GET /images/(name)/history` |
| 1403 | 1403 |
|
| ... | ... |
@@ -1451,7 +1449,7 @@ Return the history of the image `name` |
| 1451 | 1451 |
- **404** – no such image |
| 1452 | 1452 |
- **500** – server error |
| 1453 | 1453 |
|
| 1454 |
-### Push an image on the registry |
|
| 1454 |
+#### Push an image on the registry |
|
| 1455 | 1455 |
|
| 1456 | 1456 |
`POST /images/(name)/push` |
| 1457 | 1457 |
|
| ... | ... |
@@ -1494,7 +1492,7 @@ then be used in the URL. This duplicates the command line's flow. |
| 1494 | 1494 |
- **404** – no such image |
| 1495 | 1495 |
- **500** – server error |
| 1496 | 1496 |
|
| 1497 |
-### Tag an image into a repository |
|
| 1497 |
+#### Tag an image into a repository |
|
| 1498 | 1498 |
|
| 1499 | 1499 |
`POST /images/(name)/tag` |
| 1500 | 1500 |
|
| ... | ... |
@@ -1522,7 +1520,7 @@ Tag the image `name` into a repository |
| 1522 | 1522 |
- **409** – conflict |
| 1523 | 1523 |
- **500** – server error |
| 1524 | 1524 |
|
| 1525 |
-### Remove an image |
|
| 1525 |
+#### Remove an image |
|
| 1526 | 1526 |
|
| 1527 | 1527 |
`DELETE /images/(name)` |
| 1528 | 1528 |
|
| ... | ... |
@@ -1555,7 +1553,7 @@ Remove the image `name` from the filesystem |
| 1555 | 1555 |
- **409** – conflict |
| 1556 | 1556 |
- **500** – server error |
| 1557 | 1557 |
|
| 1558 |
-### Search images |
|
| 1558 |
+#### Search images |
|
| 1559 | 1559 |
|
| 1560 | 1560 |
`GET /images/search` |
| 1561 | 1561 |
|
| ... | ... |
@@ -1614,9 +1612,9 @@ be deprecated and replaced by the `is_automated` property. |
| 1614 | 1614 |
- **200** – no error |
| 1615 | 1615 |
- **500** – server error |
| 1616 | 1616 |
|
| 1617 |
-## 2.3 Misc |
|
| 1617 |
+### 2.3 Misc |
|
| 1618 | 1618 |
|
| 1619 |
-### Check auth configuration |
|
| 1619 |
+#### Check auth configuration |
|
| 1620 | 1620 |
|
| 1621 | 1621 |
`POST /auth` |
| 1622 | 1622 |
|
| ... | ... |
@@ -1644,7 +1642,7 @@ Get the default username and email |
| 1644 | 1644 |
- **204** – no error |
| 1645 | 1645 |
- **500** – server error |
| 1646 | 1646 |
|
| 1647 |
-### Display system-wide information |
|
| 1647 |
+#### Display system-wide information |
|
| 1648 | 1648 |
|
| 1649 | 1649 |
`GET /info` |
| 1650 | 1650 |
|
| ... | ... |
@@ -1713,7 +1711,7 @@ Display system-wide information |
| 1713 | 1713 |
- **200** – no error |
| 1714 | 1714 |
- **500** – server error |
| 1715 | 1715 |
|
| 1716 |
-### Show the docker version information |
|
| 1716 |
+#### Show the docker version information |
|
| 1717 | 1717 |
|
| 1718 | 1718 |
`GET /version` |
| 1719 | 1719 |
|
| ... | ... |
@@ -1743,7 +1741,7 @@ Show the docker version information |
| 1743 | 1743 |
- **200** – no error |
| 1744 | 1744 |
- **500** – server error |
| 1745 | 1745 |
|
| 1746 |
-### Ping the docker server |
|
| 1746 |
+#### Ping the docker server |
|
| 1747 | 1747 |
|
| 1748 | 1748 |
`GET /_ping` |
| 1749 | 1749 |
|
| ... | ... |
@@ -1765,7 +1763,7 @@ Ping the docker server |
| 1765 | 1765 |
- **200** - no error |
| 1766 | 1766 |
- **500** - server error |
| 1767 | 1767 |
|
| 1768 |
-### Create a new image from a container's changes |
|
| 1768 |
+#### Create a new image from a container's changes |
|
| 1769 | 1769 |
|
| 1770 | 1770 |
`POST /commit` |
| 1771 | 1771 |
|
| ... | ... |
@@ -1831,7 +1829,7 @@ Create a new image from a container's changes |
| 1831 | 1831 |
- **404** – no such container |
| 1832 | 1832 |
- **500** – server error |
| 1833 | 1833 |
|
| 1834 |
-### Monitor Docker's events |
|
| 1834 |
+#### Monitor Docker's events |
|
| 1835 | 1835 |
|
| 1836 | 1836 |
`GET /events` |
| 1837 | 1837 |
|
| ... | ... |
@@ -1873,7 +1871,7 @@ Docker images report the following events: |
| 1873 | 1873 |
- **200** – no error |
| 1874 | 1874 |
- **500** – server error |
| 1875 | 1875 |
|
| 1876 |
-### Get a tarball containing all images in a repository |
|
| 1876 |
+#### Get a tarball containing all images in a repository |
|
| 1877 | 1877 |
|
| 1878 | 1878 |
`GET /images/(name)/get` |
| 1879 | 1879 |
|
| ... | ... |
@@ -1903,7 +1901,7 @@ See the [image tarball format](#image-tarball-format) for more details. |
| 1903 | 1903 |
- **200** – no error |
| 1904 | 1904 |
- **500** – server error |
| 1905 | 1905 |
|
| 1906 |
-### Get a tarball containing all images |
|
| 1906 |
+#### Get a tarball containing all images |
|
| 1907 | 1907 |
|
| 1908 | 1908 |
`GET /images/get` |
| 1909 | 1909 |
|
| ... | ... |
@@ -1932,7 +1930,7 @@ See the [image tarball format](#image-tarball-format) for more details. |
| 1932 | 1932 |
- **200** – no error |
| 1933 | 1933 |
- **500** – server error |
| 1934 | 1934 |
|
| 1935 |
-### Load a tarball with a set of images and tags into docker |
|
| 1935 |
+#### Load a tarball with a set of images and tags into docker |
|
| 1936 | 1936 |
|
| 1937 | 1937 |
`POST /images/load` |
| 1938 | 1938 |
|
| ... | ... |
@@ -1955,7 +1953,7 @@ See the [image tarball format](#image-tarball-format) for more details. |
| 1955 | 1955 |
- **200** – no error |
| 1956 | 1956 |
- **500** – server error |
| 1957 | 1957 |
|
| 1958 |
-### Image tarball format |
|
| 1958 |
+#### Image tarball format |
|
| 1959 | 1959 |
|
| 1960 | 1960 |
An image tarball contains one directory per image layer (named using its long ID), |
| 1961 | 1961 |
each containing these files: |
| ... | ... |
@@ -1976,7 +1974,7 @@ the root that contains a list of repository and tag names mapped to layer IDs. |
| 1976 | 1976 |
} |
| 1977 | 1977 |
``` |
| 1978 | 1978 |
|
| 1979 |
-### Exec Create |
|
| 1979 |
+#### Exec Create |
|
| 1980 | 1980 |
|
| 1981 | 1981 |
`POST /containers/(id or name)/exec` |
| 1982 | 1982 |
|
| ... | ... |
@@ -2022,7 +2020,7 @@ Sets up an exec instance in a running container `id` |
| 2022 | 2022 |
- **201** – no error |
| 2023 | 2023 |
- **404** – no such container |
| 2024 | 2024 |
|
| 2025 |
-### Exec Start |
|
| 2025 |
+#### Exec Start |
|
| 2026 | 2026 |
|
| 2027 | 2027 |
`POST /exec/(id)/start` |
| 2028 | 2028 |
|
| ... | ... |
@@ -2063,7 +2061,7 @@ interactive session with the `exec` command. |
| 2063 | 2063 |
|
| 2064 | 2064 |
Similar to the stream behavior of `POST /containers/(id or name)/attach` API |
| 2065 | 2065 |
|
| 2066 |
-### Exec Resize |
|
| 2066 |
+#### Exec Resize |
|
| 2067 | 2067 |
|
| 2068 | 2068 |
`POST /exec/(id)/resize` |
| 2069 | 2069 |
|
| ... | ... |
@@ -2090,7 +2088,7 @@ This API is valid only if `tty` was specified as part of creating and starting t |
| 2090 | 2090 |
- **201** – no error |
| 2091 | 2091 |
- **404** – no such exec instance |
| 2092 | 2092 |
|
| 2093 |
-### Exec Inspect |
|
| 2093 |
+#### Exec Inspect |
|
| 2094 | 2094 |
|
| 2095 | 2095 |
`GET /exec/(id)/json` |
| 2096 | 2096 |
|
| ... | ... |
@@ -2195,9 +2193,9 @@ Return low-level information about the `exec` command `id`. |
| 2195 | 2195 |
- **404** – no such exec instance |
| 2196 | 2196 |
- **500** - server error |
| 2197 | 2197 |
|
| 2198 |
-# 3. Going further |
|
| 2198 |
+## 3. Going further |
|
| 2199 | 2199 |
|
| 2200 |
-## 3.1 Inside `docker run` |
|
| 2200 |
+### 3.1 Inside `docker run` |
|
| 2201 | 2201 |
|
| 2202 | 2202 |
As an example, the `docker run` command line makes the following API calls: |
| 2203 | 2203 |
|
| ... | ... |
@@ -2215,7 +2213,7 @@ As an example, the `docker run` command line makes the following API calls: |
| 2215 | 2215 |
|
| 2216 | 2216 |
- If in detached mode or only `stdin` is attached, display the container's id. |
| 2217 | 2217 |
|
| 2218 |
-## 3.2 Hijacking |
|
| 2218 |
+### 3.2 Hijacking |
|
| 2219 | 2219 |
|
| 2220 | 2220 |
In this version of the API, `/attach`, uses hijacking to transport `stdin`, |
| 2221 | 2221 |
`stdout`, and `stderr` on the same socket. |
| ... | ... |
@@ -2230,7 +2228,7 @@ When Docker daemon detects the `Upgrade` header, it switches its status code |
| 2230 | 2230 |
from **200 OK** to **101 UPGRADED** and resends the same headers. |
| 2231 | 2231 |
|
| 2232 | 2232 |
|
| 2233 |
-## 3.3 CORS Requests |
|
| 2233 |
+### 3.3 CORS Requests |
|
| 2234 | 2234 |
|
| 2235 | 2235 |
To set cross origin requests to the Engine API please give values to |
| 2236 | 2236 |
`--api-cors-header` when running Docker in daemon mode. Set * (asterisk) allows all, |
| ... | ... |
@@ -16,9 +16,7 @@ redirect_from: |
| 16 | 16 |
will be rejected. |
| 17 | 17 |
--> |
| 18 | 18 |
|
| 19 |
-# Docker Engine API v1.20 |
|
| 20 |
- |
|
| 21 |
-# 1. Brief introduction |
|
| 19 |
+## 1. Brief introduction |
|
| 22 | 20 |
|
| 23 | 21 |
- The daemon listens on `unix:///var/run/docker.sock` but you can |
| 24 | 22 |
[Bind Docker to another host/port or a Unix socket](../commandline/dockerd.md#bind-docker-to-another-host-port-or-a-unix-socket). |
| ... | ... |
@@ -26,11 +24,11 @@ redirect_from: |
| 26 | 26 |
or `pull`, the HTTP connection is hijacked to transport `stdout`, |
| 27 | 27 |
`stdin` and `stderr`. |
| 28 | 28 |
|
| 29 |
-# 2. Endpoints |
|
| 29 |
+## 2. Endpoints |
|
| 30 | 30 |
|
| 31 |
-## 2.1 Containers |
|
| 31 |
+### 2.1 Containers |
|
| 32 | 32 |
|
| 33 |
-### List containers |
|
| 33 |
+#### List containers |
|
| 34 | 34 |
|
| 35 | 35 |
`GET /containers/json` |
| 36 | 36 |
|
| ... | ... |
@@ -123,7 +121,7 @@ List containers |
| 123 | 123 |
- **400** – bad parameter |
| 124 | 124 |
- **500** – server error |
| 125 | 125 |
|
| 126 |
-### Create a container |
|
| 126 |
+#### Create a container |
|
| 127 | 127 |
|
| 128 | 128 |
`POST /containers/create` |
| 129 | 129 |
|
| ... | ... |
@@ -324,7 +322,7 @@ Create a container |
| 324 | 324 |
- **409** – conflict |
| 325 | 325 |
- **500** – server error |
| 326 | 326 |
|
| 327 |
-### Inspect a container |
|
| 327 |
+#### Inspect a container |
|
| 328 | 328 |
|
| 329 | 329 |
`GET /containers/(id or name)/json` |
| 330 | 330 |
|
| ... | ... |
@@ -466,7 +464,7 @@ Return low-level information on the container `id` |
| 466 | 466 |
- **404** – no such container |
| 467 | 467 |
- **500** – server error |
| 468 | 468 |
|
| 469 |
-### List processes running inside a container |
|
| 469 |
+#### List processes running inside a container |
|
| 470 | 470 |
|
| 471 | 471 |
`GET /containers/(id or name)/top` |
| 472 | 472 |
|
| ... | ... |
@@ -530,7 +528,7 @@ supported on Windows. |
| 530 | 530 |
- **404** – no such container |
| 531 | 531 |
- **500** – server error |
| 532 | 532 |
|
| 533 |
-### Get container logs |
|
| 533 |
+#### Get container logs |
|
| 534 | 534 |
|
| 535 | 535 |
`GET /containers/(id or name)/logs` |
| 536 | 536 |
|
| ... | ... |
@@ -572,7 +570,7 @@ Get `stdout` and `stderr` logs from the container ``id`` |
| 572 | 572 |
- **404** – no such container |
| 573 | 573 |
- **500** – server error |
| 574 | 574 |
|
| 575 |
-### Inspect changes on a container's filesystem |
|
| 575 |
+#### Inspect changes on a container's filesystem |
|
| 576 | 576 |
|
| 577 | 577 |
`GET /containers/(id or name)/changes` |
| 578 | 578 |
|
| ... | ... |
@@ -614,7 +612,7 @@ Values for `Kind`: |
| 614 | 614 |
- **404** – no such container |
| 615 | 615 |
- **500** – server error |
| 616 | 616 |
|
| 617 |
-### Export a container |
|
| 617 |
+#### Export a container |
|
| 618 | 618 |
|
| 619 | 619 |
`GET /containers/(id or name)/export` |
| 620 | 620 |
|
| ... | ... |
@@ -639,7 +637,7 @@ Export the contents of container `id` |
| 639 | 639 |
- **404** – no such container |
| 640 | 640 |
- **500** – server error |
| 641 | 641 |
|
| 642 |
-### Get container stats based on resource usage |
|
| 642 |
+#### Get container stats based on resource usage |
|
| 643 | 643 |
|
| 644 | 644 |
`GET /containers/(id or name)/stats` |
| 645 | 645 |
|
| ... | ... |
@@ -748,7 +746,7 @@ The precpu_stats is the cpu statistic of last read, which is used for calculatin |
| 748 | 748 |
- **404** – no such container |
| 749 | 749 |
- **500** – server error |
| 750 | 750 |
|
| 751 |
-### Resize a container TTY |
|
| 751 |
+#### Resize a container TTY |
|
| 752 | 752 |
|
| 753 | 753 |
`POST /containers/(id or name)/resize?h=<height>&w=<width>` |
| 754 | 754 |
|
| ... | ... |
@@ -775,7 +773,7 @@ Resize the TTY for container with `id`. You must restart the container for the |
| 775 | 775 |
- **404** – No such container |
| 776 | 776 |
- **500** – Cannot resize container |
| 777 | 777 |
|
| 778 |
-### Start a container |
|
| 778 |
+#### Start a container |
|
| 779 | 779 |
|
| 780 | 780 |
`POST /containers/(id or name)/start` |
| 781 | 781 |
|
| ... | ... |
@@ -800,7 +798,7 @@ Start the container `id` |
| 800 | 800 |
- **404** – no such container |
| 801 | 801 |
- **500** – server error |
| 802 | 802 |
|
| 803 |
-### Stop a container |
|
| 803 |
+#### Stop a container |
|
| 804 | 804 |
|
| 805 | 805 |
`POST /containers/(id or name)/stop` |
| 806 | 806 |
|
| ... | ... |
@@ -825,7 +823,7 @@ Stop the container `id` |
| 825 | 825 |
- **404** – no such container |
| 826 | 826 |
- **500** – server error |
| 827 | 827 |
|
| 828 |
-### Restart a container |
|
| 828 |
+#### Restart a container |
|
| 829 | 829 |
|
| 830 | 830 |
`POST /containers/(id or name)/restart` |
| 831 | 831 |
|
| ... | ... |
@@ -849,7 +847,7 @@ Restart the container `id` |
| 849 | 849 |
- **404** – no such container |
| 850 | 850 |
- **500** – server error |
| 851 | 851 |
|
| 852 |
-### Kill a container |
|
| 852 |
+#### Kill a container |
|
| 853 | 853 |
|
| 854 | 854 |
`POST /containers/(id or name)/kill` |
| 855 | 855 |
|
| ... | ... |
@@ -874,7 +872,7 @@ Kill the container `id` |
| 874 | 874 |
- **404** – no such container |
| 875 | 875 |
- **500** – server error |
| 876 | 876 |
|
| 877 |
-### Rename a container |
|
| 877 |
+#### Rename a container |
|
| 878 | 878 |
|
| 879 | 879 |
`POST /containers/(id or name)/rename` |
| 880 | 880 |
|
| ... | ... |
@@ -899,7 +897,7 @@ Rename the container `id` to a `new_name` |
| 899 | 899 |
- **409** - conflict name already assigned |
| 900 | 900 |
- **500** – server error |
| 901 | 901 |
|
| 902 |
-### Pause a container |
|
| 902 |
+#### Pause a container |
|
| 903 | 903 |
|
| 904 | 904 |
`POST /containers/(id or name)/pause` |
| 905 | 905 |
|
| ... | ... |
@@ -919,7 +917,7 @@ Pause the container `id` |
| 919 | 919 |
- **404** – no such container |
| 920 | 920 |
- **500** – server error |
| 921 | 921 |
|
| 922 |
-### Unpause a container |
|
| 922 |
+#### Unpause a container |
|
| 923 | 923 |
|
| 924 | 924 |
`POST /containers/(id or name)/unpause` |
| 925 | 925 |
|
| ... | ... |
@@ -939,7 +937,7 @@ Unpause the container `id` |
| 939 | 939 |
- **404** – no such container |
| 940 | 940 |
- **500** – server error |
| 941 | 941 |
|
| 942 |
-### Attach to a container |
|
| 942 |
+#### Attach to a container |
|
| 943 | 943 |
|
| 944 | 944 |
`POST /containers/(id or name)/attach` |
| 945 | 945 |
|
| ... | ... |
@@ -1024,7 +1022,7 @@ The simplest way to implement the Attach protocol is the following: |
| 1024 | 1024 |
4. Read the extracted size and output it on the correct output. |
| 1025 | 1025 |
5. Goto 1. |
| 1026 | 1026 |
|
| 1027 |
-### Attach to a container (websocket) |
|
| 1027 |
+#### Attach to a container (websocket) |
|
| 1028 | 1028 |
|
| 1029 | 1029 |
`GET /containers/(id or name)/attach/ws` |
| 1030 | 1030 |
|
| ... | ... |
@@ -1061,7 +1059,7 @@ Implements websocket protocol handshake according to [RFC 6455](http://tools.iet |
| 1061 | 1061 |
- **404** – no such container |
| 1062 | 1062 |
- **500** – server error |
| 1063 | 1063 |
|
| 1064 |
-### Wait a container |
|
| 1064 |
+#### Wait a container |
|
| 1065 | 1065 |
|
| 1066 | 1066 |
`POST /containers/(id or name)/wait` |
| 1067 | 1067 |
|
| ... | ... |
@@ -1084,7 +1082,7 @@ Block until container `id` stops, then returns the exit code |
| 1084 | 1084 |
- **404** – no such container |
| 1085 | 1085 |
- **500** – server error |
| 1086 | 1086 |
|
| 1087 |
-### Remove a container |
|
| 1087 |
+#### Remove a container |
|
| 1088 | 1088 |
|
| 1089 | 1089 |
`DELETE /containers/(id or name)` |
| 1090 | 1090 |
|
| ... | ... |
@@ -1113,7 +1111,7 @@ Remove the container `id` from the filesystem |
| 1113 | 1113 |
- **409** – conflict |
| 1114 | 1114 |
- **500** – server error |
| 1115 | 1115 |
|
| 1116 |
-### Copy files or folders from a container |
|
| 1116 |
+#### Copy files or folders from a container |
|
| 1117 | 1117 |
|
| 1118 | 1118 |
`POST /containers/(id or name)/copy` |
| 1119 | 1119 |
|
| ... | ... |
@@ -1145,14 +1143,14 @@ Copy files or folders of container `id` |
| 1145 | 1145 |
- **404** – no such container |
| 1146 | 1146 |
- **500** – server error |
| 1147 | 1147 |
|
| 1148 |
-### Retrieving information about files and folders in a container |
|
| 1148 |
+#### Retrieving information about files and folders in a container |
|
| 1149 | 1149 |
|
| 1150 | 1150 |
`HEAD /containers/(id or name)/archive` |
| 1151 | 1151 |
|
| 1152 | 1152 |
See the description of the `X-Docker-Container-Path-Stat` header in the |
| 1153 | 1153 |
following section. |
| 1154 | 1154 |
|
| 1155 |
-### Get an archive of a filesystem resource in a container |
|
| 1155 |
+#### Get an archive of a filesystem resource in a container |
|
| 1156 | 1156 |
|
| 1157 | 1157 |
`GET /containers/(id or name)/archive` |
| 1158 | 1158 |
|
| ... | ... |
@@ -1217,7 +1215,7 @@ desired. |
| 1217 | 1217 |
- no such file or directory (**path** does not exist) |
| 1218 | 1218 |
- **500** - server error |
| 1219 | 1219 |
|
| 1220 |
-### Extract an archive of files or folders to a directory in a container |
|
| 1220 |
+#### Extract an archive of files or folders to a directory in a container |
|
| 1221 | 1221 |
|
| 1222 | 1222 |
`PUT /containers/(id or name)/archive` |
| 1223 | 1223 |
|
| ... | ... |
@@ -1265,9 +1263,9 @@ Upload a tar archive to be extracted to a path in the filesystem of container |
| 1265 | 1265 |
- no such file or directory (**path** resource does not exist) |
| 1266 | 1266 |
- **500** – server error |
| 1267 | 1267 |
|
| 1268 |
-## 2.2 Images |
|
| 1268 |
+### 2.2 Images |
|
| 1269 | 1269 |
|
| 1270 |
-### List Images |
|
| 1270 |
+#### List Images |
|
| 1271 | 1271 |
|
| 1272 | 1272 |
`GET /images/json` |
| 1273 | 1273 |
|
| ... | ... |
@@ -1358,7 +1356,7 @@ references on the command line. |
| 1358 | 1358 |
- `label=key` or `label="key=value"` of an image label |
| 1359 | 1359 |
- **filter** - only return images with the specified name |
| 1360 | 1360 |
|
| 1361 |
-### Build image from a Dockerfile |
|
| 1361 |
+#### Build image from a Dockerfile |
|
| 1362 | 1362 |
|
| 1363 | 1363 |
`POST /build` |
| 1364 | 1364 |
|
| ... | ... |
@@ -1456,7 +1454,7 @@ or being killed. |
| 1456 | 1456 |
- **200** – no error |
| 1457 | 1457 |
- **500** – server error |
| 1458 | 1458 |
|
| 1459 |
-### Create an image |
|
| 1459 |
+#### Create an image |
|
| 1460 | 1460 |
|
| 1461 | 1461 |
`POST /images/create` |
| 1462 | 1462 |
|
| ... | ... |
@@ -1500,7 +1498,7 @@ a base64-encoded AuthConfig object. |
| 1500 | 1500 |
|
| 1501 | 1501 |
|
| 1502 | 1502 |
|
| 1503 |
-### Inspect an image |
|
| 1503 |
+#### Inspect an image |
|
| 1504 | 1504 |
|
| 1505 | 1505 |
`GET /images/(name)/json` |
| 1506 | 1506 |
|
| ... | ... |
@@ -1551,7 +1549,7 @@ Return low-level information on the image `name` |
| 1551 | 1551 |
- **404** – no such image |
| 1552 | 1552 |
- **500** – server error |
| 1553 | 1553 |
|
| 1554 |
-### Get the history of an image |
|
| 1554 |
+#### Get the history of an image |
|
| 1555 | 1555 |
|
| 1556 | 1556 |
`GET /images/(name)/history` |
| 1557 | 1557 |
|
| ... | ... |
@@ -1605,7 +1603,7 @@ Return the history of the image `name` |
| 1605 | 1605 |
- **404** – no such image |
| 1606 | 1606 |
- **500** – server error |
| 1607 | 1607 |
|
| 1608 |
-### Push an image on the registry |
|
| 1608 |
+#### Push an image on the registry |
|
| 1609 | 1609 |
|
| 1610 | 1610 |
`POST /images/(name)/push` |
| 1611 | 1611 |
|
| ... | ... |
@@ -1648,7 +1646,7 @@ then be used in the URL. This duplicates the command line's flow. |
| 1648 | 1648 |
- **404** – no such image |
| 1649 | 1649 |
- **500** – server error |
| 1650 | 1650 |
|
| 1651 |
-### Tag an image into a repository |
|
| 1651 |
+#### Tag an image into a repository |
|
| 1652 | 1652 |
|
| 1653 | 1653 |
`POST /images/(name)/tag` |
| 1654 | 1654 |
|
| ... | ... |
@@ -1676,7 +1674,7 @@ Tag the image `name` into a repository |
| 1676 | 1676 |
- **409** – conflict |
| 1677 | 1677 |
- **500** – server error |
| 1678 | 1678 |
|
| 1679 |
-### Remove an image |
|
| 1679 |
+#### Remove an image |
|
| 1680 | 1680 |
|
| 1681 | 1681 |
`DELETE /images/(name)` |
| 1682 | 1682 |
|
| ... | ... |
@@ -1709,7 +1707,7 @@ Remove the image `name` from the filesystem |
| 1709 | 1709 |
- **409** – conflict |
| 1710 | 1710 |
- **500** – server error |
| 1711 | 1711 |
|
| 1712 |
-### Search images |
|
| 1712 |
+#### Search images |
|
| 1713 | 1713 |
|
| 1714 | 1714 |
`GET /images/search` |
| 1715 | 1715 |
|
| ... | ... |
@@ -1762,9 +1760,9 @@ Search for an image on [Docker Hub](https://hub.docker.com). |
| 1762 | 1762 |
- **200** – no error |
| 1763 | 1763 |
- **500** – server error |
| 1764 | 1764 |
|
| 1765 |
-## 2.3 Misc |
|
| 1765 |
+### 2.3 Misc |
|
| 1766 | 1766 |
|
| 1767 |
-### Check auth configuration |
|
| 1767 |
+#### Check auth configuration |
|
| 1768 | 1768 |
|
| 1769 | 1769 |
`POST /auth` |
| 1770 | 1770 |
|
| ... | ... |
@@ -1792,7 +1790,7 @@ Get the default username and email |
| 1792 | 1792 |
- **204** – no error |
| 1793 | 1793 |
- **500** – server error |
| 1794 | 1794 |
|
| 1795 |
-### Display system-wide information |
|
| 1795 |
+#### Display system-wide information |
|
| 1796 | 1796 |
|
| 1797 | 1797 |
`GET /info` |
| 1798 | 1798 |
|
| ... | ... |
@@ -1861,7 +1859,7 @@ Display system-wide information |
| 1861 | 1861 |
- **200** – no error |
| 1862 | 1862 |
- **500** – server error |
| 1863 | 1863 |
|
| 1864 |
-### Show the docker version information |
|
| 1864 |
+#### Show the docker version information |
|
| 1865 | 1865 |
|
| 1866 | 1866 |
`GET /version` |
| 1867 | 1867 |
|
| ... | ... |
@@ -1892,7 +1890,7 @@ Show the docker version information |
| 1892 | 1892 |
- **200** – no error |
| 1893 | 1893 |
- **500** – server error |
| 1894 | 1894 |
|
| 1895 |
-### Ping the docker server |
|
| 1895 |
+#### Ping the docker server |
|
| 1896 | 1896 |
|
| 1897 | 1897 |
`GET /_ping` |
| 1898 | 1898 |
|
| ... | ... |
@@ -1914,7 +1912,7 @@ Ping the docker server |
| 1914 | 1914 |
- **200** - no error |
| 1915 | 1915 |
- **500** - server error |
| 1916 | 1916 |
|
| 1917 |
-### Create a new image from a container's changes |
|
| 1917 |
+#### Create a new image from a container's changes |
|
| 1918 | 1918 |
|
| 1919 | 1919 |
`POST /commit` |
| 1920 | 1920 |
|
| ... | ... |
@@ -1986,7 +1984,7 @@ Create a new image from a container's changes |
| 1986 | 1986 |
- **404** – no such container |
| 1987 | 1987 |
- **500** – server error |
| 1988 | 1988 |
|
| 1989 |
-### Monitor Docker's events |
|
| 1989 |
+#### Monitor Docker's events |
|
| 1990 | 1990 |
|
| 1991 | 1991 |
`GET /events` |
| 1992 | 1992 |
|
| ... | ... |
@@ -2028,7 +2026,7 @@ Docker images report the following events: |
| 2028 | 2028 |
- **200** – no error |
| 2029 | 2029 |
- **500** – server error |
| 2030 | 2030 |
|
| 2031 |
-### Get a tarball containing all images in a repository |
|
| 2031 |
+#### Get a tarball containing all images in a repository |
|
| 2032 | 2032 |
|
| 2033 | 2033 |
`GET /images/(name)/get` |
| 2034 | 2034 |
|
| ... | ... |
@@ -2058,7 +2056,7 @@ See the [image tarball format](#image-tarball-format) for more details. |
| 2058 | 2058 |
- **200** – no error |
| 2059 | 2059 |
- **500** – server error |
| 2060 | 2060 |
|
| 2061 |
-### Get a tarball containing all images |
|
| 2061 |
+#### Get a tarball containing all images |
|
| 2062 | 2062 |
|
| 2063 | 2063 |
`GET /images/get` |
| 2064 | 2064 |
|
| ... | ... |
@@ -2087,7 +2085,7 @@ See the [image tarball format](#image-tarball-format) for more details. |
| 2087 | 2087 |
- **200** – no error |
| 2088 | 2088 |
- **500** – server error |
| 2089 | 2089 |
|
| 2090 |
-### Load a tarball with a set of images and tags into docker |
|
| 2090 |
+#### Load a tarball with a set of images and tags into docker |
|
| 2091 | 2091 |
|
| 2092 | 2092 |
`POST /images/load` |
| 2093 | 2093 |
|
| ... | ... |
@@ -2110,7 +2108,7 @@ See the [image tarball format](#image-tarball-format) for more details. |
| 2110 | 2110 |
- **200** – no error |
| 2111 | 2111 |
- **500** – server error |
| 2112 | 2112 |
|
| 2113 |
-### Image tarball format |
|
| 2113 |
+#### Image tarball format |
|
| 2114 | 2114 |
|
| 2115 | 2115 |
An image tarball contains one directory per image layer (named using its long ID), |
| 2116 | 2116 |
each containing these files: |
| ... | ... |
@@ -2131,7 +2129,7 @@ the root that contains a list of repository and tag names mapped to layer IDs. |
| 2131 | 2131 |
} |
| 2132 | 2132 |
``` |
| 2133 | 2133 |
|
| 2134 |
-### Exec Create |
|
| 2134 |
+#### Exec Create |
|
| 2135 | 2135 |
|
| 2136 | 2136 |
`POST /containers/(id or name)/exec` |
| 2137 | 2137 |
|
| ... | ... |
@@ -2177,7 +2175,7 @@ Sets up an exec instance in a running container `id` |
| 2177 | 2177 |
- **201** – no error |
| 2178 | 2178 |
- **404** – no such container |
| 2179 | 2179 |
|
| 2180 |
-### Exec Start |
|
| 2180 |
+#### Exec Start |
|
| 2181 | 2181 |
|
| 2182 | 2182 |
`POST /exec/(id)/start` |
| 2183 | 2183 |
|
| ... | ... |
@@ -2218,7 +2216,7 @@ interactive session with the `exec` command. |
| 2218 | 2218 |
|
| 2219 | 2219 |
Similar to the stream behavior of `POST /containers/(id or name)/attach` API |
| 2220 | 2220 |
|
| 2221 |
-### Exec Resize |
|
| 2221 |
+#### Exec Resize |
|
| 2222 | 2222 |
|
| 2223 | 2223 |
`POST /exec/(id)/resize` |
| 2224 | 2224 |
|
| ... | ... |
@@ -2245,7 +2243,7 @@ This API is valid only if `tty` was specified as part of creating and starting t |
| 2245 | 2245 |
- **201** – no error |
| 2246 | 2246 |
- **404** – no such exec instance |
| 2247 | 2247 |
|
| 2248 |
-### Exec Inspect |
|
| 2248 |
+#### Exec Inspect |
|
| 2249 | 2249 |
|
| 2250 | 2250 |
`GET /exec/(id)/json` |
| 2251 | 2251 |
|
| ... | ... |
@@ -2348,9 +2346,9 @@ Return low-level information about the `exec` command `id`. |
| 2348 | 2348 |
- **404** – no such exec instance |
| 2349 | 2349 |
- **500** - server error |
| 2350 | 2350 |
|
| 2351 |
-# 3. Going further |
|
| 2351 |
+## 3. Going further |
|
| 2352 | 2352 |
|
| 2353 |
-## 3.1 Inside `docker run` |
|
| 2353 |
+### 3.1 Inside `docker run` |
|
| 2354 | 2354 |
|
| 2355 | 2355 |
As an example, the `docker run` command line makes the following API calls: |
| 2356 | 2356 |
|
| ... | ... |
@@ -2368,7 +2366,7 @@ As an example, the `docker run` command line makes the following API calls: |
| 2368 | 2368 |
|
| 2369 | 2369 |
- If in detached mode or only `stdin` is attached, display the container's id. |
| 2370 | 2370 |
|
| 2371 |
-## 3.2 Hijacking |
|
| 2371 |
+### 3.2 Hijacking |
|
| 2372 | 2372 |
|
| 2373 | 2373 |
In this version of the API, `/attach`, uses hijacking to transport `stdin`, |
| 2374 | 2374 |
`stdout`, and `stderr` on the same socket. |
| ... | ... |
@@ -2383,7 +2381,7 @@ When Docker daemon detects the `Upgrade` header, it switches its status code |
| 2383 | 2383 |
from **200 OK** to **101 UPGRADED** and resends the same headers. |
| 2384 | 2384 |
|
| 2385 | 2385 |
|
| 2386 |
-## 3.3 CORS Requests |
|
| 2386 |
+### 3.3 CORS Requests |
|
| 2387 | 2387 |
|
| 2388 | 2388 |
To set cross origin requests to the Engine API please give values to |
| 2389 | 2389 |
`--api-cors-header` when running Docker in daemon mode. Set * (asterisk) allows all, |
| ... | ... |
@@ -16,8 +16,6 @@ redirect_from: |
| 16 | 16 |
will be rejected. |
| 17 | 17 |
--> |
| 18 | 18 |
|
| 19 |
-# Docker Engine API v1.21 |
|
| 20 |
- |
|
| 21 | 19 |
## 1. Brief introduction |
| 22 | 20 |
|
| 23 | 21 |
- The daemon listens on `unix:///var/run/docker.sock` but you can |
| ... | ... |
@@ -28,11 +26,11 @@ redirect_from: |
| 28 | 28 |
- When the client API version is newer than the daemon's, these calls return an HTTP |
| 29 | 29 |
`400 Bad Request` error message. |
| 30 | 30 |
|
| 31 |
-# 2. Endpoints |
|
| 31 |
+## 2. Endpoints |
|
| 32 | 32 |
|
| 33 |
-## 2.1 Containers |
|
| 33 |
+### 2.1 Containers |
|
| 34 | 34 |
|
| 35 |
-### List containers |
|
| 35 |
+#### List containers |
|
| 36 | 36 |
|
| 37 | 37 |
`GET /containers/json` |
| 38 | 38 |
|
| ... | ... |
@@ -129,7 +127,7 @@ List containers |
| 129 | 129 |
- **400** – bad parameter |
| 130 | 130 |
- **500** – server error |
| 131 | 131 |
|
| 132 |
-### Create a container |
|
| 132 |
+#### Create a container |
|
| 133 | 133 |
|
| 134 | 134 |
`POST /containers/create` |
| 135 | 135 |
|
| ... | ... |
@@ -347,7 +345,7 @@ Create a container |
| 347 | 347 |
- **409** – conflict |
| 348 | 348 |
- **500** – server error |
| 349 | 349 |
|
| 350 |
-### Inspect a container |
|
| 350 |
+#### Inspect a container |
|
| 351 | 351 |
|
| 352 | 352 |
`GET /containers/(id or name)/json` |
| 353 | 353 |
|
| ... | ... |
@@ -537,7 +535,7 @@ Return low-level information on the container `id` |
| 537 | 537 |
- **404** – no such container |
| 538 | 538 |
- **500** – server error |
| 539 | 539 |
|
| 540 |
-### List processes running inside a container |
|
| 540 |
+#### List processes running inside a container |
|
| 541 | 541 |
|
| 542 | 542 |
`GET /containers/(id or name)/top` |
| 543 | 543 |
|
| ... | ... |
@@ -601,7 +599,7 @@ supported on Windows. |
| 601 | 601 |
- **404** – no such container |
| 602 | 602 |
- **500** – server error |
| 603 | 603 |
|
| 604 |
-### Get container logs |
|
| 604 |
+#### Get container logs |
|
| 605 | 605 |
|
| 606 | 606 |
`GET /containers/(id or name)/logs` |
| 607 | 607 |
|
| ... | ... |
@@ -643,7 +641,7 @@ Get `stdout` and `stderr` logs from the container ``id`` |
| 643 | 643 |
- **404** – no such container |
| 644 | 644 |
- **500** – server error |
| 645 | 645 |
|
| 646 |
-### Inspect changes on a container's filesystem |
|
| 646 |
+#### Inspect changes on a container's filesystem |
|
| 647 | 647 |
|
| 648 | 648 |
`GET /containers/(id or name)/changes` |
| 649 | 649 |
|
| ... | ... |
@@ -685,7 +683,7 @@ Values for `Kind`: |
| 685 | 685 |
- **404** – no such container |
| 686 | 686 |
- **500** – server error |
| 687 | 687 |
|
| 688 |
-### Export a container |
|
| 688 |
+#### Export a container |
|
| 689 | 689 |
|
| 690 | 690 |
`GET /containers/(id or name)/export` |
| 691 | 691 |
|
| ... | ... |
@@ -710,7 +708,7 @@ Export the contents of container `id` |
| 710 | 710 |
- **404** – no such container |
| 711 | 711 |
- **500** – server error |
| 712 | 712 |
|
| 713 |
-### Get container stats based on resource usage |
|
| 713 |
+#### Get container stats based on resource usage |
|
| 714 | 714 |
|
| 715 | 715 |
`GET /containers/(id or name)/stats` |
| 716 | 716 |
|
| ... | ... |
@@ -831,7 +829,7 @@ The precpu_stats is the cpu statistic of last read, which is used for calculatin |
| 831 | 831 |
- **404** – no such container |
| 832 | 832 |
- **500** – server error |
| 833 | 833 |
|
| 834 |
-### Resize a container TTY |
|
| 834 |
+#### Resize a container TTY |
|
| 835 | 835 |
|
| 836 | 836 |
`POST /containers/(id or name)/resize` |
| 837 | 837 |
|
| ... | ... |
@@ -858,7 +856,7 @@ Resize the TTY for container with `id`. The unit is number of characters. You m |
| 858 | 858 |
- **404** – No such container |
| 859 | 859 |
- **500** – Cannot resize container |
| 860 | 860 |
|
| 861 |
-### Start a container |
|
| 861 |
+#### Start a container |
|
| 862 | 862 |
|
| 863 | 863 |
`POST /containers/(id or name)/start` |
| 864 | 864 |
|
| ... | ... |
@@ -883,7 +881,7 @@ Start the container `id` |
| 883 | 883 |
- **404** – no such container |
| 884 | 884 |
- **500** – server error |
| 885 | 885 |
|
| 886 |
-### Stop a container |
|
| 886 |
+#### Stop a container |
|
| 887 | 887 |
|
| 888 | 888 |
`POST /containers/(id or name)/stop` |
| 889 | 889 |
|
| ... | ... |
@@ -908,7 +906,7 @@ Stop the container `id` |
| 908 | 908 |
- **404** – no such container |
| 909 | 909 |
- **500** – server error |
| 910 | 910 |
|
| 911 |
-### Restart a container |
|
| 911 |
+#### Restart a container |
|
| 912 | 912 |
|
| 913 | 913 |
`POST /containers/(id or name)/restart` |
| 914 | 914 |
|
| ... | ... |
@@ -932,7 +930,7 @@ Restart the container `id` |
| 932 | 932 |
- **404** – no such container |
| 933 | 933 |
- **500** – server error |
| 934 | 934 |
|
| 935 |
-### Kill a container |
|
| 935 |
+#### Kill a container |
|
| 936 | 936 |
|
| 937 | 937 |
`POST /containers/(id or name)/kill` |
| 938 | 938 |
|
| ... | ... |
@@ -957,7 +955,7 @@ Kill the container `id` |
| 957 | 957 |
- **404** – no such container |
| 958 | 958 |
- **500** – server error |
| 959 | 959 |
|
| 960 |
-### Rename a container |
|
| 960 |
+#### Rename a container |
|
| 961 | 961 |
|
| 962 | 962 |
`POST /containers/(id or name)/rename` |
| 963 | 963 |
|
| ... | ... |
@@ -982,7 +980,7 @@ Rename the container `id` to a `new_name` |
| 982 | 982 |
- **409** - conflict name already assigned |
| 983 | 983 |
- **500** – server error |
| 984 | 984 |
|
| 985 |
-### Pause a container |
|
| 985 |
+#### Pause a container |
|
| 986 | 986 |
|
| 987 | 987 |
`POST /containers/(id or name)/pause` |
| 988 | 988 |
|
| ... | ... |
@@ -1002,7 +1000,7 @@ Pause the container `id` |
| 1002 | 1002 |
- **404** – no such container |
| 1003 | 1003 |
- **500** – server error |
| 1004 | 1004 |
|
| 1005 |
-### Unpause a container |
|
| 1005 |
+#### Unpause a container |
|
| 1006 | 1006 |
|
| 1007 | 1007 |
`POST /containers/(id or name)/unpause` |
| 1008 | 1008 |
|
| ... | ... |
@@ -1022,7 +1020,7 @@ Unpause the container `id` |
| 1022 | 1022 |
- **404** – no such container |
| 1023 | 1023 |
- **500** – server error |
| 1024 | 1024 |
|
| 1025 |
-### Attach to a container |
|
| 1025 |
+#### Attach to a container |
|
| 1026 | 1026 |
|
| 1027 | 1027 |
`POST /containers/(id or name)/attach` |
| 1028 | 1028 |
|
| ... | ... |
@@ -1107,7 +1105,7 @@ The simplest way to implement the Attach protocol is the following: |
| 1107 | 1107 |
4. Read the extracted size and output it on the correct output. |
| 1108 | 1108 |
5. Goto 1. |
| 1109 | 1109 |
|
| 1110 |
-### Attach to a container (websocket) |
|
| 1110 |
+#### Attach to a container (websocket) |
|
| 1111 | 1111 |
|
| 1112 | 1112 |
`GET /containers/(id or name)/attach/ws` |
| 1113 | 1113 |
|
| ... | ... |
@@ -1144,7 +1142,7 @@ Implements websocket protocol handshake according to [RFC 6455](http://tools.iet |
| 1144 | 1144 |
- **404** – no such container |
| 1145 | 1145 |
- **500** – server error |
| 1146 | 1146 |
|
| 1147 |
-### Wait a container |
|
| 1147 |
+#### Wait a container |
|
| 1148 | 1148 |
|
| 1149 | 1149 |
`POST /containers/(id or name)/wait` |
| 1150 | 1150 |
|
| ... | ... |
@@ -1167,7 +1165,7 @@ Block until container `id` stops, then returns the exit code |
| 1167 | 1167 |
- **404** – no such container |
| 1168 | 1168 |
- **500** – server error |
| 1169 | 1169 |
|
| 1170 |
-### Remove a container |
|
| 1170 |
+#### Remove a container |
|
| 1171 | 1171 |
|
| 1172 | 1172 |
`DELETE /containers/(id or name)` |
| 1173 | 1173 |
|
| ... | ... |
@@ -1196,7 +1194,7 @@ Remove the container `id` from the filesystem |
| 1196 | 1196 |
- **409** – conflict |
| 1197 | 1197 |
- **500** – server error |
| 1198 | 1198 |
|
| 1199 |
-### Copy files or folders from a container |
|
| 1199 |
+#### Copy files or folders from a container |
|
| 1200 | 1200 |
|
| 1201 | 1201 |
`POST /containers/(id or name)/copy` |
| 1202 | 1202 |
|
| ... | ... |
@@ -1228,14 +1226,14 @@ Copy files or folders of container `id` |
| 1228 | 1228 |
- **404** – no such container |
| 1229 | 1229 |
- **500** – server error |
| 1230 | 1230 |
|
| 1231 |
-### Retrieving information about files and folders in a container |
|
| 1231 |
+#### Retrieving information about files and folders in a container |
|
| 1232 | 1232 |
|
| 1233 | 1233 |
`HEAD /containers/(id or name)/archive` |
| 1234 | 1234 |
|
| 1235 | 1235 |
See the description of the `X-Docker-Container-Path-Stat` header in the |
| 1236 | 1236 |
following section. |
| 1237 | 1237 |
|
| 1238 |
-### Get an archive of a filesystem resource in a container |
|
| 1238 |
+#### Get an archive of a filesystem resource in a container |
|
| 1239 | 1239 |
|
| 1240 | 1240 |
`GET /containers/(id or name)/archive` |
| 1241 | 1241 |
|
| ... | ... |
@@ -1300,7 +1298,7 @@ desired. |
| 1300 | 1300 |
- no such file or directory (**path** does not exist) |
| 1301 | 1301 |
- **500** - server error |
| 1302 | 1302 |
|
| 1303 |
-### Extract an archive of files or folders to a directory in a container |
|
| 1303 |
+#### Extract an archive of files or folders to a directory in a container |
|
| 1304 | 1304 |
|
| 1305 | 1305 |
`PUT /containers/(id or name)/archive` |
| 1306 | 1306 |
|
| ... | ... |
@@ -1348,9 +1346,9 @@ Upload a tar archive to be extracted to a path in the filesystem of container |
| 1348 | 1348 |
- no such file or directory (**path** resource does not exist) |
| 1349 | 1349 |
- **500** – server error |
| 1350 | 1350 |
|
| 1351 |
-## 2.2 Images |
|
| 1351 |
+### 2.2 Images |
|
| 1352 | 1352 |
|
| 1353 |
-### List Images |
|
| 1353 |
+#### List Images |
|
| 1354 | 1354 |
|
| 1355 | 1355 |
`GET /images/json` |
| 1356 | 1356 |
|
| ... | ... |
@@ -1441,7 +1439,7 @@ references on the command line. |
| 1441 | 1441 |
- `label=key` or `label="key=value"` of an image label |
| 1442 | 1442 |
- **filter** - only return images with the specified name |
| 1443 | 1443 |
|
| 1444 |
-### Build image from a Dockerfile |
|
| 1444 |
+#### Build image from a Dockerfile |
|
| 1445 | 1445 |
|
| 1446 | 1446 |
`POST /build` |
| 1447 | 1447 |
|
| ... | ... |
@@ -1545,7 +1543,7 @@ or being killed. |
| 1545 | 1545 |
- **200** – no error |
| 1546 | 1546 |
- **500** – server error |
| 1547 | 1547 |
|
| 1548 |
-### Create an image |
|
| 1548 |
+#### Create an image |
|
| 1549 | 1549 |
|
| 1550 | 1550 |
`POST /images/create` |
| 1551 | 1551 |
|
| ... | ... |
@@ -1593,7 +1591,7 @@ a base64-encoded AuthConfig object. |
| 1593 | 1593 |
|
| 1594 | 1594 |
|
| 1595 | 1595 |
|
| 1596 |
-### Inspect an image |
|
| 1596 |
+#### Inspect an image |
|
| 1597 | 1597 |
|
| 1598 | 1598 |
`GET /images/(name)/json` |
| 1599 | 1599 |
|
| ... | ... |
@@ -1704,7 +1702,7 @@ Return low-level information on the image `name` |
| 1704 | 1704 |
- **404** – no such image |
| 1705 | 1705 |
- **500** – server error |
| 1706 | 1706 |
|
| 1707 |
-### Get the history of an image |
|
| 1707 |
+#### Get the history of an image |
|
| 1708 | 1708 |
|
| 1709 | 1709 |
`GET /images/(name)/history` |
| 1710 | 1710 |
|
| ... | ... |
@@ -1758,7 +1756,7 @@ Return the history of the image `name` |
| 1758 | 1758 |
- **404** – no such image |
| 1759 | 1759 |
- **500** – server error |
| 1760 | 1760 |
|
| 1761 |
-### Push an image on the registry |
|
| 1761 |
+#### Push an image on the registry |
|
| 1762 | 1762 |
|
| 1763 | 1763 |
`POST /images/(name)/push` |
| 1764 | 1764 |
|
| ... | ... |
@@ -1801,7 +1799,7 @@ then be used in the URL. This duplicates the command line's flow. |
| 1801 | 1801 |
- **404** – no such image |
| 1802 | 1802 |
- **500** – server error |
| 1803 | 1803 |
|
| 1804 |
-### Tag an image into a repository |
|
| 1804 |
+#### Tag an image into a repository |
|
| 1805 | 1805 |
|
| 1806 | 1806 |
`POST /images/(name)/tag` |
| 1807 | 1807 |
|
| ... | ... |
@@ -1829,7 +1827,7 @@ Tag the image `name` into a repository |
| 1829 | 1829 |
- **409** – conflict |
| 1830 | 1830 |
- **500** – server error |
| 1831 | 1831 |
|
| 1832 |
-### Remove an image |
|
| 1832 |
+#### Remove an image |
|
| 1833 | 1833 |
|
| 1834 | 1834 |
`DELETE /images/(name)` |
| 1835 | 1835 |
|
| ... | ... |
@@ -1862,7 +1860,7 @@ Remove the image `name` from the filesystem |
| 1862 | 1862 |
- **409** – conflict |
| 1863 | 1863 |
- **500** – server error |
| 1864 | 1864 |
|
| 1865 |
-### Search images |
|
| 1865 |
+#### Search images |
|
| 1866 | 1866 |
|
| 1867 | 1867 |
`GET /images/search` |
| 1868 | 1868 |
|
| ... | ... |
@@ -1915,9 +1913,9 @@ Search for an image on [Docker Hub](https://hub.docker.com). |
| 1915 | 1915 |
- **200** – no error |
| 1916 | 1916 |
- **500** – server error |
| 1917 | 1917 |
|
| 1918 |
-## 2.3 Misc |
|
| 1918 |
+### 2.3 Misc |
|
| 1919 | 1919 |
|
| 1920 |
-### Check auth configuration |
|
| 1920 |
+#### Check auth configuration |
|
| 1921 | 1921 |
|
| 1922 | 1922 |
`POST /auth` |
| 1923 | 1923 |
|
| ... | ... |
@@ -1945,7 +1943,7 @@ Get the default username and email |
| 1945 | 1945 |
- **204** – no error |
| 1946 | 1946 |
- **500** – server error |
| 1947 | 1947 |
|
| 1948 |
-### Display system-wide information |
|
| 1948 |
+#### Display system-wide information |
|
| 1949 | 1949 |
|
| 1950 | 1950 |
`GET /info` |
| 1951 | 1951 |
|
| ... | ... |
@@ -2016,7 +2014,7 @@ Display system-wide information |
| 2016 | 2016 |
- **200** – no error |
| 2017 | 2017 |
- **500** – server error |
| 2018 | 2018 |
|
| 2019 |
-### Show the docker version information |
|
| 2019 |
+#### Show the docker version information |
|
| 2020 | 2020 |
|
| 2021 | 2021 |
`GET /version` |
| 2022 | 2022 |
|
| ... | ... |
@@ -2047,7 +2045,7 @@ Show the docker version information |
| 2047 | 2047 |
- **200** – no error |
| 2048 | 2048 |
- **500** – server error |
| 2049 | 2049 |
|
| 2050 |
-### Ping the docker server |
|
| 2050 |
+#### Ping the docker server |
|
| 2051 | 2051 |
|
| 2052 | 2052 |
`GET /_ping` |
| 2053 | 2053 |
|
| ... | ... |
@@ -2069,7 +2067,7 @@ Ping the docker server |
| 2069 | 2069 |
- **200** - no error |
| 2070 | 2070 |
- **500** - server error |
| 2071 | 2071 |
|
| 2072 |
-### Create a new image from a container's changes |
|
| 2072 |
+#### Create a new image from a container's changes |
|
| 2073 | 2073 |
|
| 2074 | 2074 |
`POST /commit` |
| 2075 | 2075 |
|
| ... | ... |
@@ -2141,7 +2139,7 @@ Create a new image from a container's changes |
| 2141 | 2141 |
- **404** – no such container |
| 2142 | 2142 |
- **500** – server error |
| 2143 | 2143 |
|
| 2144 |
-### Monitor Docker's events |
|
| 2144 |
+#### Monitor Docker's events |
|
| 2145 | 2145 |
|
| 2146 | 2146 |
`GET /events` |
| 2147 | 2147 |
|
| ... | ... |
@@ -2184,7 +2182,7 @@ Docker images report the following events: |
| 2184 | 2184 |
- **200** – no error |
| 2185 | 2185 |
- **500** – server error |
| 2186 | 2186 |
|
| 2187 |
-### Get a tarball containing all images in a repository |
|
| 2187 |
+#### Get a tarball containing all images in a repository |
|
| 2188 | 2188 |
|
| 2189 | 2189 |
`GET /images/(name)/get` |
| 2190 | 2190 |
|
| ... | ... |
@@ -2214,7 +2212,7 @@ See the [image tarball format](#image-tarball-format) for more details. |
| 2214 | 2214 |
- **200** – no error |
| 2215 | 2215 |
- **500** – server error |
| 2216 | 2216 |
|
| 2217 |
-### Get a tarball containing all images |
|
| 2217 |
+#### Get a tarball containing all images |
|
| 2218 | 2218 |
|
| 2219 | 2219 |
`GET /images/get` |
| 2220 | 2220 |
|
| ... | ... |
@@ -2243,7 +2241,7 @@ See the [image tarball format](#image-tarball-format) for more details. |
| 2243 | 2243 |
- **200** – no error |
| 2244 | 2244 |
- **500** – server error |
| 2245 | 2245 |
|
| 2246 |
-### Load a tarball with a set of images and tags into docker |
|
| 2246 |
+#### Load a tarball with a set of images and tags into docker |
|
| 2247 | 2247 |
|
| 2248 | 2248 |
`POST /images/load` |
| 2249 | 2249 |
|
| ... | ... |
@@ -2266,7 +2264,7 @@ See the [image tarball format](#image-tarball-format) for more details. |
| 2266 | 2266 |
- **200** – no error |
| 2267 | 2267 |
- **500** – server error |
| 2268 | 2268 |
|
| 2269 |
-### Image tarball format |
|
| 2269 |
+#### Image tarball format |
|
| 2270 | 2270 |
|
| 2271 | 2271 |
An image tarball contains one directory per image layer (named using its long ID), |
| 2272 | 2272 |
each containing these files: |
| ... | ... |
@@ -2287,7 +2285,7 @@ the root that contains a list of repository and tag names mapped to layer IDs. |
| 2287 | 2287 |
} |
| 2288 | 2288 |
``` |
| 2289 | 2289 |
|
| 2290 |
-### Exec Create |
|
| 2290 |
+#### Exec Create |
|
| 2291 | 2291 |
|
| 2292 | 2292 |
`POST /containers/(id or name)/exec` |
| 2293 | 2293 |
|
| ... | ... |
@@ -2337,7 +2335,7 @@ Sets up an exec instance in a running container `id` |
| 2337 | 2337 |
- **409** - container is paused |
| 2338 | 2338 |
- **500** - server error |
| 2339 | 2339 |
|
| 2340 |
-### Exec Start |
|
| 2340 |
+#### Exec Start |
|
| 2341 | 2341 |
|
| 2342 | 2342 |
`POST /exec/(id)/start` |
| 2343 | 2343 |
|
| ... | ... |
@@ -2379,7 +2377,7 @@ interactive session with the `exec` command. |
| 2379 | 2379 |
|
| 2380 | 2380 |
Similar to the stream behavior of `POST /containers/(id or name)/attach` API |
| 2381 | 2381 |
|
| 2382 |
-### Exec Resize |
|
| 2382 |
+#### Exec Resize |
|
| 2383 | 2383 |
|
| 2384 | 2384 |
`POST /exec/(id)/resize` |
| 2385 | 2385 |
|
| ... | ... |
@@ -2406,7 +2404,7 @@ This API is valid only if `tty` was specified as part of creating and starting t |
| 2406 | 2406 |
- **201** – no error |
| 2407 | 2407 |
- **404** – no such exec instance |
| 2408 | 2408 |
|
| 2409 |
-### Exec Inspect |
|
| 2409 |
+#### Exec Inspect |
|
| 2410 | 2410 |
|
| 2411 | 2411 |
`GET /exec/(id)/json` |
| 2412 | 2412 |
|
| ... | ... |
@@ -2532,9 +2530,9 @@ Return low-level information about the `exec` command `id`. |
| 2532 | 2532 |
- **404** – no such exec instance |
| 2533 | 2533 |
- **500** - server error |
| 2534 | 2534 |
|
| 2535 |
-## 2.4 Volumes |
|
| 2535 |
+### 2.4 Volumes |
|
| 2536 | 2536 |
|
| 2537 |
-### List volumes |
|
| 2537 |
+#### List volumes |
|
| 2538 | 2538 |
|
| 2539 | 2539 |
`GET /volumes` |
| 2540 | 2540 |
|
| ... | ... |
@@ -2566,7 +2564,7 @@ Return low-level information about the `exec` command `id`. |
| 2566 | 2566 |
- **200** - no error |
| 2567 | 2567 |
- **500** - server error |
| 2568 | 2568 |
|
| 2569 |
-### Create a volume |
|
| 2569 |
+#### Create a volume |
|
| 2570 | 2570 |
|
| 2571 | 2571 |
`POST /volumes/create` |
| 2572 | 2572 |
|
| ... | ... |
@@ -2604,7 +2602,7 @@ Create a volume |
| 2604 | 2604 |
- **DriverOpts** - A mapping of driver options and values. These options are |
| 2605 | 2605 |
passed directly to the driver and are driver specific. |
| 2606 | 2606 |
|
| 2607 |
-### Inspect a volume |
|
| 2607 |
+#### Inspect a volume |
|
| 2608 | 2608 |
|
| 2609 | 2609 |
`GET /volumes/(name)` |
| 2610 | 2610 |
|
| ... | ... |
@@ -2631,7 +2629,7 @@ Return low-level information on the volume `name` |
| 2631 | 2631 |
- **404** - no such volume |
| 2632 | 2632 |
- **500** - server error |
| 2633 | 2633 |
|
| 2634 |
-### Remove a volume |
|
| 2634 |
+#### Remove a volume |
|
| 2635 | 2635 |
|
| 2636 | 2636 |
`DELETE /volumes/(name)` |
| 2637 | 2637 |
|
| ... | ... |
@@ -2652,9 +2650,9 @@ Instruct the driver to remove the volume (`name`). |
| 2652 | 2652 |
- **409** - volume is in use and cannot be removed |
| 2653 | 2653 |
- **500** - server error |
| 2654 | 2654 |
|
| 2655 |
-## 2.5 Networks |
|
| 2655 |
+### 2.5 Networks |
|
| 2656 | 2656 |
|
| 2657 |
-### List networks |
|
| 2657 |
+#### List networks |
|
| 2658 | 2658 |
|
| 2659 | 2659 |
`GET /networks` |
| 2660 | 2660 |
|
| ... | ... |
@@ -2735,7 +2733,7 @@ Content-Type: application/json |
| 2735 | 2735 |
- **200** - no error |
| 2736 | 2736 |
- **500** - server error |
| 2737 | 2737 |
|
| 2738 |
-### Inspect network |
|
| 2738 |
+#### Inspect network |
|
| 2739 | 2739 |
|
| 2740 | 2740 |
`GET /networks/<network-id>` |
| 2741 | 2741 |
|
| ... | ... |
@@ -2786,7 +2784,7 @@ Content-Type: application/json |
| 2786 | 2786 |
- **200** - no error |
| 2787 | 2787 |
- **404** - network not found |
| 2788 | 2788 |
|
| 2789 |
-### Create a network |
|
| 2789 |
+#### Create a network |
|
| 2790 | 2790 |
|
| 2791 | 2791 |
`POST /networks/create` |
| 2792 | 2792 |
|
| ... | ... |
@@ -2844,7 +2842,7 @@ Content-Type: application/json |
| 2844 | 2844 |
`{"Subnet": <CIDR>, "IPRange": <CIDR>, "Gateway": <IP address>, "AuxAddress": <device_name:IP address>}`
|
| 2845 | 2845 |
- **Options** - Network specific options to be used by the drivers |
| 2846 | 2846 |
|
| 2847 |
-### Connect a container to a network |
|
| 2847 |
+#### Connect a container to a network |
|
| 2848 | 2848 |
|
| 2849 | 2849 |
`POST /networks/(id)/connect` |
| 2850 | 2850 |
|
| ... | ... |
@@ -2875,7 +2873,7 @@ Content-Type: application/json |
| 2875 | 2875 |
|
| 2876 | 2876 |
- **container** - container-id/name to be connected to the network |
| 2877 | 2877 |
|
| 2878 |
-### Disconnect a container from a network |
|
| 2878 |
+#### Disconnect a container from a network |
|
| 2879 | 2879 |
|
| 2880 | 2880 |
`POST /networks/(id)/disconnect` |
| 2881 | 2881 |
|
| ... | ... |
@@ -2906,7 +2904,7 @@ Content-Type: application/json |
| 2906 | 2906 |
|
| 2907 | 2907 |
- **Container** - container-id/name to be disconnected from a network |
| 2908 | 2908 |
|
| 2909 |
-### Remove a network |
|
| 2909 |
+#### Remove a network |
|
| 2910 | 2910 |
|
| 2911 | 2911 |
`DELETE /networks/(id)` |
| 2912 | 2912 |
|
| ... | ... |
@@ -2926,9 +2924,9 @@ Instruct the driver to remove the network (`id`). |
| 2926 | 2926 |
- **404** - no such network |
| 2927 | 2927 |
- **500** - server error |
| 2928 | 2928 |
|
| 2929 |
-# 3. Going further |
|
| 2929 |
+## 3. Going further |
|
| 2930 | 2930 |
|
| 2931 |
-## 3.1 Inside `docker run` |
|
| 2931 |
+### 3.1 Inside `docker run` |
|
| 2932 | 2932 |
|
| 2933 | 2933 |
As an example, the `docker run` command line makes the following API calls: |
| 2934 | 2934 |
|
| ... | ... |
@@ -2946,7 +2944,7 @@ As an example, the `docker run` command line makes the following API calls: |
| 2946 | 2946 |
|
| 2947 | 2947 |
- If in detached mode or only `stdin` is attached, display the container's id. |
| 2948 | 2948 |
|
| 2949 |
-## 3.2 Hijacking |
|
| 2949 |
+### 3.2 Hijacking |
|
| 2950 | 2950 |
|
| 2951 | 2951 |
In this version of the API, `/attach`, uses hijacking to transport `stdin`, |
| 2952 | 2952 |
`stdout`, and `stderr` on the same socket. |
| ... | ... |
@@ -2961,7 +2959,7 @@ When Docker daemon detects the `Upgrade` header, it switches its status code |
| 2961 | 2961 |
from **200 OK** to **101 UPGRADED** and resends the same headers. |
| 2962 | 2962 |
|
| 2963 | 2963 |
|
| 2964 |
-## 3.3 CORS Requests |
|
| 2964 |
+### 3.3 CORS Requests |
|
| 2965 | 2965 |
|
| 2966 | 2966 |
To set cross origin requests to the Engine API please give values to |
| 2967 | 2967 |
`--api-cors-header` when running Docker in daemon mode. Set * (asterisk) allows all, |
| ... | ... |
@@ -16,9 +16,7 @@ redirect_from: |
| 16 | 16 |
will be rejected. |
| 17 | 17 |
--> |
| 18 | 18 |
|
| 19 |
-# Docker Engine API v1.22 |
|
| 20 |
- |
|
| 21 |
-# 1. Brief introduction |
|
| 19 |
+## 1. Brief introduction |
|
| 22 | 20 |
|
| 23 | 21 |
- The daemon listens on `unix:///var/run/docker.sock` but you can |
| 24 | 22 |
[Bind Docker to another host/port or a Unix socket](../commandline/dockerd.md#bind-docker-to-another-host-port-or-a-unix-socket). |
| ... | ... |
@@ -26,11 +24,11 @@ redirect_from: |
| 26 | 26 |
or `pull`, the HTTP connection is hijacked to transport `stdout`, |
| 27 | 27 |
`stdin` and `stderr`. |
| 28 | 28 |
|
| 29 |
-# 2. Endpoints |
|
| 29 |
+## 2. Endpoints |
|
| 30 | 30 |
|
| 31 |
-## 2.1 Containers |
|
| 31 |
+### 2.1 Containers |
|
| 32 | 32 |
|
| 33 |
-### List containers |
|
| 33 |
+#### List containers |
|
| 34 | 34 |
|
| 35 | 35 |
`GET /containers/json` |
| 36 | 36 |
|
| ... | ... |
@@ -212,7 +210,7 @@ List containers |
| 212 | 212 |
- **400** – bad parameter |
| 213 | 213 |
- **500** – server error |
| 214 | 214 |
|
| 215 |
-### Create a container |
|
| 215 |
+#### Create a container |
|
| 216 | 216 |
|
| 217 | 217 |
`POST /containers/create` |
| 218 | 218 |
|
| ... | ... |
@@ -460,7 +458,7 @@ Create a container |
| 460 | 460 |
- **409** – conflict |
| 461 | 461 |
- **500** – server error |
| 462 | 462 |
|
| 463 |
-### Inspect a container |
|
| 463 |
+#### Inspect a container |
|
| 464 | 464 |
|
| 465 | 465 |
`GET /containers/(id or name)/json` |
| 466 | 466 |
|
| ... | ... |
@@ -663,7 +661,7 @@ Return low-level information on the container `id` |
| 663 | 663 |
- **404** – no such container |
| 664 | 664 |
- **500** – server error |
| 665 | 665 |
|
| 666 |
-### List processes running inside a container |
|
| 666 |
+#### List processes running inside a container |
|
| 667 | 667 |
|
| 668 | 668 |
`GET /containers/(id or name)/top` |
| 669 | 669 |
|
| ... | ... |
@@ -727,7 +725,7 @@ supported on Windows. |
| 727 | 727 |
- **404** – no such container |
| 728 | 728 |
- **500** – server error |
| 729 | 729 |
|
| 730 |
-### Get container logs |
|
| 730 |
+#### Get container logs |
|
| 731 | 731 |
|
| 732 | 732 |
`GET /containers/(id or name)/logs` |
| 733 | 733 |
|
| ... | ... |
@@ -769,7 +767,7 @@ Get `stdout` and `stderr` logs from the container ``id`` |
| 769 | 769 |
- **404** – no such container |
| 770 | 770 |
- **500** – server error |
| 771 | 771 |
|
| 772 |
-### Inspect changes on a container's filesystem |
|
| 772 |
+#### Inspect changes on a container's filesystem |
|
| 773 | 773 |
|
| 774 | 774 |
`GET /containers/(id or name)/changes` |
| 775 | 775 |
|
| ... | ... |
@@ -811,7 +809,7 @@ Values for `Kind`: |
| 811 | 811 |
- **404** – no such container |
| 812 | 812 |
- **500** – server error |
| 813 | 813 |
|
| 814 |
-### Export a container |
|
| 814 |
+#### Export a container |
|
| 815 | 815 |
|
| 816 | 816 |
`GET /containers/(id or name)/export` |
| 817 | 817 |
|
| ... | ... |
@@ -836,7 +834,7 @@ Export the contents of container `id` |
| 836 | 836 |
- **404** – no such container |
| 837 | 837 |
- **500** – server error |
| 838 | 838 |
|
| 839 |
-### Get container stats based on resource usage |
|
| 839 |
+#### Get container stats based on resource usage |
|
| 840 | 840 |
|
| 841 | 841 |
`GET /containers/(id or name)/stats` |
| 842 | 842 |
|
| ... | ... |
@@ -957,7 +955,7 @@ The precpu_stats is the cpu statistic of last read, which is used for calculatin |
| 957 | 957 |
- **404** – no such container |
| 958 | 958 |
- **500** – server error |
| 959 | 959 |
|
| 960 |
-### Resize a container TTY |
|
| 960 |
+#### Resize a container TTY |
|
| 961 | 961 |
|
| 962 | 962 |
`POST /containers/(id or name)/resize` |
| 963 | 963 |
|
| ... | ... |
@@ -984,7 +982,7 @@ Resize the TTY for container with `id`. The unit is number of characters. You m |
| 984 | 984 |
- **404** – No such container |
| 985 | 985 |
- **500** – Cannot resize container |
| 986 | 986 |
|
| 987 |
-### Start a container |
|
| 987 |
+#### Start a container |
|
| 988 | 988 |
|
| 989 | 989 |
`POST /containers/(id or name)/start` |
| 990 | 990 |
|
| ... | ... |
@@ -1015,7 +1013,7 @@ Start the container `id` |
| 1015 | 1015 |
- **404** – no such container |
| 1016 | 1016 |
- **500** – server error |
| 1017 | 1017 |
|
| 1018 |
-### Stop a container |
|
| 1018 |
+#### Stop a container |
|
| 1019 | 1019 |
|
| 1020 | 1020 |
`POST /containers/(id or name)/stop` |
| 1021 | 1021 |
|
| ... | ... |
@@ -1040,7 +1038,7 @@ Stop the container `id` |
| 1040 | 1040 |
- **404** – no such container |
| 1041 | 1041 |
- **500** – server error |
| 1042 | 1042 |
|
| 1043 |
-### Restart a container |
|
| 1043 |
+#### Restart a container |
|
| 1044 | 1044 |
|
| 1045 | 1045 |
`POST /containers/(id or name)/restart` |
| 1046 | 1046 |
|
| ... | ... |
@@ -1064,7 +1062,7 @@ Restart the container `id` |
| 1064 | 1064 |
- **404** – no such container |
| 1065 | 1065 |
- **500** – server error |
| 1066 | 1066 |
|
| 1067 |
-### Kill a container |
|
| 1067 |
+#### Kill a container |
|
| 1068 | 1068 |
|
| 1069 | 1069 |
`POST /containers/(id or name)/kill` |
| 1070 | 1070 |
|
| ... | ... |
@@ -1089,7 +1087,7 @@ Kill the container `id` |
| 1089 | 1089 |
- **404** – no such container |
| 1090 | 1090 |
- **500** – server error |
| 1091 | 1091 |
|
| 1092 |
-### Update a container |
|
| 1092 |
+#### Update a container |
|
| 1093 | 1093 |
|
| 1094 | 1094 |
`POST /containers/(id or name)/update` |
| 1095 | 1095 |
|
| ... | ... |
@@ -1129,7 +1127,7 @@ Update resource configs of one or more containers. |
| 1129 | 1129 |
- **404** – no such container |
| 1130 | 1130 |
- **500** – server error |
| 1131 | 1131 |
|
| 1132 |
-### Rename a container |
|
| 1132 |
+#### Rename a container |
|
| 1133 | 1133 |
|
| 1134 | 1134 |
`POST /containers/(id or name)/rename` |
| 1135 | 1135 |
|
| ... | ... |
@@ -1154,7 +1152,7 @@ Rename the container `id` to a `new_name` |
| 1154 | 1154 |
- **409** - conflict name already assigned |
| 1155 | 1155 |
- **500** – server error |
| 1156 | 1156 |
|
| 1157 |
-### Pause a container |
|
| 1157 |
+#### Pause a container |
|
| 1158 | 1158 |
|
| 1159 | 1159 |
`POST /containers/(id or name)/pause` |
| 1160 | 1160 |
|
| ... | ... |
@@ -1174,7 +1172,7 @@ Pause the container `id` |
| 1174 | 1174 |
- **404** – no such container |
| 1175 | 1175 |
- **500** – server error |
| 1176 | 1176 |
|
| 1177 |
-### Unpause a container |
|
| 1177 |
+#### Unpause a container |
|
| 1178 | 1178 |
|
| 1179 | 1179 |
`POST /containers/(id or name)/unpause` |
| 1180 | 1180 |
|
| ... | ... |
@@ -1194,7 +1192,7 @@ Unpause the container `id` |
| 1194 | 1194 |
- **404** – no such container |
| 1195 | 1195 |
- **500** – server error |
| 1196 | 1196 |
|
| 1197 |
-### Attach to a container |
|
| 1197 |
+#### Attach to a container |
|
| 1198 | 1198 |
|
| 1199 | 1199 |
`POST /containers/(id or name)/attach` |
| 1200 | 1200 |
|
| ... | ... |
@@ -1283,7 +1281,7 @@ The simplest way to implement the Attach protocol is the following: |
| 1283 | 1283 |
4. Read the extracted size and output it on the correct output. |
| 1284 | 1284 |
5. Goto 1. |
| 1285 | 1285 |
|
| 1286 |
-### Attach to a container (websocket) |
|
| 1286 |
+#### Attach to a container (websocket) |
|
| 1287 | 1287 |
|
| 1288 | 1288 |
`GET /containers/(id or name)/attach/ws` |
| 1289 | 1289 |
|
| ... | ... |
@@ -1323,7 +1321,7 @@ Implements websocket protocol handshake according to [RFC 6455](http://tools.iet |
| 1323 | 1323 |
- **404** – no such container |
| 1324 | 1324 |
- **500** – server error |
| 1325 | 1325 |
|
| 1326 |
-### Wait a container |
|
| 1326 |
+#### Wait a container |
|
| 1327 | 1327 |
|
| 1328 | 1328 |
`POST /containers/(id or name)/wait` |
| 1329 | 1329 |
|
| ... | ... |
@@ -1346,7 +1344,7 @@ Block until container `id` stops, then returns the exit code |
| 1346 | 1346 |
- **404** – no such container |
| 1347 | 1347 |
- **500** – server error |
| 1348 | 1348 |
|
| 1349 |
-### Remove a container |
|
| 1349 |
+#### Remove a container |
|
| 1350 | 1350 |
|
| 1351 | 1351 |
`DELETE /containers/(id or name)` |
| 1352 | 1352 |
|
| ... | ... |
@@ -1375,7 +1373,7 @@ Remove the container `id` from the filesystem |
| 1375 | 1375 |
- **409** – conflict |
| 1376 | 1376 |
- **500** – server error |
| 1377 | 1377 |
|
| 1378 |
-### Copy files or folders from a container |
|
| 1378 |
+#### Copy files or folders from a container |
|
| 1379 | 1379 |
|
| 1380 | 1380 |
`POST /containers/(id or name)/copy` |
| 1381 | 1381 |
|
| ... | ... |
@@ -1407,14 +1405,14 @@ Copy files or folders of container `id` |
| 1407 | 1407 |
- **404** – no such container |
| 1408 | 1408 |
- **500** – server error |
| 1409 | 1409 |
|
| 1410 |
-### Retrieving information about files and folders in a container |
|
| 1410 |
+#### Retrieving information about files and folders in a container |
|
| 1411 | 1411 |
|
| 1412 | 1412 |
`HEAD /containers/(id or name)/archive` |
| 1413 | 1413 |
|
| 1414 | 1414 |
See the description of the `X-Docker-Container-Path-Stat` header in the |
| 1415 | 1415 |
following section. |
| 1416 | 1416 |
|
| 1417 |
-### Get an archive of a filesystem resource in a container |
|
| 1417 |
+#### Get an archive of a filesystem resource in a container |
|
| 1418 | 1418 |
|
| 1419 | 1419 |
`GET /containers/(id or name)/archive` |
| 1420 | 1420 |
|
| ... | ... |
@@ -1479,7 +1477,7 @@ desired. |
| 1479 | 1479 |
- no such file or directory (**path** does not exist) |
| 1480 | 1480 |
- **500** - server error |
| 1481 | 1481 |
|
| 1482 |
-### Extract an archive of files or folders to a directory in a container |
|
| 1482 |
+#### Extract an archive of files or folders to a directory in a container |
|
| 1483 | 1483 |
|
| 1484 | 1484 |
`PUT /containers/(id or name)/archive` |
| 1485 | 1485 |
|
| ... | ... |
@@ -1527,9 +1525,9 @@ Upload a tar archive to be extracted to a path in the filesystem of container |
| 1527 | 1527 |
- no such file or directory (**path** resource does not exist) |
| 1528 | 1528 |
- **500** – server error |
| 1529 | 1529 |
|
| 1530 |
-## 2.2 Images |
|
| 1530 |
+### 2.2 Images |
|
| 1531 | 1531 |
|
| 1532 |
-### List Images |
|
| 1532 |
+#### List Images |
|
| 1533 | 1533 |
|
| 1534 | 1534 |
`GET /images/json` |
| 1535 | 1535 |
|
| ... | ... |
@@ -1620,7 +1618,7 @@ references on the command line. |
| 1620 | 1620 |
- `label=key` or `label="key=value"` of an image label |
| 1621 | 1621 |
- **filter** - only return images with the specified name |
| 1622 | 1622 |
|
| 1623 |
-### Build image from a Dockerfile |
|
| 1623 |
+#### Build image from a Dockerfile |
|
| 1624 | 1624 |
|
| 1625 | 1625 |
`POST /build` |
| 1626 | 1626 |
|
| ... | ... |
@@ -1725,7 +1723,7 @@ or being killed. |
| 1725 | 1725 |
- **200** – no error |
| 1726 | 1726 |
- **500** – server error |
| 1727 | 1727 |
|
| 1728 |
-### Create an image |
|
| 1728 |
+#### Create an image |
|
| 1729 | 1729 |
|
| 1730 | 1730 |
`POST /images/create` |
| 1731 | 1731 |
|
| ... | ... |
@@ -1791,7 +1789,7 @@ a base64-encoded AuthConfig object. |
| 1791 | 1791 |
|
| 1792 | 1792 |
|
| 1793 | 1793 |
|
| 1794 |
-### Inspect an image |
|
| 1794 |
+#### Inspect an image |
|
| 1795 | 1795 |
|
| 1796 | 1796 |
`GET /images/(name)/json` |
| 1797 | 1797 |
|
| ... | ... |
@@ -1902,7 +1900,7 @@ Return low-level information on the image `name` |
| 1902 | 1902 |
- **404** – no such image |
| 1903 | 1903 |
- **500** – server error |
| 1904 | 1904 |
|
| 1905 |
-### Get the history of an image |
|
| 1905 |
+#### Get the history of an image |
|
| 1906 | 1906 |
|
| 1907 | 1907 |
`GET /images/(name)/history` |
| 1908 | 1908 |
|
| ... | ... |
@@ -1956,7 +1954,7 @@ Return the history of the image `name` |
| 1956 | 1956 |
- **404** – no such image |
| 1957 | 1957 |
- **500** – server error |
| 1958 | 1958 |
|
| 1959 |
-### Push an image on the registry |
|
| 1959 |
+#### Push an image on the registry |
|
| 1960 | 1960 |
|
| 1961 | 1961 |
`POST /images/(name)/push` |
| 1962 | 1962 |
|
| ... | ... |
@@ -2018,7 +2016,7 @@ The push is cancelled if the HTTP connection is closed. |
| 2018 | 2018 |
- **404** – no such image |
| 2019 | 2019 |
- **500** – server error |
| 2020 | 2020 |
|
| 2021 |
-### Tag an image into a repository |
|
| 2021 |
+#### Tag an image into a repository |
|
| 2022 | 2022 |
|
| 2023 | 2023 |
`POST /images/(name)/tag` |
| 2024 | 2024 |
|
| ... | ... |
@@ -2046,7 +2044,7 @@ Tag the image `name` into a repository |
| 2046 | 2046 |
- **409** – conflict |
| 2047 | 2047 |
- **500** – server error |
| 2048 | 2048 |
|
| 2049 |
-### Remove an image |
|
| 2049 |
+#### Remove an image |
|
| 2050 | 2050 |
|
| 2051 | 2051 |
`DELETE /images/(name)` |
| 2052 | 2052 |
|
| ... | ... |
@@ -2079,7 +2077,7 @@ Remove the image `name` from the filesystem |
| 2079 | 2079 |
- **409** – conflict |
| 2080 | 2080 |
- **500** – server error |
| 2081 | 2081 |
|
| 2082 |
-### Search images |
|
| 2082 |
+#### Search images |
|
| 2083 | 2083 |
|
| 2084 | 2084 |
`GET /images/search` |
| 2085 | 2085 |
|
| ... | ... |
@@ -2132,9 +2130,9 @@ Search for an image on [Docker Hub](https://hub.docker.com). |
| 2132 | 2132 |
- **200** – no error |
| 2133 | 2133 |
- **500** – server error |
| 2134 | 2134 |
|
| 2135 |
-## 2.3 Misc |
|
| 2135 |
+### 2.3 Misc |
|
| 2136 | 2136 |
|
| 2137 |
-### Check auth configuration |
|
| 2137 |
+#### Check auth configuration |
|
| 2138 | 2138 |
|
| 2139 | 2139 |
`POST /auth` |
| 2140 | 2140 |
|
| ... | ... |
@@ -2162,7 +2160,7 @@ Get the default username and email |
| 2162 | 2162 |
- **204** – no error |
| 2163 | 2163 |
- **500** – server error |
| 2164 | 2164 |
|
| 2165 |
-### Display system-wide information |
|
| 2165 |
+#### Display system-wide information |
|
| 2166 | 2166 |
|
| 2167 | 2167 |
`GET /info` |
| 2168 | 2168 |
|
| ... | ... |
@@ -2249,7 +2247,7 @@ Display system-wide information |
| 2249 | 2249 |
- **200** – no error |
| 2250 | 2250 |
- **500** – server error |
| 2251 | 2251 |
|
| 2252 |
-### Show the docker version information |
|
| 2252 |
+#### Show the docker version information |
|
| 2253 | 2253 |
|
| 2254 | 2254 |
`GET /version` |
| 2255 | 2255 |
|
| ... | ... |
@@ -2281,7 +2279,7 @@ Show the docker version information |
| 2281 | 2281 |
- **200** – no error |
| 2282 | 2282 |
- **500** – server error |
| 2283 | 2283 |
|
| 2284 |
-### Ping the docker server |
|
| 2284 |
+#### Ping the docker server |
|
| 2285 | 2285 |
|
| 2286 | 2286 |
`GET /_ping` |
| 2287 | 2287 |
|
| ... | ... |
@@ -2303,7 +2301,7 @@ Ping the docker server |
| 2303 | 2303 |
- **200** - no error |
| 2304 | 2304 |
- **500** - server error |
| 2305 | 2305 |
|
| 2306 |
-### Create a new image from a container's changes |
|
| 2306 |
+#### Create a new image from a container's changes |
|
| 2307 | 2307 |
|
| 2308 | 2308 |
`POST /commit` |
| 2309 | 2309 |
|
| ... | ... |
@@ -2375,7 +2373,7 @@ Create a new image from a container's changes |
| 2375 | 2375 |
- **404** – no such container |
| 2376 | 2376 |
- **500** – server error |
| 2377 | 2377 |
|
| 2378 |
-### Monitor Docker's events |
|
| 2378 |
+#### Monitor Docker's events |
|
| 2379 | 2379 |
|
| 2380 | 2380 |
`GET /events` |
| 2381 | 2381 |
|
| ... | ... |
@@ -2575,7 +2573,7 @@ Docker networks report the following events: |
| 2575 | 2575 |
- **200** – no error |
| 2576 | 2576 |
- **500** – server error |
| 2577 | 2577 |
|
| 2578 |
-### Get a tarball containing all images in a repository |
|
| 2578 |
+#### Get a tarball containing all images in a repository |
|
| 2579 | 2579 |
|
| 2580 | 2580 |
`GET /images/(name)/get` |
| 2581 | 2581 |
|
| ... | ... |
@@ -2605,7 +2603,7 @@ See the [image tarball format](#image-tarball-format) for more details. |
| 2605 | 2605 |
- **200** – no error |
| 2606 | 2606 |
- **500** – server error |
| 2607 | 2607 |
|
| 2608 |
-### Get a tarball containing all images |
|
| 2608 |
+#### Get a tarball containing all images |
|
| 2609 | 2609 |
|
| 2610 | 2610 |
`GET /images/get` |
| 2611 | 2611 |
|
| ... | ... |
@@ -2634,7 +2632,7 @@ See the [image tarball format](#image-tarball-format) for more details. |
| 2634 | 2634 |
- **200** – no error |
| 2635 | 2635 |
- **500** – server error |
| 2636 | 2636 |
|
| 2637 |
-### Load a tarball with a set of images and tags into docker |
|
| 2637 |
+#### Load a tarball with a set of images and tags into docker |
|
| 2638 | 2638 |
|
| 2639 | 2639 |
`POST /images/load` |
| 2640 | 2640 |
|
| ... | ... |
@@ -2657,7 +2655,7 @@ See the [image tarball format](#image-tarball-format) for more details. |
| 2657 | 2657 |
- **200** – no error |
| 2658 | 2658 |
- **500** – server error |
| 2659 | 2659 |
|
| 2660 |
-### Image tarball format |
|
| 2660 |
+#### Image tarball format |
|
| 2661 | 2661 |
|
| 2662 | 2662 |
An image tarball contains one directory per image layer (named using its long ID), |
| 2663 | 2663 |
each containing these files: |
| ... | ... |
@@ -2678,7 +2676,7 @@ the root that contains a list of repository and tag names mapped to layer IDs. |
| 2678 | 2678 |
} |
| 2679 | 2679 |
``` |
| 2680 | 2680 |
|
| 2681 |
-### Exec Create |
|
| 2681 |
+#### Exec Create |
|
| 2682 | 2682 |
|
| 2683 | 2683 |
`POST /containers/(id or name)/exec` |
| 2684 | 2684 |
|
| ... | ... |
@@ -2732,7 +2730,7 @@ Sets up an exec instance in a running container `id` |
| 2732 | 2732 |
- **409** - container is paused |
| 2733 | 2733 |
- **500** - server error |
| 2734 | 2734 |
|
| 2735 |
-### Exec Start |
|
| 2735 |
+#### Exec Start |
|
| 2736 | 2736 |
|
| 2737 | 2737 |
`POST /exec/(id)/start` |
| 2738 | 2738 |
|
| ... | ... |
@@ -2774,7 +2772,7 @@ interactive session with the `exec` command. |
| 2774 | 2774 |
|
| 2775 | 2775 |
Similar to the stream behavior of `POST /containers/(id or name)/attach` API |
| 2776 | 2776 |
|
| 2777 |
-### Exec Resize |
|
| 2777 |
+#### Exec Resize |
|
| 2778 | 2778 |
|
| 2779 | 2779 |
`POST /exec/(id)/resize` |
| 2780 | 2780 |
|
| ... | ... |
@@ -2801,7 +2799,7 @@ This API is valid only if `tty` was specified as part of creating and starting t |
| 2801 | 2801 |
- **201** – no error |
| 2802 | 2802 |
- **404** – no such exec instance |
| 2803 | 2803 |
|
| 2804 |
-### Exec Inspect |
|
| 2804 |
+#### Exec Inspect |
|
| 2805 | 2805 |
|
| 2806 | 2806 |
`GET /exec/(id)/json` |
| 2807 | 2807 |
|
| ... | ... |
@@ -2844,9 +2842,9 @@ Return low-level information about the `exec` command `id`. |
| 2844 | 2844 |
- **404** – no such exec instance |
| 2845 | 2845 |
- **500** - server error |
| 2846 | 2846 |
|
| 2847 |
-## 2.4 Volumes |
|
| 2847 |
+### 2.4 Volumes |
|
| 2848 | 2848 |
|
| 2849 |
-### List volumes |
|
| 2849 |
+#### List volumes |
|
| 2850 | 2850 |
|
| 2851 | 2851 |
`GET /volumes` |
| 2852 | 2852 |
|
| ... | ... |
@@ -2879,7 +2877,7 @@ Return low-level information about the `exec` command `id`. |
| 2879 | 2879 |
- **200** - no error |
| 2880 | 2880 |
- **500** - server error |
| 2881 | 2881 |
|
| 2882 |
-### Create a volume |
|
| 2882 |
+#### Create a volume |
|
| 2883 | 2883 |
|
| 2884 | 2884 |
`POST /volumes/create` |
| 2885 | 2885 |
|
| ... | ... |
@@ -2917,7 +2915,7 @@ Create a volume |
| 2917 | 2917 |
- **DriverOpts** - A mapping of driver options and values. These options are |
| 2918 | 2918 |
passed directly to the driver and are driver specific. |
| 2919 | 2919 |
|
| 2920 |
-### Inspect a volume |
|
| 2920 |
+#### Inspect a volume |
|
| 2921 | 2921 |
|
| 2922 | 2922 |
`GET /volumes/(name)` |
| 2923 | 2923 |
|
| ... | ... |
@@ -2944,7 +2942,7 @@ Return low-level information on the volume `name` |
| 2944 | 2944 |
- **404** - no such volume |
| 2945 | 2945 |
- **500** - server error |
| 2946 | 2946 |
|
| 2947 |
-### Remove a volume |
|
| 2947 |
+#### Remove a volume |
|
| 2948 | 2948 |
|
| 2949 | 2949 |
`DELETE /volumes/(name)` |
| 2950 | 2950 |
|
| ... | ... |
@@ -2965,9 +2963,9 @@ Instruct the driver to remove the volume (`name`). |
| 2965 | 2965 |
- **409** - volume is in use and cannot be removed |
| 2966 | 2966 |
- **500** - server error |
| 2967 | 2967 |
|
| 2968 |
-## 2.5 Networks |
|
| 2968 |
+### 2.5 Networks |
|
| 2969 | 2969 |
|
| 2970 |
-### List networks |
|
| 2970 |
+#### List networks |
|
| 2971 | 2971 |
|
| 2972 | 2972 |
`GET /networks` |
| 2973 | 2973 |
|
| ... | ... |
@@ -3051,7 +3049,7 @@ Content-Type: application/json |
| 3051 | 3051 |
- **200** - no error |
| 3052 | 3052 |
- **500** - server error |
| 3053 | 3053 |
|
| 3054 |
-### Inspect network |
|
| 3054 |
+#### Inspect network |
|
| 3055 | 3055 |
|
| 3056 | 3056 |
`GET /networks/<network-id>` |
| 3057 | 3057 |
|
| ... | ... |
@@ -3107,7 +3105,7 @@ Content-Type: application/json |
| 3107 | 3107 |
- **200** - no error |
| 3108 | 3108 |
- **404** - network not found |
| 3109 | 3109 |
|
| 3110 |
-### Create a network |
|
| 3110 |
+#### Create a network |
|
| 3111 | 3111 |
|
| 3112 | 3112 |
`POST /networks/create` |
| 3113 | 3113 |
|
| ... | ... |
@@ -3174,7 +3172,7 @@ Content-Type: application/json |
| 3174 | 3174 |
- **Options** - Driver-specific options, specified as a map: `{"option":"value" [,"option2":"value2"]}`
|
| 3175 | 3175 |
- **Options** - Network specific options to be used by the drivers |
| 3176 | 3176 |
|
| 3177 |
-### Connect a container to a network |
|
| 3177 |
+#### Connect a container to a network |
|
| 3178 | 3178 |
|
| 3179 | 3179 |
`POST /networks/(id)/connect` |
| 3180 | 3180 |
|
| ... | ... |
@@ -3211,7 +3209,7 @@ Content-Type: application/json |
| 3211 | 3211 |
|
| 3212 | 3212 |
- **container** - container-id/name to be connected to the network |
| 3213 | 3213 |
|
| 3214 |
-### Disconnect a container from a network |
|
| 3214 |
+#### Disconnect a container from a network |
|
| 3215 | 3215 |
|
| 3216 | 3216 |
`POST /networks/(id)/disconnect` |
| 3217 | 3217 |
|
| ... | ... |
@@ -3244,7 +3242,7 @@ Content-Type: application/json |
| 3244 | 3244 |
- **Container** - container-id/name to be disconnected from a network |
| 3245 | 3245 |
- **Force** - Force the container to disconnect from a network |
| 3246 | 3246 |
|
| 3247 |
-### Remove a network |
|
| 3247 |
+#### Remove a network |
|
| 3248 | 3248 |
|
| 3249 | 3249 |
`DELETE /networks/(id)` |
| 3250 | 3250 |
|
| ... | ... |
@@ -3264,9 +3262,9 @@ Instruct the driver to remove the network (`id`). |
| 3264 | 3264 |
- **404** - no such network |
| 3265 | 3265 |
- **500** - server error |
| 3266 | 3266 |
|
| 3267 |
-# 3. Going further |
|
| 3267 |
+## 3. Going further |
|
| 3268 | 3268 |
|
| 3269 |
-## 3.1 Inside `docker run` |
|
| 3269 |
+### 3.1 Inside `docker run` |
|
| 3270 | 3270 |
|
| 3271 | 3271 |
As an example, the `docker run` command line makes the following API calls: |
| 3272 | 3272 |
|
| ... | ... |
@@ -3284,7 +3282,7 @@ As an example, the `docker run` command line makes the following API calls: |
| 3284 | 3284 |
|
| 3285 | 3285 |
- If in detached mode or only `stdin` is attached, display the container's id. |
| 3286 | 3286 |
|
| 3287 |
-## 3.2 Hijacking |
|
| 3287 |
+### 3.2 Hijacking |
|
| 3288 | 3288 |
|
| 3289 | 3289 |
In this version of the API, `/attach`, uses hijacking to transport `stdin`, |
| 3290 | 3290 |
`stdout`, and `stderr` on the same socket. |
| ... | ... |
@@ -3299,7 +3297,7 @@ When Docker daemon detects the `Upgrade` header, it switches its status code |
| 3299 | 3299 |
from **200 OK** to **101 UPGRADED** and resends the same headers. |
| 3300 | 3300 |
|
| 3301 | 3301 |
|
| 3302 |
-## 3.3 CORS Requests |
|
| 3302 |
+### 3.3 CORS Requests |
|
| 3303 | 3303 |
|
| 3304 | 3304 |
To set cross origin requests to the Engine API please give values to |
| 3305 | 3305 |
`--api-cors-header` when running Docker in daemon mode. Set * (asterisk) allows all, |
| ... | ... |
@@ -16,8 +16,6 @@ redirect_from: |
| 16 | 16 |
will be rejected. |
| 17 | 17 |
--> |
| 18 | 18 |
|
| 19 |
-# Docker Engine API v1.23 |
|
| 20 |
- |
|
| 21 | 19 |
## 1. Brief introduction |
| 22 | 20 |
|
| 23 | 21 |
- The daemon listens on `unix:///var/run/docker.sock` but you can |
| ... | ... |
@@ -28,11 +26,11 @@ redirect_from: |
| 28 | 28 |
- When the client API version is newer than the daemon's, these calls return an HTTP |
| 29 | 29 |
`400 Bad Request` error message. |
| 30 | 30 |
|
| 31 |
-# 2. Endpoints |
|
| 31 |
+## 2. Endpoints |
|
| 32 | 32 |
|
| 33 |
-## 2.1 Containers |
|
| 33 |
+### 2.1 Containers |
|
| 34 | 34 |
|
| 35 |
-### List containers |
|
| 35 |
+#### List containers |
|
| 36 | 36 |
|
| 37 | 37 |
`GET /containers/json` |
| 38 | 38 |
|
| ... | ... |
@@ -236,7 +234,7 @@ List containers |
| 236 | 236 |
- **400** – bad parameter |
| 237 | 237 |
- **500** – server error |
| 238 | 238 |
|
| 239 |
-### Create a container |
|
| 239 |
+#### Create a container |
|
| 240 | 240 |
|
| 241 | 241 |
`POST /containers/create` |
| 242 | 242 |
|
| ... | ... |
@@ -488,7 +486,7 @@ Create a container |
| 488 | 488 |
- **409** – conflict |
| 489 | 489 |
- **500** – server error |
| 490 | 490 |
|
| 491 |
-### Inspect a container |
|
| 491 |
+#### Inspect a container |
|
| 492 | 492 |
|
| 493 | 493 |
`GET /containers/(id or name)/json` |
| 494 | 494 |
|
| ... | ... |
@@ -691,7 +689,7 @@ Return low-level information on the container `id` |
| 691 | 691 |
- **404** – no such container |
| 692 | 692 |
- **500** – server error |
| 693 | 693 |
|
| 694 |
-### List processes running inside a container |
|
| 694 |
+#### List processes running inside a container |
|
| 695 | 695 |
|
| 696 | 696 |
`GET /containers/(id or name)/top` |
| 697 | 697 |
|
| ... | ... |
@@ -755,7 +753,7 @@ supported on Windows. |
| 755 | 755 |
- **404** – no such container |
| 756 | 756 |
- **500** – server error |
| 757 | 757 |
|
| 758 |
-### Get container logs |
|
| 758 |
+#### Get container logs |
|
| 759 | 759 |
|
| 760 | 760 |
`GET /containers/(id or name)/logs` |
| 761 | 761 |
|
| ... | ... |
@@ -797,7 +795,7 @@ Get `stdout` and `stderr` logs from the container ``id`` |
| 797 | 797 |
- **404** – no such container |
| 798 | 798 |
- **500** – server error |
| 799 | 799 |
|
| 800 |
-### Inspect changes on a container's filesystem |
|
| 800 |
+#### Inspect changes on a container's filesystem |
|
| 801 | 801 |
|
| 802 | 802 |
`GET /containers/(id or name)/changes` |
| 803 | 803 |
|
| ... | ... |
@@ -839,7 +837,7 @@ Values for `Kind`: |
| 839 | 839 |
- **404** – no such container |
| 840 | 840 |
- **500** – server error |
| 841 | 841 |
|
| 842 |
-### Export a container |
|
| 842 |
+#### Export a container |
|
| 843 | 843 |
|
| 844 | 844 |
`GET /containers/(id or name)/export` |
| 845 | 845 |
|
| ... | ... |
@@ -864,7 +862,7 @@ Export the contents of container `id` |
| 864 | 864 |
- **404** – no such container |
| 865 | 865 |
- **500** – server error |
| 866 | 866 |
|
| 867 |
-### Get container stats based on resource usage |
|
| 867 |
+#### Get container stats based on resource usage |
|
| 868 | 868 |
|
| 869 | 869 |
`GET /containers/(id or name)/stats` |
| 870 | 870 |
|
| ... | ... |
@@ -988,7 +986,7 @@ The precpu_stats is the cpu statistic of last read, which is used for calculatin |
| 988 | 988 |
- **404** – no such container |
| 989 | 989 |
- **500** – server error |
| 990 | 990 |
|
| 991 |
-### Resize a container TTY |
|
| 991 |
+#### Resize a container TTY |
|
| 992 | 992 |
|
| 993 | 993 |
`POST /containers/(id or name)/resize` |
| 994 | 994 |
|
| ... | ... |
@@ -1015,7 +1013,7 @@ Resize the TTY for container with `id`. The unit is number of characters. You m |
| 1015 | 1015 |
- **404** – No such container |
| 1016 | 1016 |
- **500** – Cannot resize container |
| 1017 | 1017 |
|
| 1018 |
-### Start a container |
|
| 1018 |
+#### Start a container |
|
| 1019 | 1019 |
|
| 1020 | 1020 |
`POST /containers/(id or name)/start` |
| 1021 | 1021 |
|
| ... | ... |
@@ -1046,7 +1044,7 @@ Start the container `id` |
| 1046 | 1046 |
- **404** – no such container |
| 1047 | 1047 |
- **500** – server error |
| 1048 | 1048 |
|
| 1049 |
-### Stop a container |
|
| 1049 |
+#### Stop a container |
|
| 1050 | 1050 |
|
| 1051 | 1051 |
`POST /containers/(id or name)/stop` |
| 1052 | 1052 |
|
| ... | ... |
@@ -1071,7 +1069,7 @@ Stop the container `id` |
| 1071 | 1071 |
- **404** – no such container |
| 1072 | 1072 |
- **500** – server error |
| 1073 | 1073 |
|
| 1074 |
-### Restart a container |
|
| 1074 |
+#### Restart a container |
|
| 1075 | 1075 |
|
| 1076 | 1076 |
`POST /containers/(id or name)/restart` |
| 1077 | 1077 |
|
| ... | ... |
@@ -1095,7 +1093,7 @@ Restart the container `id` |
| 1095 | 1095 |
- **404** – no such container |
| 1096 | 1096 |
- **500** – server error |
| 1097 | 1097 |
|
| 1098 |
-### Kill a container |
|
| 1098 |
+#### Kill a container |
|
| 1099 | 1099 |
|
| 1100 | 1100 |
`POST /containers/(id or name)/kill` |
| 1101 | 1101 |
|
| ... | ... |
@@ -1120,7 +1118,7 @@ Kill the container `id` |
| 1120 | 1120 |
- **404** – no such container |
| 1121 | 1121 |
- **500** – server error |
| 1122 | 1122 |
|
| 1123 |
-### Update a container |
|
| 1123 |
+#### Update a container |
|
| 1124 | 1124 |
|
| 1125 | 1125 |
`POST /containers/(id or name)/update` |
| 1126 | 1126 |
|
| ... | ... |
@@ -1164,7 +1162,7 @@ Update configuration of one or more containers. |
| 1164 | 1164 |
- **404** – no such container |
| 1165 | 1165 |
- **500** – server error |
| 1166 | 1166 |
|
| 1167 |
-### Rename a container |
|
| 1167 |
+#### Rename a container |
|
| 1168 | 1168 |
|
| 1169 | 1169 |
`POST /containers/(id or name)/rename` |
| 1170 | 1170 |
|
| ... | ... |
@@ -1189,7 +1187,7 @@ Rename the container `id` to a `new_name` |
| 1189 | 1189 |
- **409** - conflict name already assigned |
| 1190 | 1190 |
- **500** – server error |
| 1191 | 1191 |
|
| 1192 |
-### Pause a container |
|
| 1192 |
+#### Pause a container |
|
| 1193 | 1193 |
|
| 1194 | 1194 |
`POST /containers/(id or name)/pause` |
| 1195 | 1195 |
|
| ... | ... |
@@ -1209,7 +1207,7 @@ Pause the container `id` |
| 1209 | 1209 |
- **404** – no such container |
| 1210 | 1210 |
- **500** – server error |
| 1211 | 1211 |
|
| 1212 |
-### Unpause a container |
|
| 1212 |
+#### Unpause a container |
|
| 1213 | 1213 |
|
| 1214 | 1214 |
`POST /containers/(id or name)/unpause` |
| 1215 | 1215 |
|
| ... | ... |
@@ -1229,7 +1227,7 @@ Unpause the container `id` |
| 1229 | 1229 |
- **404** – no such container |
| 1230 | 1230 |
- **500** – server error |
| 1231 | 1231 |
|
| 1232 |
-### Attach to a container |
|
| 1232 |
+#### Attach to a container |
|
| 1233 | 1233 |
|
| 1234 | 1234 |
`POST /containers/(id or name)/attach` |
| 1235 | 1235 |
|
| ... | ... |
@@ -1318,7 +1316,7 @@ The simplest way to implement the Attach protocol is the following: |
| 1318 | 1318 |
4. Read the extracted size and output it on the correct output. |
| 1319 | 1319 |
5. Goto 1. |
| 1320 | 1320 |
|
| 1321 |
-### Attach to a container (websocket) |
|
| 1321 |
+#### Attach to a container (websocket) |
|
| 1322 | 1322 |
|
| 1323 | 1323 |
`GET /containers/(id or name)/attach/ws` |
| 1324 | 1324 |
|
| ... | ... |
@@ -1358,7 +1356,7 @@ Implements websocket protocol handshake according to [RFC 6455](http://tools.iet |
| 1358 | 1358 |
- **404** – no such container |
| 1359 | 1359 |
- **500** – server error |
| 1360 | 1360 |
|
| 1361 |
-### Wait a container |
|
| 1361 |
+#### Wait a container |
|
| 1362 | 1362 |
|
| 1363 | 1363 |
`POST /containers/(id or name)/wait` |
| 1364 | 1364 |
|
| ... | ... |
@@ -1381,7 +1379,7 @@ Block until container `id` stops, then returns the exit code |
| 1381 | 1381 |
- **404** – no such container |
| 1382 | 1382 |
- **500** – server error |
| 1383 | 1383 |
|
| 1384 |
-### Remove a container |
|
| 1384 |
+#### Remove a container |
|
| 1385 | 1385 |
|
| 1386 | 1386 |
`DELETE /containers/(id or name)` |
| 1387 | 1387 |
|
| ... | ... |
@@ -1410,7 +1408,7 @@ Remove the container `id` from the filesystem |
| 1410 | 1410 |
- **409** – conflict |
| 1411 | 1411 |
- **500** – server error |
| 1412 | 1412 |
|
| 1413 |
-### Copy files or folders from a container |
|
| 1413 |
+#### Copy files or folders from a container |
|
| 1414 | 1414 |
|
| 1415 | 1415 |
`POST /containers/(id or name)/copy` |
| 1416 | 1416 |
|
| ... | ... |
@@ -1442,14 +1440,14 @@ Copy files or folders of container `id` |
| 1442 | 1442 |
- **404** – no such container |
| 1443 | 1443 |
- **500** – server error |
| 1444 | 1444 |
|
| 1445 |
-### Retrieving information about files and folders in a container |
|
| 1445 |
+#### Retrieving information about files and folders in a container |
|
| 1446 | 1446 |
|
| 1447 | 1447 |
`HEAD /containers/(id or name)/archive` |
| 1448 | 1448 |
|
| 1449 | 1449 |
See the description of the `X-Docker-Container-Path-Stat` header in the |
| 1450 | 1450 |
following section. |
| 1451 | 1451 |
|
| 1452 |
-### Get an archive of a filesystem resource in a container |
|
| 1452 |
+#### Get an archive of a filesystem resource in a container |
|
| 1453 | 1453 |
|
| 1454 | 1454 |
`GET /containers/(id or name)/archive` |
| 1455 | 1455 |
|
| ... | ... |
@@ -1514,7 +1512,7 @@ desired. |
| 1514 | 1514 |
- no such file or directory (**path** does not exist) |
| 1515 | 1515 |
- **500** - server error |
| 1516 | 1516 |
|
| 1517 |
-### Extract an archive of files or folders to a directory in a container |
|
| 1517 |
+#### Extract an archive of files or folders to a directory in a container |
|
| 1518 | 1518 |
|
| 1519 | 1519 |
`PUT /containers/(id or name)/archive` |
| 1520 | 1520 |
|
| ... | ... |
@@ -1562,9 +1560,9 @@ Upload a tar archive to be extracted to a path in the filesystem of container |
| 1562 | 1562 |
- no such file or directory (**path** resource does not exist) |
| 1563 | 1563 |
- **500** – server error |
| 1564 | 1564 |
|
| 1565 |
-## 2.2 Images |
|
| 1565 |
+### 2.2 Images |
|
| 1566 | 1566 |
|
| 1567 |
-### List Images |
|
| 1567 |
+#### List Images |
|
| 1568 | 1568 |
|
| 1569 | 1569 |
`GET /images/json` |
| 1570 | 1570 |
|
| ... | ... |
@@ -1655,7 +1653,7 @@ references on the command line. |
| 1655 | 1655 |
- `label=key` or `label="key=value"` of an image label |
| 1656 | 1656 |
- **filter** - only return images with the specified name |
| 1657 | 1657 |
|
| 1658 |
-### Build image from a Dockerfile |
|
| 1658 |
+#### Build image from a Dockerfile |
|
| 1659 | 1659 |
|
| 1660 | 1660 |
`POST /build` |
| 1661 | 1661 |
|
| ... | ... |
@@ -1761,7 +1759,7 @@ or being killed. |
| 1761 | 1761 |
- **200** – no error |
| 1762 | 1762 |
- **500** – server error |
| 1763 | 1763 |
|
| 1764 |
-### Create an image |
|
| 1764 |
+#### Create an image |
|
| 1765 | 1765 |
|
| 1766 | 1766 |
`POST /images/create` |
| 1767 | 1767 |
|
| ... | ... |
@@ -1827,7 +1825,7 @@ a base64-encoded AuthConfig object. |
| 1827 | 1827 |
|
| 1828 | 1828 |
|
| 1829 | 1829 |
|
| 1830 |
-### Inspect an image |
|
| 1830 |
+#### Inspect an image |
|
| 1831 | 1831 |
|
| 1832 | 1832 |
`GET /images/(name)/json` |
| 1833 | 1833 |
|
| ... | ... |
@@ -1945,7 +1943,7 @@ Return low-level information on the image `name` |
| 1945 | 1945 |
- **404** – no such image |
| 1946 | 1946 |
- **500** – server error |
| 1947 | 1947 |
|
| 1948 |
-### Get the history of an image |
|
| 1948 |
+#### Get the history of an image |
|
| 1949 | 1949 |
|
| 1950 | 1950 |
`GET /images/(name)/history` |
| 1951 | 1951 |
|
| ... | ... |
@@ -1999,7 +1997,7 @@ Return the history of the image `name` |
| 1999 | 1999 |
- **404** – no such image |
| 2000 | 2000 |
- **500** – server error |
| 2001 | 2001 |
|
| 2002 |
-### Push an image on the registry |
|
| 2002 |
+#### Push an image on the registry |
|
| 2003 | 2003 |
|
| 2004 | 2004 |
`POST /images/(name)/push` |
| 2005 | 2005 |
|
| ... | ... |
@@ -2061,7 +2059,7 @@ The push is cancelled if the HTTP connection is closed. |
| 2061 | 2061 |
- **404** – no such image |
| 2062 | 2062 |
- **500** – server error |
| 2063 | 2063 |
|
| 2064 |
-### Tag an image into a repository |
|
| 2064 |
+#### Tag an image into a repository |
|
| 2065 | 2065 |
|
| 2066 | 2066 |
`POST /images/(name)/tag` |
| 2067 | 2067 |
|
| ... | ... |
@@ -2089,7 +2087,7 @@ Tag the image `name` into a repository |
| 2089 | 2089 |
- **409** – conflict |
| 2090 | 2090 |
- **500** – server error |
| 2091 | 2091 |
|
| 2092 |
-### Remove an image |
|
| 2092 |
+#### Remove an image |
|
| 2093 | 2093 |
|
| 2094 | 2094 |
`DELETE /images/(name)` |
| 2095 | 2095 |
|
| ... | ... |
@@ -2122,7 +2120,7 @@ Remove the image `name` from the filesystem |
| 2122 | 2122 |
- **409** – conflict |
| 2123 | 2123 |
- **500** – server error |
| 2124 | 2124 |
|
| 2125 |
-### Search images |
|
| 2125 |
+#### Search images |
|
| 2126 | 2126 |
|
| 2127 | 2127 |
`GET /images/search` |
| 2128 | 2128 |
|
| ... | ... |
@@ -2175,9 +2173,9 @@ Search for an image on [Docker Hub](https://hub.docker.com). |
| 2175 | 2175 |
- **200** – no error |
| 2176 | 2176 |
- **500** – server error |
| 2177 | 2177 |
|
| 2178 |
-## 2.3 Misc |
|
| 2178 |
+### 2.3 Misc |
|
| 2179 | 2179 |
|
| 2180 |
-### Check auth configuration |
|
| 2180 |
+#### Check auth configuration |
|
| 2181 | 2181 |
|
| 2182 | 2182 |
`POST /auth` |
| 2183 | 2183 |
|
| ... | ... |
@@ -2210,7 +2208,7 @@ if available, for accessing the registry without password. |
| 2210 | 2210 |
- **204** – no error |
| 2211 | 2211 |
- **500** – server error |
| 2212 | 2212 |
|
| 2213 |
-### Display system-wide information |
|
| 2213 |
+#### Display system-wide information |
|
| 2214 | 2214 |
|
| 2215 | 2215 |
`GET /info` |
| 2216 | 2216 |
|
| ... | ... |
@@ -2299,7 +2297,7 @@ Display system-wide information |
| 2299 | 2299 |
- **200** – no error |
| 2300 | 2300 |
- **500** – server error |
| 2301 | 2301 |
|
| 2302 |
-### Show the docker version information |
|
| 2302 |
+#### Show the docker version information |
|
| 2303 | 2303 |
|
| 2304 | 2304 |
`GET /version` |
| 2305 | 2305 |
|
| ... | ... |
@@ -2331,7 +2329,7 @@ Show the docker version information |
| 2331 | 2331 |
- **200** – no error |
| 2332 | 2332 |
- **500** – server error |
| 2333 | 2333 |
|
| 2334 |
-### Ping the docker server |
|
| 2334 |
+#### Ping the docker server |
|
| 2335 | 2335 |
|
| 2336 | 2336 |
`GET /_ping` |
| 2337 | 2337 |
|
| ... | ... |
@@ -2353,7 +2351,7 @@ Ping the docker server |
| 2353 | 2353 |
- **200** - no error |
| 2354 | 2354 |
- **500** - server error |
| 2355 | 2355 |
|
| 2356 |
-### Create a new image from a container's changes |
|
| 2356 |
+#### Create a new image from a container's changes |
|
| 2357 | 2357 |
|
| 2358 | 2358 |
`POST /commit` |
| 2359 | 2359 |
|
| ... | ... |
@@ -2425,7 +2423,7 @@ Create a new image from a container's changes |
| 2425 | 2425 |
- **404** – no such container |
| 2426 | 2426 |
- **500** – server error |
| 2427 | 2427 |
|
| 2428 |
-### Monitor Docker's events |
|
| 2428 |
+#### Monitor Docker's events |
|
| 2429 | 2429 |
|
| 2430 | 2430 |
`GET /events` |
| 2431 | 2431 |
|
| ... | ... |
@@ -2625,7 +2623,7 @@ Docker networks report the following events: |
| 2625 | 2625 |
- **200** – no error |
| 2626 | 2626 |
- **500** – server error |
| 2627 | 2627 |
|
| 2628 |
-### Get a tarball containing all images in a repository |
|
| 2628 |
+#### Get a tarball containing all images in a repository |
|
| 2629 | 2629 |
|
| 2630 | 2630 |
`GET /images/(name)/get` |
| 2631 | 2631 |
|
| ... | ... |
@@ -2655,7 +2653,7 @@ See the [image tarball format](#image-tarball-format) for more details. |
| 2655 | 2655 |
- **200** – no error |
| 2656 | 2656 |
- **500** – server error |
| 2657 | 2657 |
|
| 2658 |
-### Get a tarball containing all images |
|
| 2658 |
+#### Get a tarball containing all images |
|
| 2659 | 2659 |
|
| 2660 | 2660 |
`GET /images/get` |
| 2661 | 2661 |
|
| ... | ... |
@@ -2684,7 +2682,7 @@ See the [image tarball format](#image-tarball-format) for more details. |
| 2684 | 2684 |
- **200** – no error |
| 2685 | 2685 |
- **500** – server error |
| 2686 | 2686 |
|
| 2687 |
-### Load a tarball with a set of images and tags into docker |
|
| 2687 |
+#### Load a tarball with a set of images and tags into docker |
|
| 2688 | 2688 |
|
| 2689 | 2689 |
`POST /images/load` |
| 2690 | 2690 |
|
| ... | ... |
@@ -2733,7 +2731,7 @@ action completes. |
| 2733 | 2733 |
- **200** – no error |
| 2734 | 2734 |
- **500** – server error |
| 2735 | 2735 |
|
| 2736 |
-### Image tarball format |
|
| 2736 |
+#### Image tarball format |
|
| 2737 | 2737 |
|
| 2738 | 2738 |
An image tarball contains one directory per image layer (named using its long ID), |
| 2739 | 2739 |
each containing these files: |
| ... | ... |
@@ -2754,7 +2752,7 @@ the root that contains a list of repository and tag names mapped to layer IDs. |
| 2754 | 2754 |
} |
| 2755 | 2755 |
``` |
| 2756 | 2756 |
|
| 2757 |
-### Exec Create |
|
| 2757 |
+#### Exec Create |
|
| 2758 | 2758 |
|
| 2759 | 2759 |
`POST /containers/(id or name)/exec` |
| 2760 | 2760 |
|
| ... | ... |
@@ -2808,7 +2806,7 @@ Sets up an exec instance in a running container `id` |
| 2808 | 2808 |
- **409** - container is paused |
| 2809 | 2809 |
- **500** - server error |
| 2810 | 2810 |
|
| 2811 |
-### Exec Start |
|
| 2811 |
+#### Exec Start |
|
| 2812 | 2812 |
|
| 2813 | 2813 |
`POST /exec/(id)/start` |
| 2814 | 2814 |
|
| ... | ... |
@@ -2850,7 +2848,7 @@ interactive session with the `exec` command. |
| 2850 | 2850 |
|
| 2851 | 2851 |
Similar to the stream behavior of `POST /containers/(id or name)/attach` API |
| 2852 | 2852 |
|
| 2853 |
-### Exec Resize |
|
| 2853 |
+#### Exec Resize |
|
| 2854 | 2854 |
|
| 2855 | 2855 |
`POST /exec/(id)/resize` |
| 2856 | 2856 |
|
| ... | ... |
@@ -2877,7 +2875,7 @@ This API is valid only if `tty` was specified as part of creating and starting t |
| 2877 | 2877 |
- **201** – no error |
| 2878 | 2878 |
- **404** – no such exec instance |
| 2879 | 2879 |
|
| 2880 |
-### Exec Inspect |
|
| 2880 |
+#### Exec Inspect |
|
| 2881 | 2881 |
|
| 2882 | 2882 |
`GET /exec/(id)/json` |
| 2883 | 2883 |
|
| ... | ... |
@@ -2920,9 +2918,9 @@ Return low-level information about the `exec` command `id`. |
| 2920 | 2920 |
- **404** – no such exec instance |
| 2921 | 2921 |
- **500** - server error |
| 2922 | 2922 |
|
| 2923 |
-## 2.4 Volumes |
|
| 2923 |
+### 2.4 Volumes |
|
| 2924 | 2924 |
|
| 2925 |
-### List volumes |
|
| 2925 |
+#### List volumes |
|
| 2926 | 2926 |
|
| 2927 | 2927 |
`GET /volumes` |
| 2928 | 2928 |
|
| ... | ... |
@@ -2955,7 +2953,7 @@ Return low-level information about the `exec` command `id`. |
| 2955 | 2955 |
- **200** - no error |
| 2956 | 2956 |
- **500** - server error |
| 2957 | 2957 |
|
| 2958 |
-### Create a volume |
|
| 2958 |
+#### Create a volume |
|
| 2959 | 2959 |
|
| 2960 | 2960 |
`POST /volumes/create` |
| 2961 | 2961 |
|
| ... | ... |
@@ -3002,7 +3000,7 @@ Create a volume |
| 3002 | 3002 |
passed directly to the driver and are driver specific. |
| 3003 | 3003 |
- **Labels** - Labels to set on the volume, specified as a map: `{"key":"value","key2":"value2"}`
|
| 3004 | 3004 |
|
| 3005 |
-### Inspect a volume |
|
| 3005 |
+#### Inspect a volume |
|
| 3006 | 3006 |
|
| 3007 | 3007 |
`GET /volumes/(name)` |
| 3008 | 3008 |
|
| ... | ... |
@@ -3033,7 +3031,7 @@ Return low-level information on the volume `name` |
| 3033 | 3033 |
- **404** - no such volume |
| 3034 | 3034 |
- **500** - server error |
| 3035 | 3035 |
|
| 3036 |
-### Remove a volume |
|
| 3036 |
+#### Remove a volume |
|
| 3037 | 3037 |
|
| 3038 | 3038 |
`DELETE /volumes/(name)` |
| 3039 | 3039 |
|
| ... | ... |
@@ -3054,9 +3052,9 @@ Instruct the driver to remove the volume (`name`). |
| 3054 | 3054 |
- **409** - volume is in use and cannot be removed |
| 3055 | 3055 |
- **500** - server error |
| 3056 | 3056 |
|
| 3057 |
-## 3.5 Networks |
|
| 3057 |
+### 3.5 Networks |
|
| 3058 | 3058 |
|
| 3059 |
-### List networks |
|
| 3059 |
+#### List networks |
|
| 3060 | 3060 |
|
| 3061 | 3061 |
`GET /networks` |
| 3062 | 3062 |
|
| ... | ... |
@@ -3146,7 +3144,7 @@ Content-Type: application/json |
| 3146 | 3146 |
- **200** - no error |
| 3147 | 3147 |
- **500** - server error |
| 3148 | 3148 |
|
| 3149 |
-### Inspect network |
|
| 3149 |
+#### Inspect network |
|
| 3150 | 3150 |
|
| 3151 | 3151 |
`GET /networks/<network-id>` |
| 3152 | 3152 |
|
| ... | ... |
@@ -3208,7 +3206,7 @@ Content-Type: application/json |
| 3208 | 3208 |
- **200** - no error |
| 3209 | 3209 |
- **404** - network not found |
| 3210 | 3210 |
|
| 3211 |
-### Create a network |
|
| 3211 |
+#### Create a network |
|
| 3212 | 3212 |
|
| 3213 | 3213 |
`POST /networks/create` |
| 3214 | 3214 |
|
| ... | ... |
@@ -3291,7 +3289,7 @@ Content-Type: application/json |
| 3291 | 3291 |
- **Options** - Network specific options to be used by the drivers |
| 3292 | 3292 |
- **Labels** - Labels to set on the network, specified as a map: `{"key":"value" [,"key2":"value2"]}`
|
| 3293 | 3293 |
|
| 3294 |
-### Connect a container to a network |
|
| 3294 |
+#### Connect a container to a network |
|
| 3295 | 3295 |
|
| 3296 | 3296 |
`POST /networks/(id)/connect` |
| 3297 | 3297 |
|
| ... | ... |
@@ -3328,7 +3326,7 @@ Content-Type: application/json |
| 3328 | 3328 |
|
| 3329 | 3329 |
- **container** - container-id/name to be connected to the network |
| 3330 | 3330 |
|
| 3331 |
-### Disconnect a container from a network |
|
| 3331 |
+#### Disconnect a container from a network |
|
| 3332 | 3332 |
|
| 3333 | 3333 |
`POST /networks/(id)/disconnect` |
| 3334 | 3334 |
|
| ... | ... |
@@ -3361,7 +3359,7 @@ Content-Type: application/json |
| 3361 | 3361 |
- **Container** - container-id/name to be disconnected from a network |
| 3362 | 3362 |
- **Force** - Force the container to disconnect from a network |
| 3363 | 3363 |
|
| 3364 |
-### Remove a network |
|
| 3364 |
+#### Remove a network |
|
| 3365 | 3365 |
|
| 3366 | 3366 |
`DELETE /networks/(id)` |
| 3367 | 3367 |
|
| ... | ... |
@@ -3381,9 +3379,9 @@ Instruct the driver to remove the network (`id`). |
| 3381 | 3381 |
- **404** - no such network |
| 3382 | 3382 |
- **500** - server error |
| 3383 | 3383 |
|
| 3384 |
-# 3. Going further |
|
| 3384 |
+## 3. Going further |
|
| 3385 | 3385 |
|
| 3386 |
-## 3.1 Inside `docker run` |
|
| 3386 |
+### 3.1 Inside `docker run` |
|
| 3387 | 3387 |
|
| 3388 | 3388 |
As an example, the `docker run` command line makes the following API calls: |
| 3389 | 3389 |
|
| ... | ... |
@@ -3401,7 +3399,7 @@ As an example, the `docker run` command line makes the following API calls: |
| 3401 | 3401 |
|
| 3402 | 3402 |
- If in detached mode or only `stdin` is attached, display the container's id. |
| 3403 | 3403 |
|
| 3404 |
-## 3.2 Hijacking |
|
| 3404 |
+### 3.2 Hijacking |
|
| 3405 | 3405 |
|
| 3406 | 3406 |
In this version of the API, `/attach`, uses hijacking to transport `stdin`, |
| 3407 | 3407 |
`stdout`, and `stderr` on the same socket. |
| ... | ... |
@@ -3416,7 +3414,7 @@ When Docker daemon detects the `Upgrade` header, it switches its status code |
| 3416 | 3416 |
from **200 OK** to **101 UPGRADED** and resends the same headers. |
| 3417 | 3417 |
|
| 3418 | 3418 |
|
| 3419 |
-## 3.3 CORS Requests |
|
| 3419 |
+### 3.3 CORS Requests |
|
| 3420 | 3420 |
|
| 3421 | 3421 |
To set cross origin requests to the Engine API please give values to |
| 3422 | 3422 |
`--api-cors-header` when running Docker in daemon mode. Set * (asterisk) allows all, |
| ... | ... |
@@ -16,9 +16,7 @@ redirect_from: |
| 16 | 16 |
will be rejected. |
| 17 | 17 |
--> |
| 18 | 18 |
|
| 19 |
-# Docker Engine API v1.24 |
|
| 20 |
- |
|
| 21 |
-# 1. Brief introduction |
|
| 19 |
+## 1. Brief introduction |
|
| 22 | 20 |
|
| 23 | 21 |
- The daemon listens on `unix:///var/run/docker.sock` but you can |
| 24 | 22 |
[Bind Docker to another host/port or a Unix socket](../commandline/dockerd.md#bind-docker-to-another-host-port-or-a-unix-socket). |
| ... | ... |
@@ -26,7 +24,7 @@ redirect_from: |
| 26 | 26 |
or `pull`, the HTTP connection is hijacked to transport `stdout`, |
| 27 | 27 |
`stdin` and `stderr`. |
| 28 | 28 |
|
| 29 |
-# 2. Errors |
|
| 29 |
+## 2. Errors |
|
| 30 | 30 |
|
| 31 | 31 |
The Engine API uses standard HTTP status codes to indicate the success or failure of the API call. The body of the response will be JSON in the following format: |
| 32 | 32 |
|
| ... | ... |
@@ -36,11 +34,11 @@ The Engine API uses standard HTTP status codes to indicate the success or failur |
| 36 | 36 |
|
| 37 | 37 |
The status codes that are returned for each endpoint are specified in the endpoint documentation below. |
| 38 | 38 |
|
| 39 |
-# 3. Endpoints |
|
| 39 |
+## 3. Endpoints |
|
| 40 | 40 |
|
| 41 |
-## 3.1 Containers |
|
| 41 |
+### 3.1 Containers |
|
| 42 | 42 |
|
| 43 |
-### List containers |
|
| 43 |
+#### List containers |
|
| 44 | 44 |
|
| 45 | 45 |
`GET /containers/json` |
| 46 | 46 |
|
| ... | ... |
@@ -245,7 +243,7 @@ List containers |
| 245 | 245 |
- **400** – bad parameter |
| 246 | 246 |
- **500** – server error |
| 247 | 247 |
|
| 248 |
-### Create a container |
|
| 248 |
+#### Create a container |
|
| 249 | 249 |
|
| 250 | 250 |
`POST /containers/create` |
| 251 | 251 |
|
| ... | ... |
@@ -511,7 +509,7 @@ Create a container |
| 511 | 511 |
- **409** – conflict |
| 512 | 512 |
- **500** – server error |
| 513 | 513 |
|
| 514 |
-### Inspect a container |
|
| 514 |
+#### Inspect a container |
|
| 515 | 515 |
|
| 516 | 516 |
`GET /containers/(id or name)/json` |
| 517 | 517 |
|
| ... | ... |
@@ -721,7 +719,7 @@ Return low-level information on the container `id` |
| 721 | 721 |
- **404** – no such container |
| 722 | 722 |
- **500** – server error |
| 723 | 723 |
|
| 724 |
-### List processes running inside a container |
|
| 724 |
+#### List processes running inside a container |
|
| 725 | 725 |
|
| 726 | 726 |
`GET /containers/(id or name)/top` |
| 727 | 727 |
|
| ... | ... |
@@ -785,7 +783,7 @@ supported on Windows. |
| 785 | 785 |
- **404** – no such container |
| 786 | 786 |
- **500** – server error |
| 787 | 787 |
|
| 788 |
-### Get container logs |
|
| 788 |
+#### Get container logs |
|
| 789 | 789 |
|
| 790 | 790 |
`GET /containers/(id or name)/logs` |
| 791 | 791 |
|
| ... | ... |
@@ -828,7 +826,7 @@ Get `stdout` and `stderr` logs from the container ``id`` |
| 828 | 828 |
- **404** – no such container |
| 829 | 829 |
- **500** – server error |
| 830 | 830 |
|
| 831 |
-### Inspect changes on a container's filesystem |
|
| 831 |
+#### Inspect changes on a container's filesystem |
|
| 832 | 832 |
|
| 833 | 833 |
`GET /containers/(id or name)/changes` |
| 834 | 834 |
|
| ... | ... |
@@ -870,7 +868,7 @@ Values for `Kind`: |
| 870 | 870 |
- **404** – no such container |
| 871 | 871 |
- **500** – server error |
| 872 | 872 |
|
| 873 |
-### Export a container |
|
| 873 |
+#### Export a container |
|
| 874 | 874 |
|
| 875 | 875 |
`GET /containers/(id or name)/export` |
| 876 | 876 |
|
| ... | ... |
@@ -895,7 +893,7 @@ Export the contents of container `id` |
| 895 | 895 |
- **404** – no such container |
| 896 | 896 |
- **500** – server error |
| 897 | 897 |
|
| 898 |
-### Get container stats based on resource usage |
|
| 898 |
+#### Get container stats based on resource usage |
|
| 899 | 899 |
|
| 900 | 900 |
`GET /containers/(id or name)/stats` |
| 901 | 901 |
|
| ... | ... |
@@ -1019,7 +1017,7 @@ The precpu_stats is the cpu statistic of last read, which is used for calculatin |
| 1019 | 1019 |
- **404** – no such container |
| 1020 | 1020 |
- **500** – server error |
| 1021 | 1021 |
|
| 1022 |
-### Resize a container TTY |
|
| 1022 |
+#### Resize a container TTY |
|
| 1023 | 1023 |
|
| 1024 | 1024 |
`POST /containers/(id or name)/resize` |
| 1025 | 1025 |
|
| ... | ... |
@@ -1046,7 +1044,7 @@ Resize the TTY for container with `id`. The unit is number of characters. You m |
| 1046 | 1046 |
- **404** – No such container |
| 1047 | 1047 |
- **500** – Cannot resize container |
| 1048 | 1048 |
|
| 1049 |
-### Start a container |
|
| 1049 |
+#### Start a container |
|
| 1050 | 1050 |
|
| 1051 | 1051 |
`POST /containers/(id or name)/start` |
| 1052 | 1052 |
|
| ... | ... |
@@ -1073,7 +1071,7 @@ Start the container `id` |
| 1073 | 1073 |
- **404** – no such container |
| 1074 | 1074 |
- **500** – server error |
| 1075 | 1075 |
|
| 1076 |
-### Stop a container |
|
| 1076 |
+#### Stop a container |
|
| 1077 | 1077 |
|
| 1078 | 1078 |
`POST /containers/(id or name)/stop` |
| 1079 | 1079 |
|
| ... | ... |
@@ -1098,7 +1096,7 @@ Stop the container `id` |
| 1098 | 1098 |
- **404** – no such container |
| 1099 | 1099 |
- **500** – server error |
| 1100 | 1100 |
|
| 1101 |
-### Restart a container |
|
| 1101 |
+#### Restart a container |
|
| 1102 | 1102 |
|
| 1103 | 1103 |
`POST /containers/(id or name)/restart` |
| 1104 | 1104 |
|
| ... | ... |
@@ -1122,7 +1120,7 @@ Restart the container `id` |
| 1122 | 1122 |
- **404** – no such container |
| 1123 | 1123 |
- **500** – server error |
| 1124 | 1124 |
|
| 1125 |
-### Kill a container |
|
| 1125 |
+#### Kill a container |
|
| 1126 | 1126 |
|
| 1127 | 1127 |
`POST /containers/(id or name)/kill` |
| 1128 | 1128 |
|
| ... | ... |
@@ -1147,7 +1145,7 @@ Kill the container `id` |
| 1147 | 1147 |
- **404** – no such container |
| 1148 | 1148 |
- **500** – server error |
| 1149 | 1149 |
|
| 1150 |
-### Update a container |
|
| 1150 |
+#### Update a container |
|
| 1151 | 1151 |
|
| 1152 | 1152 |
`POST /containers/(id or name)/update` |
| 1153 | 1153 |
|
| ... | ... |
@@ -1191,7 +1189,7 @@ Update configuration of one or more containers. |
| 1191 | 1191 |
- **404** – no such container |
| 1192 | 1192 |
- **500** – server error |
| 1193 | 1193 |
|
| 1194 |
-### Rename a container |
|
| 1194 |
+#### Rename a container |
|
| 1195 | 1195 |
|
| 1196 | 1196 |
`POST /containers/(id or name)/rename` |
| 1197 | 1197 |
|
| ... | ... |
@@ -1216,7 +1214,7 @@ Rename the container `id` to a `new_name` |
| 1216 | 1216 |
- **409** - conflict name already assigned |
| 1217 | 1217 |
- **500** – server error |
| 1218 | 1218 |
|
| 1219 |
-### Pause a container |
|
| 1219 |
+#### Pause a container |
|
| 1220 | 1220 |
|
| 1221 | 1221 |
`POST /containers/(id or name)/pause` |
| 1222 | 1222 |
|
| ... | ... |
@@ -1236,7 +1234,7 @@ Pause the container `id` |
| 1236 | 1236 |
- **404** – no such container |
| 1237 | 1237 |
- **500** – server error |
| 1238 | 1238 |
|
| 1239 |
-### Unpause a container |
|
| 1239 |
+#### Unpause a container |
|
| 1240 | 1240 |
|
| 1241 | 1241 |
`POST /containers/(id or name)/unpause` |
| 1242 | 1242 |
|
| ... | ... |
@@ -1256,7 +1254,7 @@ Unpause the container `id` |
| 1256 | 1256 |
- **404** – no such container |
| 1257 | 1257 |
- **500** – server error |
| 1258 | 1258 |
|
| 1259 |
-### Attach to a container |
|
| 1259 |
+#### Attach to a container |
|
| 1260 | 1260 |
|
| 1261 | 1261 |
`POST /containers/(id or name)/attach` |
| 1262 | 1262 |
|
| ... | ... |
@@ -1345,7 +1343,7 @@ The simplest way to implement the Attach protocol is the following: |
| 1345 | 1345 |
4. Read the extracted size and output it on the correct output. |
| 1346 | 1346 |
5. Goto 1. |
| 1347 | 1347 |
|
| 1348 |
-### Attach to a container (websocket) |
|
| 1348 |
+#### Attach to a container (websocket) |
|
| 1349 | 1349 |
|
| 1350 | 1350 |
`GET /containers/(id or name)/attach/ws` |
| 1351 | 1351 |
|
| ... | ... |
@@ -1385,7 +1383,7 @@ Implements websocket protocol handshake according to [RFC 6455](http://tools.iet |
| 1385 | 1385 |
- **404** – no such container |
| 1386 | 1386 |
- **500** – server error |
| 1387 | 1387 |
|
| 1388 |
-### Wait a container |
|
| 1388 |
+#### Wait a container |
|
| 1389 | 1389 |
|
| 1390 | 1390 |
`POST /containers/(id or name)/wait` |
| 1391 | 1391 |
|
| ... | ... |
@@ -1408,7 +1406,7 @@ Block until container `id` stops, then returns the exit code |
| 1408 | 1408 |
- **404** – no such container |
| 1409 | 1409 |
- **500** – server error |
| 1410 | 1410 |
|
| 1411 |
-### Remove a container |
|
| 1411 |
+#### Remove a container |
|
| 1412 | 1412 |
|
| 1413 | 1413 |
`DELETE /containers/(id or name)` |
| 1414 | 1414 |
|
| ... | ... |
@@ -1437,14 +1435,14 @@ Remove the container `id` from the filesystem |
| 1437 | 1437 |
- **409** – conflict |
| 1438 | 1438 |
- **500** – server error |
| 1439 | 1439 |
|
| 1440 |
-### Retrieving information about files and folders in a container |
|
| 1440 |
+#### Retrieving information about files and folders in a container |
|
| 1441 | 1441 |
|
| 1442 | 1442 |
`HEAD /containers/(id or name)/archive` |
| 1443 | 1443 |
|
| 1444 | 1444 |
See the description of the `X-Docker-Container-Path-Stat` header in the |
| 1445 | 1445 |
following section. |
| 1446 | 1446 |
|
| 1447 |
-### Get an archive of a filesystem resource in a container |
|
| 1447 |
+#### Get an archive of a filesystem resource in a container |
|
| 1448 | 1448 |
|
| 1449 | 1449 |
`GET /containers/(id or name)/archive` |
| 1450 | 1450 |
|
| ... | ... |
@@ -1509,7 +1507,7 @@ desired. |
| 1509 | 1509 |
- no such file or directory (**path** does not exist) |
| 1510 | 1510 |
- **500** - server error |
| 1511 | 1511 |
|
| 1512 |
-### Extract an archive of files or folders to a directory in a container |
|
| 1512 |
+#### Extract an archive of files or folders to a directory in a container |
|
| 1513 | 1513 |
|
| 1514 | 1514 |
`PUT /containers/(id or name)/archive` |
| 1515 | 1515 |
|
| ... | ... |
@@ -1557,9 +1555,9 @@ Upload a tar archive to be extracted to a path in the filesystem of container |
| 1557 | 1557 |
- no such file or directory (**path** resource does not exist) |
| 1558 | 1558 |
- **500** – server error |
| 1559 | 1559 |
|
| 1560 |
-## 3.2 Images |
|
| 1560 |
+### 3.2 Images |
|
| 1561 | 1561 |
|
| 1562 |
-### List Images |
|
| 1562 |
+#### List Images |
|
| 1563 | 1563 |
|
| 1564 | 1564 |
`GET /images/json` |
| 1565 | 1565 |
|
| ... | ... |
@@ -1652,7 +1650,7 @@ references on the command line. |
| 1652 | 1652 |
- `since`=(`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`) |
| 1653 | 1653 |
- **filter** - only return images with the specified name |
| 1654 | 1654 |
|
| 1655 |
-### Build image from a Dockerfile |
|
| 1655 |
+#### Build image from a Dockerfile |
|
| 1656 | 1656 |
|
| 1657 | 1657 |
`POST /build` |
| 1658 | 1658 |
|
| ... | ... |
@@ -1758,7 +1756,7 @@ or being killed. |
| 1758 | 1758 |
- **200** – no error |
| 1759 | 1759 |
- **500** – server error |
| 1760 | 1760 |
|
| 1761 |
-### Create an image |
|
| 1761 |
+#### Create an image |
|
| 1762 | 1762 |
|
| 1763 | 1763 |
`POST /images/create` |
| 1764 | 1764 |
|
| ... | ... |
@@ -1824,7 +1822,7 @@ a base64-encoded AuthConfig object. |
| 1824 | 1824 |
|
| 1825 | 1825 |
|
| 1826 | 1826 |
|
| 1827 |
-### Inspect an image |
|
| 1827 |
+#### Inspect an image |
|
| 1828 | 1828 |
|
| 1829 | 1829 |
`GET /images/(name)/json` |
| 1830 | 1830 |
|
| ... | ... |
@@ -1942,7 +1940,7 @@ Return low-level information on the image `name` |
| 1942 | 1942 |
- **404** – no such image |
| 1943 | 1943 |
- **500** – server error |
| 1944 | 1944 |
|
| 1945 |
-### Get the history of an image |
|
| 1945 |
+#### Get the history of an image |
|
| 1946 | 1946 |
|
| 1947 | 1947 |
`GET /images/(name)/history` |
| 1948 | 1948 |
|
| ... | ... |
@@ -1996,7 +1994,7 @@ Return the history of the image `name` |
| 1996 | 1996 |
- **404** – no such image |
| 1997 | 1997 |
- **500** – server error |
| 1998 | 1998 |
|
| 1999 |
-### Push an image on the registry |
|
| 1999 |
+#### Push an image on the registry |
|
| 2000 | 2000 |
|
| 2001 | 2001 |
`POST /images/(name)/push` |
| 2002 | 2002 |
|
| ... | ... |
@@ -2058,7 +2056,7 @@ The push is cancelled if the HTTP connection is closed. |
| 2058 | 2058 |
- **404** – no such image |
| 2059 | 2059 |
- **500** – server error |
| 2060 | 2060 |
|
| 2061 |
-### Tag an image into a repository |
|
| 2061 |
+#### Tag an image into a repository |
|
| 2062 | 2062 |
|
| 2063 | 2063 |
`POST /images/(name)/tag` |
| 2064 | 2064 |
|
| ... | ... |
@@ -2085,7 +2083,7 @@ Tag the image `name` into a repository |
| 2085 | 2085 |
- **409** – conflict |
| 2086 | 2086 |
- **500** – server error |
| 2087 | 2087 |
|
| 2088 |
-### Remove an image |
|
| 2088 |
+#### Remove an image |
|
| 2089 | 2089 |
|
| 2090 | 2090 |
`DELETE /images/(name)` |
| 2091 | 2091 |
|
| ... | ... |
@@ -2118,7 +2116,7 @@ Remove the image `name` from the filesystem |
| 2118 | 2118 |
- **409** – conflict |
| 2119 | 2119 |
- **500** – server error |
| 2120 | 2120 |
|
| 2121 |
-### Search images |
|
| 2121 |
+#### Search images |
|
| 2122 | 2122 |
|
| 2123 | 2123 |
`GET /images/search` |
| 2124 | 2124 |
|
| ... | ... |
@@ -2176,9 +2174,9 @@ Search for an image on [Docker Hub](https://hub.docker.com). |
| 2176 | 2176 |
- **200** – no error |
| 2177 | 2177 |
- **500** – server error |
| 2178 | 2178 |
|
| 2179 |
-## 3.3 Misc |
|
| 2179 |
+### 3.3 Misc |
|
| 2180 | 2180 |
|
| 2181 |
-### Check auth configuration |
|
| 2181 |
+#### Check auth configuration |
|
| 2182 | 2182 |
|
| 2183 | 2183 |
`POST /auth` |
| 2184 | 2184 |
|
| ... | ... |
@@ -2211,7 +2209,7 @@ if available, for accessing the registry without password. |
| 2211 | 2211 |
- **204** – no error |
| 2212 | 2212 |
- **500** – server error |
| 2213 | 2213 |
|
| 2214 |
-### Display system-wide information |
|
| 2214 |
+#### Display system-wide information |
|
| 2215 | 2215 |
|
| 2216 | 2216 |
`GET /info` |
| 2217 | 2217 |
|
| ... | ... |
@@ -2304,7 +2302,7 @@ Display system-wide information |
| 2304 | 2304 |
- **200** – no error |
| 2305 | 2305 |
- **500** – server error |
| 2306 | 2306 |
|
| 2307 |
-### Show the docker version information |
|
| 2307 |
+#### Show the docker version information |
|
| 2308 | 2308 |
|
| 2309 | 2309 |
`GET /version` |
| 2310 | 2310 |
|
| ... | ... |
@@ -2336,7 +2334,7 @@ Show the docker version information |
| 2336 | 2336 |
- **200** – no error |
| 2337 | 2337 |
- **500** – server error |
| 2338 | 2338 |
|
| 2339 |
-### Ping the docker server |
|
| 2339 |
+#### Ping the docker server |
|
| 2340 | 2340 |
|
| 2341 | 2341 |
`GET /_ping` |
| 2342 | 2342 |
|
| ... | ... |
@@ -2358,7 +2356,7 @@ Ping the docker server |
| 2358 | 2358 |
- **200** - no error |
| 2359 | 2359 |
- **500** - server error |
| 2360 | 2360 |
|
| 2361 |
-### Create a new image from a container's changes |
|
| 2361 |
+#### Create a new image from a container's changes |
|
| 2362 | 2362 |
|
| 2363 | 2363 |
`POST /commit` |
| 2364 | 2364 |
|
| ... | ... |
@@ -2430,7 +2428,7 @@ Create a new image from a container's changes |
| 2430 | 2430 |
- **404** – no such container |
| 2431 | 2431 |
- **500** – server error |
| 2432 | 2432 |
|
| 2433 |
-### Monitor Docker's events |
|
| 2433 |
+#### Monitor Docker's events |
|
| 2434 | 2434 |
|
| 2435 | 2435 |
`GET /events` |
| 2436 | 2436 |
|
| ... | ... |
@@ -2635,7 +2633,7 @@ Docker daemon report the following event: |
| 2635 | 2635 |
- **200** – no error |
| 2636 | 2636 |
- **500** – server error |
| 2637 | 2637 |
|
| 2638 |
-### Get a tarball containing all images in a repository |
|
| 2638 |
+#### Get a tarball containing all images in a repository |
|
| 2639 | 2639 |
|
| 2640 | 2640 |
`GET /images/(name)/get` |
| 2641 | 2641 |
|
| ... | ... |
@@ -2665,7 +2663,7 @@ See the [image tarball format](#image-tarball-format) for more details. |
| 2665 | 2665 |
- **200** – no error |
| 2666 | 2666 |
- **500** – server error |
| 2667 | 2667 |
|
| 2668 |
-### Get a tarball containing all images |
|
| 2668 |
+#### Get a tarball containing all images |
|
| 2669 | 2669 |
|
| 2670 | 2670 |
`GET /images/get` |
| 2671 | 2671 |
|
| ... | ... |
@@ -2694,7 +2692,7 @@ See the [image tarball format](#image-tarball-format) for more details. |
| 2694 | 2694 |
- **200** – no error |
| 2695 | 2695 |
- **500** – server error |
| 2696 | 2696 |
|
| 2697 |
-### Load a tarball with a set of images and tags into docker |
|
| 2697 |
+#### Load a tarball with a set of images and tags into docker |
|
| 2698 | 2698 |
|
| 2699 | 2699 |
`POST /images/load` |
| 2700 | 2700 |
|
| ... | ... |
@@ -2743,7 +2741,7 @@ action completes. |
| 2743 | 2743 |
- **200** – no error |
| 2744 | 2744 |
- **500** – server error |
| 2745 | 2745 |
|
| 2746 |
-### Image tarball format |
|
| 2746 |
+#### Image tarball format |
|
| 2747 | 2747 |
|
| 2748 | 2748 |
An image tarball contains one directory per image layer (named using its long ID), |
| 2749 | 2749 |
each containing these files: |
| ... | ... |
@@ -2764,7 +2762,7 @@ the root that contains a list of repository and tag names mapped to layer IDs. |
| 2764 | 2764 |
} |
| 2765 | 2765 |
``` |
| 2766 | 2766 |
|
| 2767 |
-### Exec Create |
|
| 2767 |
+#### Exec Create |
|
| 2768 | 2768 |
|
| 2769 | 2769 |
`POST /containers/(id or name)/exec` |
| 2770 | 2770 |
|
| ... | ... |
@@ -2818,7 +2816,7 @@ Sets up an exec instance in a running container `id` |
| 2818 | 2818 |
- **409** - container is paused |
| 2819 | 2819 |
- **500** - server error |
| 2820 | 2820 |
|
| 2821 |
-### Exec Start |
|
| 2821 |
+#### Exec Start |
|
| 2822 | 2822 |
|
| 2823 | 2823 |
`POST /exec/(id)/start` |
| 2824 | 2824 |
|
| ... | ... |
@@ -2860,7 +2858,7 @@ interactive session with the `exec` command. |
| 2860 | 2860 |
|
| 2861 | 2861 |
Similar to the stream behavior of `POST /containers/(id or name)/attach` API |
| 2862 | 2862 |
|
| 2863 |
-### Exec Resize |
|
| 2863 |
+#### Exec Resize |
|
| 2864 | 2864 |
|
| 2865 | 2865 |
`POST /exec/(id)/resize` |
| 2866 | 2866 |
|
| ... | ... |
@@ -2887,7 +2885,7 @@ This API is valid only if `tty` was specified as part of creating and starting t |
| 2887 | 2887 |
- **201** – no error |
| 2888 | 2888 |
- **404** – no such exec instance |
| 2889 | 2889 |
|
| 2890 |
-### Exec Inspect |
|
| 2890 |
+#### Exec Inspect |
|
| 2891 | 2891 |
|
| 2892 | 2892 |
`GET /exec/(id)/json` |
| 2893 | 2893 |
|
| ... | ... |
@@ -2930,9 +2928,9 @@ Return low-level information about the `exec` command `id`. |
| 2930 | 2930 |
- **404** – no such exec instance |
| 2931 | 2931 |
- **500** - server error |
| 2932 | 2932 |
|
| 2933 |
-## 3.4 Volumes |
|
| 2933 |
+### 3.4 Volumes |
|
| 2934 | 2934 |
|
| 2935 |
-### List volumes |
|
| 2935 |
+#### List volumes |
|
| 2936 | 2936 |
|
| 2937 | 2937 |
`GET /volumes` |
| 2938 | 2938 |
|
| ... | ... |
@@ -2970,7 +2968,7 @@ Return low-level information about the `exec` command `id`. |
| 2970 | 2970 |
- **200** - no error |
| 2971 | 2971 |
- **500** - server error |
| 2972 | 2972 |
|
| 2973 |
-### Create a volume |
|
| 2973 |
+#### Create a volume |
|
| 2974 | 2974 |
|
| 2975 | 2975 |
`POST /volumes/create` |
| 2976 | 2976 |
|
| ... | ... |
@@ -3027,7 +3025,7 @@ Create a volume |
| 3027 | 3027 |
Refer to the [inspect a volume](#inspect-a-volume) section or details about the |
| 3028 | 3028 |
JSON fields returned in the response. |
| 3029 | 3029 |
|
| 3030 |
-### Inspect a volume |
|
| 3030 |
+#### Inspect a volume |
|
| 3031 | 3031 |
|
| 3032 | 3032 |
`GET /volumes/(name)` |
| 3033 | 3033 |
|
| ... | ... |
@@ -3079,7 +3077,7 @@ response. |
| 3079 | 3079 |
- **Scope** - Scope describes the level at which the volume exists, can be one of |
| 3080 | 3080 |
`global` for cluster-wide or `local` for machine level. The default is `local`. |
| 3081 | 3081 |
|
| 3082 |
-### Remove a volume |
|
| 3082 |
+#### Remove a volume |
|
| 3083 | 3083 |
|
| 3084 | 3084 |
`DELETE /volumes/(name)` |
| 3085 | 3085 |
|
| ... | ... |
@@ -3100,9 +3098,9 @@ Instruct the driver to remove the volume (`name`). |
| 3100 | 3100 |
- **409** - volume is in use and cannot be removed |
| 3101 | 3101 |
- **500** - server error |
| 3102 | 3102 |
|
| 3103 |
-## 3.5 Networks |
|
| 3103 |
+### 3.5 Networks |
|
| 3104 | 3104 |
|
| 3105 |
-### List networks |
|
| 3105 |
+#### List networks |
|
| 3106 | 3106 |
|
| 3107 | 3107 |
`GET /networks` |
| 3108 | 3108 |
|
| ... | ... |
@@ -3194,7 +3192,7 @@ Content-Type: application/json |
| 3194 | 3194 |
- **200** - no error |
| 3195 | 3195 |
- **500** - server error |
| 3196 | 3196 |
|
| 3197 |
-### Inspect network |
|
| 3197 |
+#### Inspect network |
|
| 3198 | 3198 |
|
| 3199 | 3199 |
`GET /networks/<network-id>` |
| 3200 | 3200 |
|
| ... | ... |
@@ -3256,7 +3254,7 @@ Content-Type: application/json |
| 3256 | 3256 |
- **200** - no error |
| 3257 | 3257 |
- **404** - network not found |
| 3258 | 3258 |
|
| 3259 |
-### Create a network |
|
| 3259 |
+#### Create a network |
|
| 3260 | 3260 |
|
| 3261 | 3261 |
`POST /networks/create` |
| 3262 | 3262 |
|
| ... | ... |
@@ -3339,7 +3337,7 @@ Content-Type: application/json |
| 3339 | 3339 |
- **Options** - Network specific options to be used by the drivers |
| 3340 | 3340 |
- **Labels** - Labels to set on the network, specified as a map: `{"key":"value" [,"key2":"value2"]}`
|
| 3341 | 3341 |
|
| 3342 |
-### Connect a container to a network |
|
| 3342 |
+#### Connect a container to a network |
|
| 3343 | 3343 |
|
| 3344 | 3344 |
`POST /networks/(id)/connect` |
| 3345 | 3345 |
|
| ... | ... |
@@ -3377,7 +3375,7 @@ Content-Type: application/json |
| 3377 | 3377 |
|
| 3378 | 3378 |
- **container** - container-id/name to be connected to the network |
| 3379 | 3379 |
|
| 3380 |
-### Disconnect a container from a network |
|
| 3380 |
+#### Disconnect a container from a network |
|
| 3381 | 3381 |
|
| 3382 | 3382 |
`POST /networks/(id)/disconnect` |
| 3383 | 3383 |
|
| ... | ... |
@@ -3411,7 +3409,7 @@ Content-Type: application/json |
| 3411 | 3411 |
- **Container** - container-id/name to be disconnected from a network |
| 3412 | 3412 |
- **Force** - Force the container to disconnect from a network |
| 3413 | 3413 |
|
| 3414 |
-### Remove a network |
|
| 3414 |
+#### Remove a network |
|
| 3415 | 3415 |
|
| 3416 | 3416 |
`DELETE /networks/(id)` |
| 3417 | 3417 |
|
| ... | ... |
@@ -3431,9 +3429,9 @@ Instruct the driver to remove the network (`id`). |
| 3431 | 3431 |
- **404** - no such network |
| 3432 | 3432 |
- **500** - server error |
| 3433 | 3433 |
|
| 3434 |
-## 3.6 Plugins (experimental) |
|
| 3434 |
+### 3.6 Plugins (experimental) |
|
| 3435 | 3435 |
|
| 3436 |
-### List plugins |
|
| 3436 |
+#### List plugins |
|
| 3437 | 3437 |
|
| 3438 | 3438 |
`GET /plugins` |
| 3439 | 3439 |
|
| ... | ... |
@@ -3563,7 +3561,7 @@ Content-Type: application/json |
| 3563 | 3563 |
- **200** - no error |
| 3564 | 3564 |
- **500** - server error |
| 3565 | 3565 |
|
| 3566 |
-### Install a plugin |
|
| 3566 |
+#### Install a plugin |
|
| 3567 | 3567 |
|
| 3568 | 3568 |
`POST /plugins/pull?name=<plugin name>` |
| 3569 | 3569 |
|
| ... | ... |
@@ -3625,7 +3623,7 @@ Content-Length: 175 |
| 3625 | 3625 |
name must have at least one component |
| 3626 | 3626 |
- **500** - plugin already exists |
| 3627 | 3627 |
|
| 3628 |
-### Inspect a plugin |
|
| 3628 |
+#### Inspect a plugin |
|
| 3629 | 3629 |
|
| 3630 | 3630 |
`GET /plugins/(plugin name)` |
| 3631 | 3631 |
|
| ... | ... |
@@ -3758,7 +3756,7 @@ Content-Type: application/json |
| 3758 | 3758 |
- **200** - no error |
| 3759 | 3759 |
- **404** - plugin not installed |
| 3760 | 3760 |
|
| 3761 |
-### Enable a plugin |
|
| 3761 |
+#### Enable a plugin |
|
| 3762 | 3762 |
|
| 3763 | 3763 |
`POST /plugins/(plugin name)/enable` |
| 3764 | 3764 |
|
| ... | ... |
@@ -3786,7 +3784,7 @@ Content-Type: text/plain; charset=utf-8 |
| 3786 | 3786 |
- **200** - no error |
| 3787 | 3787 |
- **500** - plugin is already enabled |
| 3788 | 3788 |
|
| 3789 |
-### Disable a plugin |
|
| 3789 |
+#### Disable a plugin |
|
| 3790 | 3790 |
|
| 3791 | 3791 |
`POST /plugins/(plugin name)/disable` |
| 3792 | 3792 |
|
| ... | ... |
@@ -3814,7 +3812,7 @@ Content-Type: text/plain; charset=utf-8 |
| 3814 | 3814 |
- **200** - no error |
| 3815 | 3815 |
- **500** - plugin is already disabled |
| 3816 | 3816 |
|
| 3817 |
-### Remove a plugin |
|
| 3817 |
+#### Remove a plugin |
|
| 3818 | 3818 |
|
| 3819 | 3819 |
`DELETE /plugins/(plugin name)` |
| 3820 | 3820 |
|
| ... | ... |
@@ -3844,7 +3842,7 @@ Content-Type: text/plain; charset=utf-8 |
| 3844 | 3844 |
|
| 3845 | 3845 |
<!-- TODO Document "docker plugin push" endpoint once we have "plugin build" |
| 3846 | 3846 |
|
| 3847 |
-### Push a plugin |
|
| 3847 |
+#### Push a plugin |
|
| 3848 | 3848 |
|
| 3849 | 3849 |
`POST /v1.24/plugins/tiborvass/(plugin name)/push HTTP/1.1` |
| 3850 | 3850 |
|
| ... | ... |
@@ -3870,11 +3868,11 @@ an image](#create-an-image) section for more details. |
| 3870 | 3870 |
|
| 3871 | 3871 |
--> |
| 3872 | 3872 |
|
| 3873 |
-## 3.7 Nodes |
|
| 3873 |
+### 3.7 Nodes |
|
| 3874 | 3874 |
|
| 3875 | 3875 |
**Note**: Node operations require the engine to be part of a swarm. |
| 3876 | 3876 |
|
| 3877 |
-### List nodes |
|
| 3877 |
+#### List nodes |
|
| 3878 | 3878 |
|
| 3879 | 3879 |
|
| 3880 | 3880 |
`GET /nodes` |
| ... | ... |
@@ -3967,7 +3965,7 @@ List nodes |
| 3967 | 3967 |
- **200** – no error |
| 3968 | 3968 |
- **500** – server error |
| 3969 | 3969 |
|
| 3970 |
-### Inspect a node |
|
| 3970 |
+#### Inspect a node |
|
| 3971 | 3971 |
|
| 3972 | 3972 |
|
| 3973 | 3973 |
`GET /nodes/(id or name)` |
| ... | ... |
@@ -4049,7 +4047,7 @@ Return low-level information on the node `id` |
| 4049 | 4049 |
- **404** – no such node |
| 4050 | 4050 |
- **500** – server error |
| 4051 | 4051 |
|
| 4052 |
-### Remove a node |
|
| 4052 |
+#### Remove a node |
|
| 4053 | 4053 |
|
| 4054 | 4054 |
|
| 4055 | 4055 |
`DELETE /nodes/(id or name)` |
| ... | ... |
@@ -4077,7 +4075,7 @@ Remove a node from the swarm. |
| 4077 | 4077 |
- **404** – no such node |
| 4078 | 4078 |
- **500** – server error |
| 4079 | 4079 |
|
| 4080 |
-### Update a node |
|
| 4080 |
+#### Update a node |
|
| 4081 | 4081 |
|
| 4082 | 4082 |
|
| 4083 | 4083 |
`POST /nodes/(id)/update` |
| ... | ... |
@@ -4132,9 +4130,9 @@ JSON Parameters: |
| 4132 | 4132 |
- **404** – no such node |
| 4133 | 4133 |
- **500** – server error |
| 4134 | 4134 |
|
| 4135 |
-## 3.8 Swarm |
|
| 4135 |
+### 3.8 Swarm |
|
| 4136 | 4136 |
|
| 4137 |
-### Inspect swarm |
|
| 4137 |
+#### Inspect swarm |
|
| 4138 | 4138 |
|
| 4139 | 4139 |
|
| 4140 | 4140 |
`GET /swarm` |
| ... | ... |
@@ -4182,7 +4180,7 @@ Inspect swarm |
| 4182 | 4182 |
|
| 4183 | 4183 |
- **200** - no error |
| 4184 | 4184 |
|
| 4185 |
-### Initialize a new swarm |
|
| 4185 |
+#### Initialize a new swarm |
|
| 4186 | 4186 |
|
| 4187 | 4187 |
|
| 4188 | 4188 |
`POST /swarm/init` |
| ... | ... |
@@ -4258,7 +4256,7 @@ JSON Parameters: |
| 4258 | 4258 |
- **Options** - An object with key/value pairs that are interpreted |
| 4259 | 4259 |
as protocol-specific options for the external CA driver. |
| 4260 | 4260 |
|
| 4261 |
-### Join an existing swarm |
|
| 4261 |
+#### Join an existing swarm |
|
| 4262 | 4262 |
|
| 4263 | 4263 |
`POST /swarm/join` |
| 4264 | 4264 |
|
| ... | ... |
@@ -4300,7 +4298,7 @@ JSON Parameters: |
| 4300 | 4300 |
- **RemoteAddr** – Address of any manager node already participating in the swarm. |
| 4301 | 4301 |
- **JoinToken** – Secret token for joining this swarm. |
| 4302 | 4302 |
|
| 4303 |
-### Leave a swarm |
|
| 4303 |
+#### Leave a swarm |
|
| 4304 | 4304 |
|
| 4305 | 4305 |
|
| 4306 | 4306 |
`POST /swarm/leave` |
| ... | ... |
@@ -4326,7 +4324,7 @@ Leave a swarm |
| 4326 | 4326 |
- **200** – no error |
| 4327 | 4327 |
- **406** – node is not part of a swarm |
| 4328 | 4328 |
|
| 4329 |
-### Update a swarm |
|
| 4329 |
+#### Update a swarm |
|
| 4330 | 4330 |
|
| 4331 | 4331 |
|
| 4332 | 4332 |
`POST /swarm/update` |
| ... | ... |
@@ -4407,11 +4405,11 @@ JSON Parameters: |
| 4407 | 4407 |
- **Worker** - Token to use for joining as a worker. |
| 4408 | 4408 |
- **Manager** - Token to use for joining as a manager. |
| 4409 | 4409 |
|
| 4410 |
-## 3.9 Services |
|
| 4410 |
+### 3.9 Services |
|
| 4411 | 4411 |
|
| 4412 | 4412 |
**Note**: Service operations require to first be part of a swarm. |
| 4413 | 4413 |
|
| 4414 |
-### List services |
|
| 4414 |
+#### List services |
|
| 4415 | 4415 |
|
| 4416 | 4416 |
|
| 4417 | 4417 |
`GET /services` |
| ... | ... |
@@ -4516,7 +4514,7 @@ List services |
| 4516 | 4516 |
- **200** – no error |
| 4517 | 4517 |
- **500** – server error |
| 4518 | 4518 |
|
| 4519 |
-### Create a service |
|
| 4519 |
+#### Create a service |
|
| 4520 | 4520 |
|
| 4521 | 4521 |
`POST /services/create` |
| 4522 | 4522 |
|
| ... | ... |
@@ -4689,7 +4687,7 @@ image](#create-an-image) section for more details. |
| 4689 | 4689 |
section for more details. |
| 4690 | 4690 |
|
| 4691 | 4691 |
|
| 4692 |
-### Remove a service |
|
| 4692 |
+#### Remove a service |
|
| 4693 | 4693 |
|
| 4694 | 4694 |
|
| 4695 | 4695 |
`DELETE /services/(id or name)` |
| ... | ... |
@@ -4712,7 +4710,7 @@ Stop and remove the service `id` |
| 4712 | 4712 |
- **404** – no such service |
| 4713 | 4713 |
- **500** – server error |
| 4714 | 4714 |
|
| 4715 |
-### Inspect one or more services |
|
| 4715 |
+#### Inspect one or more services |
|
| 4716 | 4716 |
|
| 4717 | 4717 |
|
| 4718 | 4718 |
`GET /services/(id or name)` |
| ... | ... |
@@ -4801,7 +4799,7 @@ Return information on the service `id`. |
| 4801 | 4801 |
- **404** – no such service |
| 4802 | 4802 |
- **500** – server error |
| 4803 | 4803 |
|
| 4804 |
-### Update a service |
|
| 4804 |
+#### Update a service |
|
| 4805 | 4805 |
|
| 4806 | 4806 |
`POST /services/(id or name)/update` |
| 4807 | 4807 |
|
| ... | ... |
@@ -4934,11 +4932,11 @@ image](#create-an-image) section for more details. |
| 4934 | 4934 |
- **404** – no such service |
| 4935 | 4935 |
- **500** – server error |
| 4936 | 4936 |
|
| 4937 |
-## 3.10 Tasks |
|
| 4937 |
+### 3.10 Tasks |
|
| 4938 | 4938 |
|
| 4939 | 4939 |
**Note**: Task operations require the engine to be part of a swarm. |
| 4940 | 4940 |
|
| 4941 |
-### List tasks |
|
| 4941 |
+#### List tasks |
|
| 4942 | 4942 |
|
| 4943 | 4943 |
|
| 4944 | 4944 |
`GET /tasks` |
| ... | ... |
@@ -5136,7 +5134,7 @@ List tasks |
| 5136 | 5136 |
- **200** – no error |
| 5137 | 5137 |
- **500** – server error |
| 5138 | 5138 |
|
| 5139 |
-### Inspect a task |
|
| 5139 |
+#### Inspect a task |
|
| 5140 | 5140 |
|
| 5141 | 5141 |
|
| 5142 | 5142 |
`GET /tasks/(task id)` |
| ... | ... |
@@ -5239,9 +5237,9 @@ Get details on a task |
| 5239 | 5239 |
- **404** – unknown task |
| 5240 | 5240 |
- **500** – server error |
| 5241 | 5241 |
|
| 5242 |
-# 4. Going further |
|
| 5242 |
+## 4. Going further |
|
| 5243 | 5243 |
|
| 5244 |
-## 4.1 Inside `docker run` |
|
| 5244 |
+### 4.1 Inside `docker run` |
|
| 5245 | 5245 |
|
| 5246 | 5246 |
As an example, the `docker run` command line makes the following API calls: |
| 5247 | 5247 |
|
| ... | ... |
@@ -5259,7 +5257,7 @@ As an example, the `docker run` command line makes the following API calls: |
| 5259 | 5259 |
|
| 5260 | 5260 |
- If in detached mode or only `stdin` is attached, display the container's id. |
| 5261 | 5261 |
|
| 5262 |
-## 4.2 Hijacking |
|
| 5262 |
+### 4.2 Hijacking |
|
| 5263 | 5263 |
|
| 5264 | 5264 |
In this version of the API, `/attach`, uses hijacking to transport `stdin`, |
| 5265 | 5265 |
`stdout`, and `stderr` on the same socket. |
| ... | ... |
@@ -5274,7 +5272,7 @@ When Docker daemon detects the `Upgrade` header, it switches its status code |
| 5274 | 5274 |
from **200 OK** to **101 UPGRADED** and resends the same headers. |
| 5275 | 5275 |
|
| 5276 | 5276 |
|
| 5277 |
-## 4.3 CORS Requests |
|
| 5277 |
+### 4.3 CORS Requests |
|
| 5278 | 5278 |
|
| 5279 | 5279 |
To set cross origin requests to the Engine API please give values to |
| 5280 | 5280 |
`--api-cors-header` when running Docker in daemon mode. Set * (asterisk) allows all, |
| ... | ... |
@@ -72,7 +72,11 @@ keywords: "API, Docker, rcli, REST, documentation" |
| 72 | 72 |
* `DELETE /plugins/(plugin name)` delete a plugin. |
| 73 | 73 |
* `POST /node/(id or name)/update` now accepts both `id` or `name` to identify the node to update. |
| 74 | 74 |
* `GET /images/json` now support a `reference` filter. |
| 75 |
- |
|
| 75 |
+* `GET /secrets` returns information on the secrets. |
|
| 76 |
+* `POST /secrets/create` creates a secret. |
|
| 77 |
+* `DELETE /secrets/{id}` removes the secret `id`.
|
|
| 78 |
+* `GET /secrets/{id}` returns information on the secret `id`.
|
|
| 79 |
+* `POST /secrets/{id}/update` updates the secret `id`.
|
|
| 76 | 80 |
|
| 77 | 81 |
## v1.24 API changes |
| 78 | 82 |
|
| ... | ... |
@@ -32,7 +32,7 @@ The `filter` param to filter the list of image by reference (name or name:tag) i |
| 32 | 32 |
|
| 33 | 33 |
**Target For Removal In Release: v1.16** |
| 34 | 34 |
|
| 35 |
-`repository:shortid` syntax for referencing images is very little used, collides with with tag references can be confused with digest references. |
|
| 35 |
+`repository:shortid` syntax for referencing images is very little used, collides with tag references can be confused with digest references. |
|
| 36 | 36 |
|
| 37 | 37 |
### `docker daemon` subcommand |
| 38 | 38 |
**Deprecated In Release: [v1.13](https://github.com/docker/docker/releases/tag/v1.13.0)** |
| ... | ... |
@@ -82,7 +82,6 @@ Options: |
| 82 | 82 |
--memory-reservation string Memory soft limit |
| 83 | 83 |
--memory-swap string Swap limit equal to memory plus swap: '-1' to enable unlimited swap |
| 84 | 84 |
--memory-swappiness int Tune container memory swappiness (0 to 100) (default -1) |
| 85 |
- --mount value Attach a filesytem mount to the container (default []) |
|
| 86 | 85 |
--name string Assign a name to the container |
| 87 | 86 |
--network-alias value Add network-scoped alias for the container (default []) |
| 88 | 87 |
--network string Connect a container to a network (default "default") |
| ... | ... |
@@ -22,7 +22,7 @@ Usage: docker node ps [OPTIONS] [NODE...] |
| 22 | 22 |
List tasks running on one or more nodes, defaults to current node. |
| 23 | 23 |
|
| 24 | 24 |
Options: |
| 25 |
- -a, --all Show all tasks (default shows tasks that are or will be running) |
|
| 25 |
+ -a, --all Display all instances |
|
| 26 | 26 |
-f, --filter value Filter output based on conditions provided |
| 27 | 27 |
--help Print usage |
| 28 | 28 |
--no-resolve Do not map IDs to Names |
| ... | ... |
@@ -16,13 +16,13 @@ keywords: "plugin, inspect" |
| 16 | 16 |
# plugin inspect |
| 17 | 17 |
|
| 18 | 18 |
```markdown |
| 19 |
-Usage: docker plugin inspect [OPTIONS] PLUGIN [PLUGIN...] |
|
| 19 |
+Usage: docker plugin inspect [OPTIONS] PLUGIN|ID [PLUGIN|ID...] |
|
| 20 | 20 |
|
| 21 | 21 |
Display detailed information on one or more plugins |
| 22 | 22 |
|
| 23 | 23 |
Options: |
| 24 |
- -f, --format string Format the output using the given Go template |
|
| 25 |
- --help Print usage |
|
| 24 |
+ -f, --format string Format the output using the given Go template |
|
| 25 |
+ --help Print usage |
|
| 26 | 26 |
``` |
| 27 | 27 |
|
| 28 | 28 |
Returns information about a plugin. By default, this command renders all results |
| ... | ... |
@@ -92,7 +92,6 @@ Options: |
| 92 | 92 |
--memory-reservation string Memory soft limit |
| 93 | 93 |
--memory-swap string Swap limit equal to memory plus swap: '-1' to enable unlimited swap |
| 94 | 94 |
--memory-swappiness int Tune container memory swappiness (0 to 100) (default -1) |
| 95 |
- --mount value Attach a filesystem mount to the container (default []) |
|
| 96 | 95 |
--name string Assign a name to the container |
| 97 | 96 |
--network-alias value Add network-scoped alias for the container (default []) |
| 98 | 97 |
--network string Connect a container to a network |
| ... | ... |
@@ -284,21 +283,6 @@ of a bind mount must be a local directory, not a file. |
| 284 | 284 |
|
| 285 | 285 |
For in-depth information about volumes, refer to [manage data in containers](https://docs.docker.com/engine/tutorials/dockervolumes/) |
| 286 | 286 |
|
| 287 |
-### Add bin-mounts or volumes using the --mount flag |
|
| 288 |
- |
|
| 289 |
-The `--mount` flag allows you to mount volumes, host-directories and `tmpfs` |
|
| 290 |
-mounts in a container. |
|
| 291 |
- |
|
| 292 |
-The `--mount` flag supports most options that are supported by the `-v` or the |
|
| 293 |
-`--volume` flag, but uses a different syntax. For in-depth information on the |
|
| 294 |
-`--mount` flag, and a comparison between `--volume` and `--mount`, refer to |
|
| 295 |
-the [service create command reference](service_create.md#add-bind-mounts-or-volumes). |
|
| 296 |
- |
|
| 297 |
-Examples: |
|
| 298 |
- |
|
| 299 |
- $ docker run --read-only --mount type=volume,target=/icanwrite busybox touch /icanwrite/here |
|
| 300 |
- $ docker run -t -i --mount type=bind,src=/data,dst=/data busybox sh |
|
| 301 |
- |
|
| 302 | 287 |
### Publish or expose port (-p, --expose) |
| 303 | 288 |
|
| 304 | 289 |
$ docker run -p 127.0.0.1:80:8080 ubuntu bash |
| ... | ... |
@@ -678,7 +662,7 @@ The `credentialspec` must be in the format `file://spec.txt` or `registry://keyn |
| 678 | 678 |
|
| 679 | 679 |
### Stop container with timeout (--stop-timeout) |
| 680 | 680 |
|
| 681 |
-The `--stop-timeout` flag sets the the timeout (in seconds) that a pre-defined (see `--stop-signal`) system call |
|
| 681 |
+The `--stop-timeout` flag sets the timeout (in seconds) that a pre-defined (see `--stop-signal`) system call |
|
| 682 | 682 |
signal that will be sent to the container to exit. After timeout elapses the container will be killed with SIGKILL. |
| 683 | 683 |
|
| 684 | 684 |
### Specify isolation technology for container (--isolation) |
| ... | ... |
@@ -27,9 +27,9 @@ Options: |
| 27 | 27 |
-q, --quiet Only display IDs |
| 28 | 28 |
``` |
| 29 | 29 |
|
| 30 |
-Run this command from a manager to list the secrets in the Swarm. |
|
| 30 |
+Run this command on a manager node to list the secrets in the Swarm. |
|
| 31 | 31 |
|
| 32 |
-On a manager node: |
|
| 32 |
+## Examples |
|
| 33 | 33 |
|
| 34 | 34 |
```bash |
| 35 | 35 |
$ docker secret ls |
| ... | ... |
@@ -22,7 +22,6 @@ Usage: docker service ps [OPTIONS] SERVICE |
| 22 | 22 |
List the tasks of a service |
| 23 | 23 |
|
| 24 | 24 |
Options: |
| 25 |
- -a, --all Show all tasks (default shows tasks that are or will be running) |
|
| 26 | 25 |
-f, --filter filter Filter output based on conditions provided |
| 27 | 26 |
--help Print usage |
| 28 | 27 |
--no-resolve Do not map IDs to Names |
| ... | ... |
@@ -280,7 +280,7 @@ A virtual machine is a program that emulates a complete computer and imitates de |
| 280 | 280 |
It shares physical hardware resources with other users but isolates the operating system. The |
| 281 | 281 |
end user has the same experience on a Virtual Machine as they would have on dedicated hardware. |
| 282 | 282 |
|
| 283 |
-Compared to to containers, a virtual machine is heavier to run, provides more isolation, |
|
| 283 |
+Compared to containers, a virtual machine is heavier to run, provides more isolation, |
|
| 284 | 284 |
gets its own set of resources and does minimal sharing. |
| 285 | 285 |
|
| 286 | 286 |
*Also known as : VM* |
| ... | ... |
@@ -4,7 +4,7 @@ export SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
| 4 | 4 |
source "${SCRIPTDIR}/.validate"
|
| 5 | 5 |
|
| 6 | 6 |
IFS=$'\n' |
| 7 |
-files=( $(validate_diff --diff-filter=ACMR --name-only -- 'api/types/' || true) ) |
|
| 7 |
+files=( $(validate_diff --diff-filter=ACMR --name-only -- 'api/types/' 'api/swagger.yaml' || true) ) |
|
| 8 | 8 |
unset IFS |
| 9 | 9 |
|
| 10 | 10 |
if [ ${#files[@]} -gt 0 ]; then
|
| ... | ... |
@@ -26,5 +26,5 @@ if [ ${#files[@]} -gt 0 ]; then
|
| 26 | 26 |
echo 'Congratulations! All api changes are done the right way.' |
| 27 | 27 |
fi |
| 28 | 28 |
else |
| 29 |
- echo 'No api/types/ changes in diff.' |
|
| 29 |
+ echo 'No api/types/ or api/swagger.yaml changes in diff.' |
|
| 30 | 30 |
fi |
| ... | ... |
@@ -234,7 +234,9 @@ func (s *saveSession) saveImage(id image.ID) (map[layer.DiffID]distribution.Desc |
| 234 | 234 |
var layers []string |
| 235 | 235 |
var foreignSrcs map[layer.DiffID]distribution.Descriptor |
| 236 | 236 |
for i := range img.RootFS.DiffIDs {
|
| 237 |
- v1Img := image.V1Image{}
|
|
| 237 |
+ v1Img := image.V1Image{
|
|
| 238 |
+ Created: img.Created, |
|
| 239 |
+ } |
|
| 238 | 240 |
if i == len(img.RootFS.DiffIDs)-1 {
|
| 239 | 241 |
v1Img = img.V1Image |
| 240 | 242 |
} |
| ... | ... |
@@ -317,7 +317,7 @@ func (d *SwarmDaemon) getSecret(c *check.C, id string) *swarm.Secret {
|
| 317 | 317 |
func (d *SwarmDaemon) deleteSecret(c *check.C, id string) {
|
| 318 | 318 |
status, out, err := d.SockRequest("DELETE", "/secrets/"+id, nil)
|
| 319 | 319 |
c.Assert(err, checker.IsNil, check.Commentf(string(out))) |
| 320 |
- c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
|
|
| 320 |
+ c.Assert(status, checker.Equals, http.StatusNoContent, check.Commentf("output: %q", string(out)))
|
|
| 321 | 321 |
} |
| 322 | 322 |
|
| 323 | 323 |
func (d *SwarmDaemon) getSwarm(c *check.C) swarm.Swarm {
|
| ... | ... |
@@ -728,7 +728,7 @@ func (s *DockerSuite) TestContainerAPIInvalidPortSyntax(c *check.C) {
|
| 728 | 728 |
c.Assert(string(b[:]), checker.Contains, "invalid port") |
| 729 | 729 |
} |
| 730 | 730 |
|
| 731 |
-func (s *DockerSuite) TestContainerAPIInvalidRestartPolicyName(c *check.C) {
|
|
| 731 |
+func (s *DockerSuite) TestContainerAPIRestartPolicyInvalidPolicyName(c *check.C) {
|
|
| 732 | 732 |
config := `{
|
| 733 | 733 |
"Image": "busybox", |
| 734 | 734 |
"HostConfig": {
|
| ... | ... |
@@ -748,7 +748,7 @@ func (s *DockerSuite) TestContainerAPIInvalidRestartPolicyName(c *check.C) {
|
| 748 | 748 |
c.Assert(string(b[:]), checker.Contains, "invalid restart policy") |
| 749 | 749 |
} |
| 750 | 750 |
|
| 751 |
-func (s *DockerSuite) TestContainerAPIInvalidRestartPolicyRetryMismatch(c *check.C) {
|
|
| 751 |
+func (s *DockerSuite) TestContainerAPIRestartPolicyRetryMismatch(c *check.C) {
|
|
| 752 | 752 |
config := `{
|
| 753 | 753 |
"Image": "busybox", |
| 754 | 754 |
"HostConfig": {
|
| ... | ... |
@@ -765,10 +765,10 @@ func (s *DockerSuite) TestContainerAPIInvalidRestartPolicyRetryMismatch(c *check |
| 765 | 765 |
|
| 766 | 766 |
b, err := readBody(body) |
| 767 | 767 |
c.Assert(err, checker.IsNil) |
| 768 |
- c.Assert(string(b[:]), checker.Contains, "maximum restart count not valid with restart policy") |
|
| 768 |
+ c.Assert(string(b[:]), checker.Contains, "maximum retry count cannot be used with restart policy") |
|
| 769 | 769 |
} |
| 770 | 770 |
|
| 771 |
-func (s *DockerSuite) TestContainerAPIInvalidRestartPolicyPositiveRetryCount(c *check.C) {
|
|
| 771 |
+func (s *DockerSuite) TestContainerAPIRestartPolicyNegativeRetryCount(c *check.C) {
|
|
| 772 | 772 |
config := `{
|
| 773 | 773 |
"Image": "busybox", |
| 774 | 774 |
"HostConfig": {
|
| ... | ... |
@@ -785,7 +785,23 @@ func (s *DockerSuite) TestContainerAPIInvalidRestartPolicyPositiveRetryCount(c * |
| 785 | 785 |
|
| 786 | 786 |
b, err := readBody(body) |
| 787 | 787 |
c.Assert(err, checker.IsNil) |
| 788 |
- c.Assert(string(b[:]), checker.Contains, "maximum restart count must be a positive integer") |
|
| 788 |
+ c.Assert(string(b[:]), checker.Contains, "maximum retry count cannot be negative") |
|
| 789 |
+} |
|
| 790 |
+ |
|
| 791 |
+func (s *DockerSuite) TestContainerAPIRestartPolicyDefaultRetryCount(c *check.C) {
|
|
| 792 |
+ config := `{
|
|
| 793 |
+ "Image": "busybox", |
|
| 794 |
+ "HostConfig": {
|
|
| 795 |
+ "RestartPolicy": {
|
|
| 796 |
+ "Name": "on-failure", |
|
| 797 |
+ "MaximumRetryCount": 0 |
|
| 798 |
+ } |
|
| 799 |
+ } |
|
| 800 |
+ }` |
|
| 801 |
+ |
|
| 802 |
+ res, _, err := sockRequestRaw("POST", "/containers/create", strings.NewReader(config), "application/json")
|
|
| 803 |
+ c.Assert(err, checker.IsNil) |
|
| 804 |
+ c.Assert(res.StatusCode, checker.Equals, http.StatusCreated) |
|
| 789 | 805 |
} |
| 790 | 806 |
|
| 791 | 807 |
// Issue 7941 - test to make sure a "null" in JSON is just ignored. |
| ... | ... |
@@ -7311,3 +7311,19 @@ RUN ["cat", "/foo/file"] |
| 7311 | 7311 |
c.Fatal(err) |
| 7312 | 7312 |
} |
| 7313 | 7313 |
} |
| 7314 |
+ |
|
| 7315 |
+// Case-insensitive environment variables on Windows |
|
| 7316 |
+func (s *DockerSuite) TestBuildWindowsEnvCaseInsensitive(c *check.C) {
|
|
| 7317 |
+ testRequires(c, DaemonIsWindows) |
|
| 7318 |
+ name := "testbuildwindowsenvcaseinsensitive" |
|
| 7319 |
+ if _, err := buildImage(name, ` |
|
| 7320 |
+ FROM `+WindowsBaseImage+` |
|
| 7321 |
+ ENV FOO=bar foo=bar |
|
| 7322 |
+ `, true); err != nil {
|
|
| 7323 |
+ c.Fatal(err) |
|
| 7324 |
+ } |
|
| 7325 |
+ res := inspectFieldJSON(c, name, "Config.Env") |
|
| 7326 |
+ if res != `["foo=bar"]` { // Should not have FOO=bar in it - takes the last one processed. And only one entry as deduped.
|
|
| 7327 |
+ c.Fatalf("Case insensitive environment variables on Windows failed. Got %s", res)
|
|
| 7328 |
+ } |
|
| 7329 |
+} |
| ... | ... |
@@ -201,3 +201,52 @@ func (s *DockerSuite) TestPluginCreate(c *check.C) {
|
| 201 | 201 |
// The output will consists of one HEADER line and one line of foo/bar-driver |
| 202 | 202 |
c.Assert(len(strings.Split(strings.TrimSpace(out), "\n")), checker.Equals, 2) |
| 203 | 203 |
} |
| 204 |
+ |
|
| 205 |
+func (s *DockerSuite) TestPluginInspect(c *check.C) {
|
|
| 206 |
+ testRequires(c, DaemonIsLinux, Network) |
|
| 207 |
+ _, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", pNameWithTag)
|
|
| 208 |
+ c.Assert(err, checker.IsNil) |
|
| 209 |
+ |
|
| 210 |
+ out, _, err := dockerCmdWithError("plugin", "ls")
|
|
| 211 |
+ c.Assert(err, checker.IsNil) |
|
| 212 |
+ c.Assert(out, checker.Contains, pName) |
|
| 213 |
+ c.Assert(out, checker.Contains, pTag) |
|
| 214 |
+ c.Assert(out, checker.Contains, "true") |
|
| 215 |
+ |
|
| 216 |
+ // Find the ID first |
|
| 217 |
+ out, _, err = dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", pNameWithTag)
|
|
| 218 |
+ c.Assert(err, checker.IsNil) |
|
| 219 |
+ id := strings.TrimSpace(out) |
|
| 220 |
+ c.Assert(id, checker.Not(checker.Equals), "") |
|
| 221 |
+ |
|
| 222 |
+ // Long form |
|
| 223 |
+ out, _, err = dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", id)
|
|
| 224 |
+ c.Assert(err, checker.IsNil) |
|
| 225 |
+ c.Assert(strings.TrimSpace(out), checker.Equals, id) |
|
| 226 |
+ |
|
| 227 |
+ // Short form |
|
| 228 |
+ out, _, err = dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", id[:5])
|
|
| 229 |
+ c.Assert(err, checker.IsNil) |
|
| 230 |
+ c.Assert(strings.TrimSpace(out), checker.Equals, id) |
|
| 231 |
+ |
|
| 232 |
+ // Name with tag form |
|
| 233 |
+ out, _, err = dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", pNameWithTag)
|
|
| 234 |
+ c.Assert(err, checker.IsNil) |
|
| 235 |
+ c.Assert(strings.TrimSpace(out), checker.Equals, id) |
|
| 236 |
+ |
|
| 237 |
+ // Name without tag form |
|
| 238 |
+ out, _, err = dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", pName)
|
|
| 239 |
+ c.Assert(err, checker.IsNil) |
|
| 240 |
+ c.Assert(strings.TrimSpace(out), checker.Equals, id) |
|
| 241 |
+ |
|
| 242 |
+ _, _, err = dockerCmdWithError("plugin", "disable", pNameWithTag)
|
|
| 243 |
+ c.Assert(err, checker.IsNil) |
|
| 244 |
+ |
|
| 245 |
+ out, _, err = dockerCmdWithError("plugin", "remove", pNameWithTag)
|
|
| 246 |
+ c.Assert(err, checker.IsNil) |
|
| 247 |
+ c.Assert(out, checker.Contains, pNameWithTag) |
|
| 248 |
+ |
|
| 249 |
+ // After remove nothing should be found |
|
| 250 |
+ _, _, err = dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", id[:5])
|
|
| 251 |
+ c.Assert(err, checker.NotNil) |
|
| 252 |
+} |
| ... | ... |
@@ -74,7 +74,7 @@ func (s *DockerSuite) TestRestartWithVolumes(c *check.C) {
|
| 74 | 74 |
} |
| 75 | 75 |
|
| 76 | 76 |
func (s *DockerSuite) TestRestartPolicyNO(c *check.C) {
|
| 77 |
- out, _ := dockerCmd(c, "run", "-d", "--restart=no", "busybox", "false") |
|
| 77 |
+ out, _ := dockerCmd(c, "create", "--restart=no", "busybox") |
|
| 78 | 78 |
|
| 79 | 79 |
id := strings.TrimSpace(string(out)) |
| 80 | 80 |
name := inspectField(c, id, "HostConfig.RestartPolicy.Name") |
| ... | ... |
@@ -82,7 +82,7 @@ func (s *DockerSuite) TestRestartPolicyNO(c *check.C) {
|
| 82 | 82 |
} |
| 83 | 83 |
|
| 84 | 84 |
func (s *DockerSuite) TestRestartPolicyAlways(c *check.C) {
|
| 85 |
- out, _ := dockerCmd(c, "run", "-d", "--restart=always", "busybox", "false") |
|
| 85 |
+ out, _ := dockerCmd(c, "create", "--restart=always", "busybox") |
|
| 86 | 86 |
|
| 87 | 87 |
id := strings.TrimSpace(string(out)) |
| 88 | 88 |
name := inspectField(c, id, "HostConfig.RestartPolicy.Name") |
| ... | ... |
@@ -95,12 +95,36 @@ func (s *DockerSuite) TestRestartPolicyAlways(c *check.C) {
|
| 95 | 95 |
} |
| 96 | 96 |
|
| 97 | 97 |
func (s *DockerSuite) TestRestartPolicyOnFailure(c *check.C) {
|
| 98 |
- out, _ := dockerCmd(c, "run", "-d", "--restart=on-failure:1", "busybox", "false") |
|
| 98 |
+ out, _, err := dockerCmdWithError("create", "--restart=on-failure:-1", "busybox")
|
|
| 99 |
+ c.Assert(err, check.NotNil, check.Commentf(out)) |
|
| 100 |
+ c.Assert(out, checker.Contains, "maximum retry count cannot be negative") |
|
| 101 |
+ |
|
| 102 |
+ out, _ = dockerCmd(c, "create", "--restart=on-failure:1", "busybox") |
|
| 99 | 103 |
|
| 100 | 104 |
id := strings.TrimSpace(string(out)) |
| 101 | 105 |
name := inspectField(c, id, "HostConfig.RestartPolicy.Name") |
| 106 |
+ maxRetry := inspectField(c, id, "HostConfig.RestartPolicy.MaximumRetryCount") |
|
| 107 |
+ |
|
| 102 | 108 |
c.Assert(name, checker.Equals, "on-failure") |
| 109 |
+ c.Assert(maxRetry, checker.Equals, "1") |
|
| 110 |
+ |
|
| 111 |
+ out, _ = dockerCmd(c, "create", "--restart=on-failure:0", "busybox") |
|
| 103 | 112 |
|
| 113 |
+ id = strings.TrimSpace(string(out)) |
|
| 114 |
+ name = inspectField(c, id, "HostConfig.RestartPolicy.Name") |
|
| 115 |
+ maxRetry = inspectField(c, id, "HostConfig.RestartPolicy.MaximumRetryCount") |
|
| 116 |
+ |
|
| 117 |
+ c.Assert(name, checker.Equals, "on-failure") |
|
| 118 |
+ c.Assert(maxRetry, checker.Equals, "0") |
|
| 119 |
+ |
|
| 120 |
+ out, _ = dockerCmd(c, "create", "--restart=on-failure", "busybox") |
|
| 121 |
+ |
|
| 122 |
+ id = strings.TrimSpace(string(out)) |
|
| 123 |
+ name = inspectField(c, id, "HostConfig.RestartPolicy.Name") |
|
| 124 |
+ maxRetry = inspectField(c, id, "HostConfig.RestartPolicy.MaximumRetryCount") |
|
| 125 |
+ |
|
| 126 |
+ c.Assert(name, checker.Equals, "on-failure") |
|
| 127 |
+ c.Assert(maxRetry, checker.Equals, "0") |
|
| 104 | 128 |
} |
| 105 | 129 |
|
| 106 | 130 |
// a good container with --restart=on-failure:3 |
| ... | ... |
@@ -4590,184 +4590,6 @@ func (s *DockerSuite) TestRunDuplicateMount(c *check.C) {
|
| 4590 | 4590 |
c.Assert(out, checker.Contains, "null") |
| 4591 | 4591 |
} |
| 4592 | 4592 |
|
| 4593 |
-func (s *DockerSuite) TestRunMount(c *check.C) {
|
|
| 4594 |
- testRequires(c, DaemonIsLinux, SameHostDaemon, NotUserNamespace) |
|
| 4595 |
- |
|
| 4596 |
- // mnt1, mnt2, and testCatFooBar are commonly used in multiple test cases |
|
| 4597 |
- tmpDir, err := ioutil.TempDir("", "mount")
|
|
| 4598 |
- if err != nil {
|
|
| 4599 |
- c.Fatal(err) |
|
| 4600 |
- } |
|
| 4601 |
- defer os.RemoveAll(tmpDir) |
|
| 4602 |
- mnt1, mnt2 := path.Join(tmpDir, "mnt1"), path.Join(tmpDir, "mnt2") |
|
| 4603 |
- if err := os.Mkdir(mnt1, 0755); err != nil {
|
|
| 4604 |
- c.Fatal(err) |
|
| 4605 |
- } |
|
| 4606 |
- if err := os.Mkdir(mnt2, 0755); err != nil {
|
|
| 4607 |
- c.Fatal(err) |
|
| 4608 |
- } |
|
| 4609 |
- if err := ioutil.WriteFile(path.Join(mnt1, "test1"), []byte("test1"), 0644); err != nil {
|
|
| 4610 |
- c.Fatal(err) |
|
| 4611 |
- } |
|
| 4612 |
- if err := ioutil.WriteFile(path.Join(mnt2, "test2"), []byte("test2"), 0644); err != nil {
|
|
| 4613 |
- c.Fatal(err) |
|
| 4614 |
- } |
|
| 4615 |
- testCatFooBar := func(cName string) error {
|
|
| 4616 |
- out, _ := dockerCmd(c, "exec", cName, "cat", "/foo/test1") |
|
| 4617 |
- if out != "test1" {
|
|
| 4618 |
- return fmt.Errorf("%s not mounted on /foo", mnt1)
|
|
| 4619 |
- } |
|
| 4620 |
- out, _ = dockerCmd(c, "exec", cName, "cat", "/bar/test2") |
|
| 4621 |
- if out != "test2" {
|
|
| 4622 |
- return fmt.Errorf("%s not mounted on /bar", mnt2)
|
|
| 4623 |
- } |
|
| 4624 |
- return nil |
|
| 4625 |
- } |
|
| 4626 |
- |
|
| 4627 |
- type testCase struct {
|
|
| 4628 |
- equivalents [][]string |
|
| 4629 |
- valid bool |
|
| 4630 |
- // fn should be nil if valid==false |
|
| 4631 |
- fn func(cName string) error |
|
| 4632 |
- } |
|
| 4633 |
- cases := []testCase{
|
|
| 4634 |
- {
|
|
| 4635 |
- equivalents: [][]string{
|
|
| 4636 |
- {
|
|
| 4637 |
- "--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt1),
|
|
| 4638 |
- "--mount", fmt.Sprintf("type=bind,src=%s,dst=/bar", mnt2),
|
|
| 4639 |
- }, |
|
| 4640 |
- {
|
|
| 4641 |
- "--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt1),
|
|
| 4642 |
- "--mount", fmt.Sprintf("type=bind,src=%s,target=/bar", mnt2),
|
|
| 4643 |
- }, |
|
| 4644 |
- {
|
|
| 4645 |
- "--volume", fmt.Sprintf("%s:/foo", mnt1),
|
|
| 4646 |
- "--mount", fmt.Sprintf("type=bind,src=%s,target=/bar", mnt2),
|
|
| 4647 |
- }, |
|
| 4648 |
- }, |
|
| 4649 |
- valid: true, |
|
| 4650 |
- fn: testCatFooBar, |
|
| 4651 |
- }, |
|
| 4652 |
- {
|
|
| 4653 |
- equivalents: [][]string{
|
|
| 4654 |
- {
|
|
| 4655 |
- "--mount", fmt.Sprintf("type=volume,src=%s,dst=/foo", mnt1),
|
|
| 4656 |
- "--mount", fmt.Sprintf("type=volume,src=%s,dst=/bar", mnt2),
|
|
| 4657 |
- }, |
|
| 4658 |
- {
|
|
| 4659 |
- "--mount", fmt.Sprintf("type=volume,src=%s,dst=/foo", mnt1),
|
|
| 4660 |
- "--mount", fmt.Sprintf("type=volume,src=%s,target=/bar", mnt2),
|
|
| 4661 |
- }, |
|
| 4662 |
- }, |
|
| 4663 |
- valid: false, |
|
| 4664 |
- }, |
|
| 4665 |
- {
|
|
| 4666 |
- equivalents: [][]string{
|
|
| 4667 |
- {
|
|
| 4668 |
- "--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt1),
|
|
| 4669 |
- "--mount", fmt.Sprintf("type=volume,src=%s,dst=/bar", mnt2),
|
|
| 4670 |
- }, |
|
| 4671 |
- {
|
|
| 4672 |
- "--volume", fmt.Sprintf("%s:/foo", mnt1),
|
|
| 4673 |
- "--mount", fmt.Sprintf("type=volume,src=%s,target=/bar", mnt2),
|
|
| 4674 |
- }, |
|
| 4675 |
- }, |
|
| 4676 |
- valid: false, |
|
| 4677 |
- fn: testCatFooBar, |
|
| 4678 |
- }, |
|
| 4679 |
- {
|
|
| 4680 |
- equivalents: [][]string{
|
|
| 4681 |
- {
|
|
| 4682 |
- "--read-only", |
|
| 4683 |
- "--mount", "type=volume,dst=/bar", |
|
| 4684 |
- }, |
|
| 4685 |
- }, |
|
| 4686 |
- valid: true, |
|
| 4687 |
- fn: func(cName string) error {
|
|
| 4688 |
- _, _, err := dockerCmdWithError("exec", cName, "touch", "/bar/icanwritehere")
|
|
| 4689 |
- return err |
|
| 4690 |
- }, |
|
| 4691 |
- }, |
|
| 4692 |
- {
|
|
| 4693 |
- equivalents: [][]string{
|
|
| 4694 |
- {
|
|
| 4695 |
- "--read-only", |
|
| 4696 |
- "--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt1),
|
|
| 4697 |
- "--mount", "type=volume,dst=/bar", |
|
| 4698 |
- }, |
|
| 4699 |
- {
|
|
| 4700 |
- "--read-only", |
|
| 4701 |
- "--volume", fmt.Sprintf("%s:/foo", mnt1),
|
|
| 4702 |
- "--mount", "type=volume,dst=/bar", |
|
| 4703 |
- }, |
|
| 4704 |
- }, |
|
| 4705 |
- valid: true, |
|
| 4706 |
- fn: func(cName string) error {
|
|
| 4707 |
- out, _ := dockerCmd(c, "exec", cName, "cat", "/foo/test1") |
|
| 4708 |
- if out != "test1" {
|
|
| 4709 |
- return fmt.Errorf("%s not mounted on /foo", mnt1)
|
|
| 4710 |
- } |
|
| 4711 |
- _, _, err := dockerCmdWithError("exec", cName, "touch", "/bar/icanwritehere")
|
|
| 4712 |
- return err |
|
| 4713 |
- }, |
|
| 4714 |
- }, |
|
| 4715 |
- {
|
|
| 4716 |
- equivalents: [][]string{
|
|
| 4717 |
- {
|
|
| 4718 |
- "--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt1),
|
|
| 4719 |
- "--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt2),
|
|
| 4720 |
- }, |
|
| 4721 |
- {
|
|
| 4722 |
- "--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt1),
|
|
| 4723 |
- "--mount", fmt.Sprintf("type=bind,src=%s,target=/foo", mnt2),
|
|
| 4724 |
- }, |
|
| 4725 |
- {
|
|
| 4726 |
- "--volume", fmt.Sprintf("%s:/foo", mnt1),
|
|
| 4727 |
- "--mount", fmt.Sprintf("type=bind,src=%s,target=/foo", mnt2),
|
|
| 4728 |
- }, |
|
| 4729 |
- }, |
|
| 4730 |
- valid: false, |
|
| 4731 |
- }, |
|
| 4732 |
- {
|
|
| 4733 |
- equivalents: [][]string{
|
|
| 4734 |
- {
|
|
| 4735 |
- "--volume", fmt.Sprintf("%s:/foo", mnt1),
|
|
| 4736 |
- "--mount", fmt.Sprintf("type=volume,src=%s,target=/foo", mnt2),
|
|
| 4737 |
- }, |
|
| 4738 |
- }, |
|
| 4739 |
- valid: false, |
|
| 4740 |
- }, |
|
| 4741 |
- {
|
|
| 4742 |
- equivalents: [][]string{
|
|
| 4743 |
- {
|
|
| 4744 |
- "--mount", "type=volume,target=/foo", |
|
| 4745 |
- "--mount", "type=volume,target=/foo", |
|
| 4746 |
- }, |
|
| 4747 |
- }, |
|
| 4748 |
- valid: false, |
|
| 4749 |
- }, |
|
| 4750 |
- } |
|
| 4751 |
- |
|
| 4752 |
- for i, testCase := range cases {
|
|
| 4753 |
- for j, opts := range testCase.equivalents {
|
|
| 4754 |
- cName := fmt.Sprintf("mount-%d-%d", i, j)
|
|
| 4755 |
- _, _, err := dockerCmdWithError(append([]string{"run", "-i", "-d", "--name", cName},
|
|
| 4756 |
- append(opts, []string{"busybox", "top"}...)...)...)
|
|
| 4757 |
- if testCase.valid {
|
|
| 4758 |
- c.Assert(err, check.IsNil, |
|
| 4759 |
- check.Commentf("got error while creating a container with %v (%s)", opts, cName))
|
|
| 4760 |
- c.Assert(testCase.fn(cName), check.IsNil, |
|
| 4761 |
- check.Commentf("got error while executing test for %v (%s)", opts, cName))
|
|
| 4762 |
- dockerCmd(c, "rm", "-f", cName) |
|
| 4763 |
- } else {
|
|
| 4764 |
- c.Assert(err, checker.NotNil, |
|
| 4765 |
- check.Commentf("got nil while creating a container with %v (%s)", opts, cName))
|
|
| 4766 |
- } |
|
| 4767 |
- } |
|
| 4768 |
- } |
|
| 4769 |
-} |
|
| 4770 |
- |
|
| 4771 | 4593 |
func (s *DockerSuite) TestRunWindowsWithCPUCount(c *check.C) {
|
| 4772 | 4594 |
testRequires(c, DaemonIsWindows) |
| 4773 | 4595 |
|
| ... | ... |
@@ -123,7 +123,7 @@ func (s *DockerSwarmSuite) TestServiceCreateWithSecretSourceTarget(c *check.C) {
|
| 123 | 123 |
|
| 124 | 124 |
func (s *DockerSwarmSuite) TestServiceCreateMountTmpfs(c *check.C) {
|
| 125 | 125 |
d := s.AddDaemon(c, true, true) |
| 126 |
- out, err := d.Cmd("service", "create", "--mount", "type=tmpfs,target=/foo", "busybox", "sh", "-c", "mount | grep foo; tail -f /dev/null")
|
|
| 126 |
+ out, err := d.Cmd("service", "create", "--mount", "type=tmpfs,target=/foo,tmpfs-size=1MB", "busybox", "sh", "-c", "mount | grep foo; tail -f /dev/null")
|
|
| 127 | 127 |
c.Assert(err, checker.IsNil, check.Commentf(out)) |
| 128 | 128 |
id := strings.TrimSpace(out) |
| 129 | 129 |
|
| ... | ... |
@@ -152,6 +152,8 @@ func (s *DockerSwarmSuite) TestServiceCreateMountTmpfs(c *check.C) {
|
| 152 | 152 |
c.Assert(mountConfig[0].Source, checker.Equals, "") |
| 153 | 153 |
c.Assert(mountConfig[0].Target, checker.Equals, "/foo") |
| 154 | 154 |
c.Assert(mountConfig[0].Type, checker.Equals, mount.TypeTmpfs) |
| 155 |
+ c.Assert(mountConfig[0].TmpfsOptions, checker.NotNil) |
|
| 156 |
+ c.Assert(mountConfig[0].TmpfsOptions.SizeBytes, checker.Equals, int64(1048576)) |
|
| 155 | 157 |
|
| 156 | 158 |
// check container mounts actual |
| 157 | 159 |
out, err = s.nodeCmd(c, task.NodeID, "inspect", "--format", "{{json .Mounts}}", task.Status.ContainerStatus.ContainerID)
|
| ... | ... |
@@ -169,4 +171,5 @@ func (s *DockerSwarmSuite) TestServiceCreateMountTmpfs(c *check.C) {
|
| 169 | 169 |
out, err = s.nodeCmd(c, task.NodeID, "logs", task.Status.ContainerStatus.ContainerID) |
| 170 | 170 |
c.Assert(err, checker.IsNil, check.Commentf(out)) |
| 171 | 171 |
c.Assert(strings.TrimSpace(out), checker.HasPrefix, "tmpfs on /foo type tmpfs") |
| 172 |
+ c.Assert(strings.TrimSpace(out), checker.Contains, "size=1024k") |
|
| 172 | 173 |
} |
| ... | ... |
@@ -226,88 +226,6 @@ func (s *DockerSwarmSuite) TestSwarmNodeTaskListFilter(c *check.C) {
|
| 226 | 226 |
c.Assert(out, checker.Not(checker.Contains), name+".1") |
| 227 | 227 |
c.Assert(out, checker.Not(checker.Contains), name+".2") |
| 228 | 228 |
c.Assert(out, checker.Not(checker.Contains), name+".3") |
| 229 |
- |
|
| 230 |
- out, err = d.Cmd("node", "ps", "--filter", "desired-state=running", "self")
|
|
| 231 |
- c.Assert(err, checker.IsNil) |
|
| 232 |
- c.Assert(out, checker.Contains, name+".1") |
|
| 233 |
- c.Assert(out, checker.Contains, name+".2") |
|
| 234 |
- c.Assert(out, checker.Contains, name+".3") |
|
| 235 |
- |
|
| 236 |
- out, err = d.Cmd("node", "ps", "--filter", "desired-state=shutdown", "self")
|
|
| 237 |
- c.Assert(err, checker.IsNil) |
|
| 238 |
- c.Assert(out, checker.Not(checker.Contains), name+".1") |
|
| 239 |
- c.Assert(out, checker.Not(checker.Contains), name+".2") |
|
| 240 |
- c.Assert(out, checker.Not(checker.Contains), name+".3") |
|
| 241 |
-} |
|
| 242 |
- |
|
| 243 |
-func (s *DockerSwarmSuite) TestSwarmServiceTaskListAll(c *check.C) {
|
|
| 244 |
- d := s.AddDaemon(c, true, true) |
|
| 245 |
- |
|
| 246 |
- name := "service-task-list-1" |
|
| 247 |
- out, err := d.Cmd("service", "create", "--name", name, "--replicas=3", "busybox", "top")
|
|
| 248 |
- c.Assert(err, checker.IsNil) |
|
| 249 |
- c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") |
|
| 250 |
- |
|
| 251 |
- // make sure task has been deployed. |
|
| 252 |
- waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 3) |
|
| 253 |
- |
|
| 254 |
- out, err = d.Cmd("service", "ps", name)
|
|
| 255 |
- c.Assert(err, checker.IsNil) |
|
| 256 |
- c.Assert(out, checker.Contains, name+".1") |
|
| 257 |
- c.Assert(out, checker.Contains, name+".2") |
|
| 258 |
- c.Assert(out, checker.Contains, name+".3") |
|
| 259 |
- |
|
| 260 |
- // Get the last container id so we can restart it to cause a task error in the history |
|
| 261 |
- containerID, err := d.Cmd("ps", "-q", "-l")
|
|
| 262 |
- c.Assert(err, checker.IsNil) |
|
| 263 |
- |
|
| 264 |
- _, err = d.Cmd("stop", strings.TrimSpace(containerID))
|
|
| 265 |
- c.Assert(err, checker.IsNil) |
|
| 266 |
- |
|
| 267 |
- waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 3) |
|
| 268 |
- |
|
| 269 |
- out, err = d.Cmd("service", "ps", name)
|
|
| 270 |
- c.Assert(err, checker.IsNil) |
|
| 271 |
- c.Assert(out, checker.Count, name, 3) |
|
| 272 |
- |
|
| 273 |
- out, err = d.Cmd("service", "ps", name, "-a")
|
|
| 274 |
- c.Assert(err, checker.IsNil) |
|
| 275 |
- c.Assert(out, checker.Count, name, 4) |
|
| 276 |
-} |
|
| 277 |
- |
|
| 278 |
-func (s *DockerSwarmSuite) TestSwarmNodeTaskListAll(c *check.C) {
|
|
| 279 |
- d := s.AddDaemon(c, true, true) |
|
| 280 |
- |
|
| 281 |
- name := "node-task-list" |
|
| 282 |
- out, err := d.Cmd("service", "create", "--name", name, "--replicas=3", "busybox", "top")
|
|
| 283 |
- c.Assert(err, checker.IsNil) |
|
| 284 |
- c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") |
|
| 285 |
- |
|
| 286 |
- // make sure task has been deployed. |
|
| 287 |
- waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 3) |
|
| 288 |
- |
|
| 289 |
- out, err = d.Cmd("service", "ps", name)
|
|
| 290 |
- c.Assert(err, checker.IsNil) |
|
| 291 |
- c.Assert(out, checker.Contains, name+".1") |
|
| 292 |
- c.Assert(out, checker.Contains, name+".2") |
|
| 293 |
- c.Assert(out, checker.Contains, name+".3") |
|
| 294 |
- |
|
| 295 |
- // Get the last container id so we can restart it to cause a task error in the history |
|
| 296 |
- containerID, err := d.Cmd("ps", "-q", "-l")
|
|
| 297 |
- c.Assert(err, checker.IsNil) |
|
| 298 |
- |
|
| 299 |
- _, err = d.Cmd("stop", strings.TrimSpace(containerID))
|
|
| 300 |
- c.Assert(err, checker.IsNil) |
|
| 301 |
- |
|
| 302 |
- waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 3) |
|
| 303 |
- |
|
| 304 |
- out, err = d.Cmd("node", "ps", "self")
|
|
| 305 |
- c.Assert(err, checker.IsNil) |
|
| 306 |
- c.Assert(out, checker.Count, name, 3) |
|
| 307 |
- |
|
| 308 |
- out, err = d.Cmd("node", "ps", "self", "-a")
|
|
| 309 |
- c.Assert(err, checker.IsNil) |
|
| 310 |
- c.Assert(out, checker.Count, name, 4) |
|
| 311 | 229 |
} |
| 312 | 230 |
|
| 313 | 231 |
// Test case for #25375 |
| ... | ... |
@@ -405,13 +405,8 @@ func (clnt *client) getContainerLastEventSinceTime(id string, tsp *timestamp.Tim |
| 405 | 405 |
logrus.Errorf("libcontainerd: failed to get container event for %s: %q", id, err)
|
| 406 | 406 |
return nil, err |
| 407 | 407 |
} |
| 408 |
- |
|
| 409 |
- logrus.Debugf("libcontainerd: received past event %#v", e)
|
|
| 410 |
- |
|
| 411 |
- switch e.Type {
|
|
| 412 |
- case StateExit, StatePause, StateResume: |
|
| 413 |
- ev = e |
|
| 414 |
- } |
|
| 408 |
+ ev = e |
|
| 409 |
+ logrus.Debugf("libcontainerd: received past event %#v", ev)
|
|
| 415 | 410 |
} |
| 416 | 411 |
|
| 417 | 412 |
return ev, nil |
| ... | ... |
@@ -456,30 +451,36 @@ func (clnt *client) Restore(containerID string, attachStdio StdioCallback, optio |
| 456 | 456 |
// Get its last event |
| 457 | 457 |
ev, eerr := clnt.getContainerLastEvent(containerID) |
| 458 | 458 |
if err != nil || cont.Status == "Stopped" {
|
| 459 |
- if err != nil && !strings.Contains(err.Error(), "container not found") {
|
|
| 460 |
- // Legitimate error |
|
| 461 |
- return err |
|
| 459 |
+ if err != nil {
|
|
| 460 |
+ logrus.Warnf("libcontainerd: failed to retrieve container %s state: %v", containerID, err)
|
|
| 462 | 461 |
} |
| 463 |
- |
|
| 464 |
- if ev == nil {
|
|
| 465 |
- if _, err := clnt.getContainer(containerID); err == nil {
|
|
| 466 |
- // If ev is nil and the container is running in containerd, |
|
| 467 |
- // we already consumed all the event of the |
|
| 468 |
- // container, included the "exit" one. |
|
| 469 |
- // Thus we return to avoid overriding the Exit Code. |
|
| 470 |
- logrus.Warnf("libcontainerd: restore was called on a fully synced container (%s)", containerID)
|
|
| 471 |
- return nil |
|
| 472 |
- } |
|
| 473 |
- // the container is not running so we need to fix the state within docker |
|
| 474 |
- ev = &containerd.Event{
|
|
| 475 |
- Type: StateExit, |
|
| 476 |
- Status: 1, |
|
| 462 |
+ if ev != nil && (ev.Pid != InitFriendlyName || ev.Type != StateExit) {
|
|
| 463 |
+ // Wait a while for the exit event |
|
| 464 |
+ timeout := time.NewTimer(10 * time.Second) |
|
| 465 |
+ tick := time.NewTicker(100 * time.Millisecond) |
|
| 466 |
+ stop: |
|
| 467 |
+ for {
|
|
| 468 |
+ select {
|
|
| 469 |
+ case <-timeout.C: |
|
| 470 |
+ break stop |
|
| 471 |
+ case <-tick.C: |
|
| 472 |
+ ev, eerr = clnt.getContainerLastEvent(containerID) |
|
| 473 |
+ if eerr != nil {
|
|
| 474 |
+ break stop |
|
| 475 |
+ } |
|
| 476 |
+ if ev != nil && ev.Pid == InitFriendlyName && ev.Type == StateExit {
|
|
| 477 |
+ break stop |
|
| 478 |
+ } |
|
| 479 |
+ } |
|
| 477 | 480 |
} |
| 481 |
+ timeout.Stop() |
|
| 482 |
+ tick.Stop() |
|
| 478 | 483 |
} |
| 479 | 484 |
|
| 480 |
- // get the exit status for this container |
|
| 481 |
- ec := uint32(0) |
|
| 482 |
- if eerr == nil && ev.Type == StateExit {
|
|
| 485 |
+ // get the exit status for this container, if we don't have |
|
| 486 |
+ // one, indicate an error |
|
| 487 |
+ ec := uint32(255) |
|
| 488 |
+ if eerr == nil && ev != nil && ev.Pid == InitFriendlyName && ev.Type == StateExit {
|
|
| 483 | 489 |
ec = ev.Status |
| 484 | 490 |
} |
| 485 | 491 |
clnt.setExited(containerID, ec) |
| ... | ... |
@@ -8,6 +8,7 @@ import ( |
| 8 | 8 |
"os" |
| 9 | 9 |
"path/filepath" |
| 10 | 10 |
goruntime "runtime" |
| 11 |
+ "strings" |
|
| 11 | 12 |
"time" |
| 12 | 13 |
|
| 13 | 14 |
containerd "github.com/docker/containerd/api/grpc/types" |
| ... | ... |
@@ -86,6 +87,9 @@ func (p *process) sendCloseStdin() error {
|
| 86 | 86 |
Pid: p.friendlyName, |
| 87 | 87 |
CloseStdin: true, |
| 88 | 88 |
}) |
| 89 |
+ if err != nil && (strings.Contains(err.Error(), "container not found") || strings.Contains(err.Error(), "process not found")) {
|
|
| 90 |
+ return nil |
|
| 91 |
+ } |
|
| 89 | 92 |
return err |
| 90 | 93 |
} |
| 91 | 94 |
|
| ... | ... |
@@ -83,7 +83,7 @@ set as the **URL**, the repository is cloned locally and then sent as the contex |
| 83 | 83 |
Users pass these values at build-time. Docker uses the `buildargs` as the |
| 84 | 84 |
environment context for command(s) run via the Dockerfile's `RUN` instruction |
| 85 | 85 |
or for variable expansion in other Dockerfile instructions. This is not meant |
| 86 |
- for passing secret values. [Read more about the buildargs instruction](/reference/builder/#arg) |
|
| 86 |
+ for passing secret values. [Read more about the buildargs instruction](https://docs.docker.com/engine/reference/builder/#arg) |
|
| 87 | 87 |
|
| 88 | 88 |
**--force-rm**=*true*|*false* |
| 89 | 89 |
Always remove intermediate containers, even after unsuccessful builds. The default is *false*. |
| ... | ... |
@@ -56,7 +56,6 @@ docker-create - Create a new container |
| 56 | 56 |
[**--memory-reservation**[=*MEMORY-RESERVATION*]] |
| 57 | 57 |
[**--memory-swap**[=*LIMIT*]] |
| 58 | 58 |
[**--memory-swappiness**[=*MEMORY-SWAPPINESS*]] |
| 59 |
-[**--mount**[=*MOUNT*]] |
|
| 60 | 59 |
[**--name**[=*NAME*]] |
| 61 | 60 |
[**--network-alias**[=*[]*]] |
| 62 | 61 |
[**--network**[=*"bridge"*]] |
| ... | ... |
@@ -20,7 +20,7 @@ do not specify a `SERVER`, the command uses Docker's public registry located at |
| 20 | 20 |
`docker login` requires user to use `sudo` or be `root`, except when: |
| 21 | 21 |
|
| 22 | 22 |
1. connecting to a remote daemon, such as a `docker-machine` provisioned `docker engine`. |
| 23 |
-2. user is added to the `docker` group. This will impact the security of your system; the `docker` group is `root` equivalent. See [Docker Daemon Attack Surface](https://docs.docker.com/articles/security/#docker-daemon-attack-surface) for details. |
|
| 23 |
+2. user is added to the `docker` group. This will impact the security of your system; the `docker` group is `root` equivalent. See [Docker Daemon Attack Surface](https://docs.docker.com/engine/articles/security/#docker-daemon-attack-surface) for details. |
|
| 24 | 24 |
|
| 25 | 25 |
You can log into any public or private repository for which you have |
| 26 | 26 |
credentials. When you log in, the command stores encoded credentials in |
| ... | ... |
@@ -18,7 +18,7 @@ that it is being suspended, and subsequently resumed. On Windows, only Hyper-V |
| 18 | 18 |
containers can be paused. |
| 19 | 19 |
|
| 20 | 20 |
See the [cgroups freezer documentation] |
| 21 |
-(https://www.kernel.org/doc/Documentation/cgroups/freezer-subsystem.txt) for |
|
| 21 |
+(https://www.kernel.org/doc/Documentation/cgroup-v1/freezer-subsystem.txt) for |
|
| 22 | 22 |
further details. |
| 23 | 23 |
|
| 24 | 24 |
# OPTIONS |
| ... | ... |
@@ -58,7 +58,6 @@ docker-run - Run a command in a new container |
| 58 | 58 |
[**--memory-reservation**[=*MEMORY-RESERVATION*]] |
| 59 | 59 |
[**--memory-swap**[=*LIMIT*]] |
| 60 | 60 |
[**--memory-swappiness**[=*MEMORY-SWAPPINESS*]] |
| 61 |
-[**--mount**[=*MOUNT*]] |
|
| 62 | 61 |
[**--name**[=*NAME*]] |
| 63 | 62 |
[**--network-alias**[=*[]*]] |
| 64 | 63 |
[**--network**[=*"bridge"*]] |
| ... | ... |
@@ -14,7 +14,7 @@ The `docker unpause` command un-suspends all processes in a container. |
| 14 | 14 |
On Linux, it does this using the cgroups freezer. |
| 15 | 15 |
|
| 16 | 16 |
See the [cgroups freezer documentation] |
| 17 |
-(https://www.kernel.org/doc/Documentation/cgroups/freezer-subsystem.txt) for |
|
| 17 |
+(https://www.kernel.org/doc/Documentation/cgroup-v1/freezer-subsystem.txt) for |
|
| 18 | 18 |
further details. |
| 19 | 19 |
|
| 20 | 20 |
# OPTIONS |
| ... | ... |
@@ -59,4 +59,4 @@ To view all available fields, you can use the format `{{json .}}`.
|
| 59 | 59 |
# HISTORY |
| 60 | 60 |
June 2014, updated by Sven Dowideit <SvenDowideit@home.org.au> |
| 61 | 61 |
June 2015, updated by John Howard <jhoward@microsoft.com> |
| 62 |
-June 2015, updated by Patrick Hemmer <patrick.hemmer@gmail.com |
|
| 62 |
+June 2015, updated by Patrick Hemmer <patrick.hemmer@gmail.com> |
| 63 | 63 |
deleted file mode 100644 |
| ... | ... |
@@ -1,15 +0,0 @@ |
| 1 |
-// +build cgo |
|
| 2 |
- |
|
| 3 |
-package graphdb |
|
| 4 |
- |
|
| 5 |
-import "database/sql" |
|
| 6 |
- |
|
| 7 |
-// NewSqliteConn opens a connection to a sqlite |
|
| 8 |
-// database. |
|
| 9 |
-func NewSqliteConn(root string) (*Database, error) {
|
|
| 10 |
- conn, err := sql.Open("sqlite3", root)
|
|
| 11 |
- if err != nil {
|
|
| 12 |
- return nil, err |
|
| 13 |
- } |
|
| 14 |
- return NewDatabase(conn) |
|
| 15 |
-} |
| 16 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,19 @@ |
| 0 |
+// +build cgo |
|
| 1 |
+ |
|
| 2 |
+package graphdb |
|
| 3 |
+ |
|
| 4 |
+import ( |
|
| 5 |
+ "database/sql" |
|
| 6 |
+ |
|
| 7 |
+ _ "github.com/mattn/go-sqlite3" // registers sqlite |
|
| 8 |
+) |
|
| 9 |
+ |
|
| 10 |
+// NewSqliteConn opens a connection to a sqlite |
|
| 11 |
+// database. |
|
| 12 |
+func NewSqliteConn(root string) (*Database, error) {
|
|
| 13 |
+ conn, err := sql.Open("sqlite3", root)
|
|
| 14 |
+ if err != nil {
|
|
| 15 |
+ return nil, err |
|
| 16 |
+ } |
|
| 17 |
+ return NewDatabase(conn) |
|
| 18 |
+} |
| 9 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,551 +0,0 @@ |
| 1 |
-package graphdb |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "database/sql" |
|
| 5 |
- "fmt" |
|
| 6 |
- "path" |
|
| 7 |
- "strings" |
|
| 8 |
- "sync" |
|
| 9 |
-) |
|
| 10 |
- |
|
| 11 |
-const ( |
|
| 12 |
- createEntityTable = ` |
|
| 13 |
- CREATE TABLE IF NOT EXISTS entity ( |
|
| 14 |
- id text NOT NULL PRIMARY KEY |
|
| 15 |
- );` |
|
| 16 |
- |
|
| 17 |
- createEdgeTable = ` |
|
| 18 |
- CREATE TABLE IF NOT EXISTS edge ( |
|
| 19 |
- "entity_id" text NOT NULL, |
|
| 20 |
- "parent_id" text NULL, |
|
| 21 |
- "name" text NOT NULL, |
|
| 22 |
- CONSTRAINT "parent_fk" FOREIGN KEY ("parent_id") REFERENCES "entity" ("id"),
|
|
| 23 |
- CONSTRAINT "entity_fk" FOREIGN KEY ("entity_id") REFERENCES "entity" ("id")
|
|
| 24 |
- ); |
|
| 25 |
- ` |
|
| 26 |
- |
|
| 27 |
- createEdgeIndices = ` |
|
| 28 |
- CREATE UNIQUE INDEX IF NOT EXISTS "name_parent_ix" ON "edge" (parent_id, name); |
|
| 29 |
- ` |
|
| 30 |
-) |
|
| 31 |
- |
|
| 32 |
-// Entity with a unique id. |
|
| 33 |
-type Entity struct {
|
|
| 34 |
- id string |
|
| 35 |
-} |
|
| 36 |
- |
|
| 37 |
-// An Edge connects two entities together. |
|
| 38 |
-type Edge struct {
|
|
| 39 |
- EntityID string |
|
| 40 |
- Name string |
|
| 41 |
- ParentID string |
|
| 42 |
-} |
|
| 43 |
- |
|
| 44 |
-// Entities stores the list of entities. |
|
| 45 |
-type Entities map[string]*Entity |
|
| 46 |
- |
|
| 47 |
-// Edges stores the relationships between entities. |
|
| 48 |
-type Edges []*Edge |
|
| 49 |
- |
|
| 50 |
-// WalkFunc is a function invoked to process an individual entity. |
|
| 51 |
-type WalkFunc func(fullPath string, entity *Entity) error |
|
| 52 |
- |
|
| 53 |
-// Database is a graph database for storing entities and their relationships. |
|
| 54 |
-type Database struct {
|
|
| 55 |
- conn *sql.DB |
|
| 56 |
- mux sync.RWMutex |
|
| 57 |
-} |
|
| 58 |
- |
|
| 59 |
-// IsNonUniqueNameError processes the error to check if it's caused by |
|
| 60 |
-// a constraint violation. |
|
| 61 |
-// This is necessary because the error isn't the same across various |
|
| 62 |
-// sqlite versions. |
|
| 63 |
-func IsNonUniqueNameError(err error) bool {
|
|
| 64 |
- str := err.Error() |
|
| 65 |
- // sqlite 3.7.17-1ubuntu1 returns: |
|
| 66 |
- // Set failure: Abort due to constraint violation: columns parent_id, name are not unique |
|
| 67 |
- if strings.HasSuffix(str, "name are not unique") {
|
|
| 68 |
- return true |
|
| 69 |
- } |
|
| 70 |
- // sqlite-3.8.3-1.fc20 returns: |
|
| 71 |
- // Set failure: Abort due to constraint violation: UNIQUE constraint failed: edge.parent_id, edge.name |
|
| 72 |
- if strings.Contains(str, "UNIQUE constraint failed") && strings.Contains(str, "edge.name") {
|
|
| 73 |
- return true |
|
| 74 |
- } |
|
| 75 |
- // sqlite-3.6.20-1.el6 returns: |
|
| 76 |
- // Set failure: Abort due to constraint violation: constraint failed |
|
| 77 |
- if strings.HasSuffix(str, "constraint failed") {
|
|
| 78 |
- return true |
|
| 79 |
- } |
|
| 80 |
- return false |
|
| 81 |
-} |
|
| 82 |
- |
|
| 83 |
-// NewDatabase creates a new graph database initialized with a root entity. |
|
| 84 |
-func NewDatabase(conn *sql.DB) (*Database, error) {
|
|
| 85 |
- if conn == nil {
|
|
| 86 |
- return nil, fmt.Errorf("Database connection cannot be nil")
|
|
| 87 |
- } |
|
| 88 |
- db := &Database{conn: conn}
|
|
| 89 |
- |
|
| 90 |
- // Create root entities |
|
| 91 |
- tx, err := conn.Begin() |
|
| 92 |
- if err != nil {
|
|
| 93 |
- return nil, err |
|
| 94 |
- } |
|
| 95 |
- |
|
| 96 |
- if _, err := tx.Exec(createEntityTable); err != nil {
|
|
| 97 |
- return nil, err |
|
| 98 |
- } |
|
| 99 |
- if _, err := tx.Exec(createEdgeTable); err != nil {
|
|
| 100 |
- return nil, err |
|
| 101 |
- } |
|
| 102 |
- if _, err := tx.Exec(createEdgeIndices); err != nil {
|
|
| 103 |
- return nil, err |
|
| 104 |
- } |
|
| 105 |
- |
|
| 106 |
- if _, err := tx.Exec("DELETE FROM entity where id = ?", "0"); err != nil {
|
|
| 107 |
- tx.Rollback() |
|
| 108 |
- return nil, err |
|
| 109 |
- } |
|
| 110 |
- |
|
| 111 |
- if _, err := tx.Exec("INSERT INTO entity (id) VALUES (?);", "0"); err != nil {
|
|
| 112 |
- tx.Rollback() |
|
| 113 |
- return nil, err |
|
| 114 |
- } |
|
| 115 |
- |
|
| 116 |
- if _, err := tx.Exec("DELETE FROM edge where entity_id=? and name=?", "0", "/"); err != nil {
|
|
| 117 |
- tx.Rollback() |
|
| 118 |
- return nil, err |
|
| 119 |
- } |
|
| 120 |
- |
|
| 121 |
- if _, err := tx.Exec("INSERT INTO edge (entity_id, name) VALUES(?,?);", "0", "/"); err != nil {
|
|
| 122 |
- tx.Rollback() |
|
| 123 |
- return nil, err |
|
| 124 |
- } |
|
| 125 |
- |
|
| 126 |
- if err := tx.Commit(); err != nil {
|
|
| 127 |
- return nil, err |
|
| 128 |
- } |
|
| 129 |
- |
|
| 130 |
- return db, nil |
|
| 131 |
-} |
|
| 132 |
- |
|
| 133 |
-// Close the underlying connection to the database. |
|
| 134 |
-func (db *Database) Close() error {
|
|
| 135 |
- return db.conn.Close() |
|
| 136 |
-} |
|
| 137 |
- |
|
| 138 |
-// Set the entity id for a given path. |
|
| 139 |
-func (db *Database) Set(fullPath, id string) (*Entity, error) {
|
|
| 140 |
- db.mux.Lock() |
|
| 141 |
- defer db.mux.Unlock() |
|
| 142 |
- |
|
| 143 |
- tx, err := db.conn.Begin() |
|
| 144 |
- if err != nil {
|
|
| 145 |
- return nil, err |
|
| 146 |
- } |
|
| 147 |
- |
|
| 148 |
- var entityID string |
|
| 149 |
- if err := tx.QueryRow("SELECT id FROM entity WHERE id = ?;", id).Scan(&entityID); err != nil {
|
|
| 150 |
- if err == sql.ErrNoRows {
|
|
| 151 |
- if _, err := tx.Exec("INSERT INTO entity (id) VALUES(?);", id); err != nil {
|
|
| 152 |
- tx.Rollback() |
|
| 153 |
- return nil, err |
|
| 154 |
- } |
|
| 155 |
- } else {
|
|
| 156 |
- tx.Rollback() |
|
| 157 |
- return nil, err |
|
| 158 |
- } |
|
| 159 |
- } |
|
| 160 |
- e := &Entity{id}
|
|
| 161 |
- |
|
| 162 |
- parentPath, name := splitPath(fullPath) |
|
| 163 |
- if err := db.setEdge(parentPath, name, e, tx); err != nil {
|
|
| 164 |
- tx.Rollback() |
|
| 165 |
- return nil, err |
|
| 166 |
- } |
|
| 167 |
- |
|
| 168 |
- if err := tx.Commit(); err != nil {
|
|
| 169 |
- return nil, err |
|
| 170 |
- } |
|
| 171 |
- return e, nil |
|
| 172 |
-} |
|
| 173 |
- |
|
| 174 |
-// Exists returns true if a name already exists in the database. |
|
| 175 |
-func (db *Database) Exists(name string) bool {
|
|
| 176 |
- db.mux.RLock() |
|
| 177 |
- defer db.mux.RUnlock() |
|
| 178 |
- |
|
| 179 |
- e, err := db.get(name) |
|
| 180 |
- if err != nil {
|
|
| 181 |
- return false |
|
| 182 |
- } |
|
| 183 |
- return e != nil |
|
| 184 |
-} |
|
| 185 |
- |
|
| 186 |
-func (db *Database) setEdge(parentPath, name string, e *Entity, tx *sql.Tx) error {
|
|
| 187 |
- parent, err := db.get(parentPath) |
|
| 188 |
- if err != nil {
|
|
| 189 |
- return err |
|
| 190 |
- } |
|
| 191 |
- if parent.id == e.id {
|
|
| 192 |
- return fmt.Errorf("Cannot set self as child")
|
|
| 193 |
- } |
|
| 194 |
- |
|
| 195 |
- if _, err := tx.Exec("INSERT INTO edge (parent_id, name, entity_id) VALUES (?,?,?);", parent.id, name, e.id); err != nil {
|
|
| 196 |
- return err |
|
| 197 |
- } |
|
| 198 |
- return nil |
|
| 199 |
-} |
|
| 200 |
- |
|
| 201 |
-// RootEntity returns the root "/" entity for the database. |
|
| 202 |
-func (db *Database) RootEntity() *Entity {
|
|
| 203 |
- return &Entity{
|
|
| 204 |
- id: "0", |
|
| 205 |
- } |
|
| 206 |
-} |
|
| 207 |
- |
|
| 208 |
-// Get returns the entity for a given path. |
|
| 209 |
-func (db *Database) Get(name string) *Entity {
|
|
| 210 |
- db.mux.RLock() |
|
| 211 |
- defer db.mux.RUnlock() |
|
| 212 |
- |
|
| 213 |
- e, err := db.get(name) |
|
| 214 |
- if err != nil {
|
|
| 215 |
- return nil |
|
| 216 |
- } |
|
| 217 |
- return e |
|
| 218 |
-} |
|
| 219 |
- |
|
| 220 |
-func (db *Database) get(name string) (*Entity, error) {
|
|
| 221 |
- e := db.RootEntity() |
|
| 222 |
- // We always know the root name so return it if |
|
| 223 |
- // it is requested |
|
| 224 |
- if name == "/" {
|
|
| 225 |
- return e, nil |
|
| 226 |
- } |
|
| 227 |
- |
|
| 228 |
- parts := split(name) |
|
| 229 |
- for i := 1; i < len(parts); i++ {
|
|
| 230 |
- p := parts[i] |
|
| 231 |
- if p == "" {
|
|
| 232 |
- continue |
|
| 233 |
- } |
|
| 234 |
- |
|
| 235 |
- next := db.child(e, p) |
|
| 236 |
- if next == nil {
|
|
| 237 |
- return nil, fmt.Errorf("Cannot find child for %s", name)
|
|
| 238 |
- } |
|
| 239 |
- e = next |
|
| 240 |
- } |
|
| 241 |
- return e, nil |
|
| 242 |
- |
|
| 243 |
-} |
|
| 244 |
- |
|
| 245 |
-// List all entities by from the name. |
|
| 246 |
-// The key will be the full path of the entity. |
|
| 247 |
-func (db *Database) List(name string, depth int) Entities {
|
|
| 248 |
- db.mux.RLock() |
|
| 249 |
- defer db.mux.RUnlock() |
|
| 250 |
- |
|
| 251 |
- out := Entities{}
|
|
| 252 |
- e, err := db.get(name) |
|
| 253 |
- if err != nil {
|
|
| 254 |
- return out |
|
| 255 |
- } |
|
| 256 |
- |
|
| 257 |
- children, err := db.children(e, name, depth, nil) |
|
| 258 |
- if err != nil {
|
|
| 259 |
- return out |
|
| 260 |
- } |
|
| 261 |
- |
|
| 262 |
- for _, c := range children {
|
|
| 263 |
- out[c.FullPath] = c.Entity |
|
| 264 |
- } |
|
| 265 |
- return out |
|
| 266 |
-} |
|
| 267 |
- |
|
| 268 |
-// Walk through the child graph of an entity, calling walkFunc for each child entity. |
|
| 269 |
-// It is safe for walkFunc to call graph functions. |
|
| 270 |
-func (db *Database) Walk(name string, walkFunc WalkFunc, depth int) error {
|
|
| 271 |
- children, err := db.Children(name, depth) |
|
| 272 |
- if err != nil {
|
|
| 273 |
- return err |
|
| 274 |
- } |
|
| 275 |
- |
|
| 276 |
- // Note: the database lock must not be held while calling walkFunc |
|
| 277 |
- for _, c := range children {
|
|
| 278 |
- if err := walkFunc(c.FullPath, c.Entity); err != nil {
|
|
| 279 |
- return err |
|
| 280 |
- } |
|
| 281 |
- } |
|
| 282 |
- return nil |
|
| 283 |
-} |
|
| 284 |
- |
|
| 285 |
-// Children returns the children of the specified entity. |
|
| 286 |
-func (db *Database) Children(name string, depth int) ([]WalkMeta, error) {
|
|
| 287 |
- db.mux.RLock() |
|
| 288 |
- defer db.mux.RUnlock() |
|
| 289 |
- |
|
| 290 |
- e, err := db.get(name) |
|
| 291 |
- if err != nil {
|
|
| 292 |
- return nil, err |
|
| 293 |
- } |
|
| 294 |
- |
|
| 295 |
- return db.children(e, name, depth, nil) |
|
| 296 |
-} |
|
| 297 |
- |
|
| 298 |
-// Parents returns the parents of a specified entity. |
|
| 299 |
-func (db *Database) Parents(name string) ([]string, error) {
|
|
| 300 |
- db.mux.RLock() |
|
| 301 |
- defer db.mux.RUnlock() |
|
| 302 |
- |
|
| 303 |
- e, err := db.get(name) |
|
| 304 |
- if err != nil {
|
|
| 305 |
- return nil, err |
|
| 306 |
- } |
|
| 307 |
- return db.parents(e) |
|
| 308 |
-} |
|
| 309 |
- |
|
| 310 |
-// Refs returns the reference count for a specified id. |
|
| 311 |
-func (db *Database) Refs(id string) int {
|
|
| 312 |
- db.mux.RLock() |
|
| 313 |
- defer db.mux.RUnlock() |
|
| 314 |
- |
|
| 315 |
- var count int |
|
| 316 |
- if err := db.conn.QueryRow("SELECT COUNT(*) FROM edge WHERE entity_id = ?;", id).Scan(&count); err != nil {
|
|
| 317 |
- return 0 |
|
| 318 |
- } |
|
| 319 |
- return count |
|
| 320 |
-} |
|
| 321 |
- |
|
| 322 |
-// RefPaths returns all the id's path references. |
|
| 323 |
-func (db *Database) RefPaths(id string) Edges {
|
|
| 324 |
- db.mux.RLock() |
|
| 325 |
- defer db.mux.RUnlock() |
|
| 326 |
- |
|
| 327 |
- refs := Edges{}
|
|
| 328 |
- |
|
| 329 |
- rows, err := db.conn.Query("SELECT name, parent_id FROM edge WHERE entity_id = ?;", id)
|
|
| 330 |
- if err != nil {
|
|
| 331 |
- return refs |
|
| 332 |
- } |
|
| 333 |
- defer rows.Close() |
|
| 334 |
- |
|
| 335 |
- for rows.Next() {
|
|
| 336 |
- var name string |
|
| 337 |
- var parentID string |
|
| 338 |
- if err := rows.Scan(&name, &parentID); err != nil {
|
|
| 339 |
- return refs |
|
| 340 |
- } |
|
| 341 |
- refs = append(refs, &Edge{
|
|
| 342 |
- EntityID: id, |
|
| 343 |
- Name: name, |
|
| 344 |
- ParentID: parentID, |
|
| 345 |
- }) |
|
| 346 |
- } |
|
| 347 |
- return refs |
|
| 348 |
-} |
|
| 349 |
- |
|
| 350 |
-// Delete the reference to an entity at a given path. |
|
| 351 |
-func (db *Database) Delete(name string) error {
|
|
| 352 |
- db.mux.Lock() |
|
| 353 |
- defer db.mux.Unlock() |
|
| 354 |
- |
|
| 355 |
- if name == "/" {
|
|
| 356 |
- return fmt.Errorf("Cannot delete root entity")
|
|
| 357 |
- } |
|
| 358 |
- |
|
| 359 |
- parentPath, n := splitPath(name) |
|
| 360 |
- parent, err := db.get(parentPath) |
|
| 361 |
- if err != nil {
|
|
| 362 |
- return err |
|
| 363 |
- } |
|
| 364 |
- |
|
| 365 |
- if _, err := db.conn.Exec("DELETE FROM edge WHERE parent_id = ? AND name = ?;", parent.id, n); err != nil {
|
|
| 366 |
- return err |
|
| 367 |
- } |
|
| 368 |
- return nil |
|
| 369 |
-} |
|
| 370 |
- |
|
| 371 |
-// Purge removes the entity with the specified id |
|
| 372 |
-// Walk the graph to make sure all references to the entity |
|
| 373 |
-// are removed and return the number of references removed |
|
| 374 |
-func (db *Database) Purge(id string) (int, error) {
|
|
| 375 |
- db.mux.Lock() |
|
| 376 |
- defer db.mux.Unlock() |
|
| 377 |
- |
|
| 378 |
- tx, err := db.conn.Begin() |
|
| 379 |
- if err != nil {
|
|
| 380 |
- return -1, err |
|
| 381 |
- } |
|
| 382 |
- |
|
| 383 |
- // Delete all edges |
|
| 384 |
- rows, err := tx.Exec("DELETE FROM edge WHERE entity_id = ?;", id)
|
|
| 385 |
- if err != nil {
|
|
| 386 |
- tx.Rollback() |
|
| 387 |
- return -1, err |
|
| 388 |
- } |
|
| 389 |
- changes, err := rows.RowsAffected() |
|
| 390 |
- if err != nil {
|
|
| 391 |
- return -1, err |
|
| 392 |
- } |
|
| 393 |
- |
|
| 394 |
- // Clear who's using this id as parent |
|
| 395 |
- refs, err := tx.Exec("DELETE FROM edge WHERE parent_id = ?;", id)
|
|
| 396 |
- if err != nil {
|
|
| 397 |
- tx.Rollback() |
|
| 398 |
- return -1, err |
|
| 399 |
- } |
|
| 400 |
- refsCount, err := refs.RowsAffected() |
|
| 401 |
- if err != nil {
|
|
| 402 |
- return -1, err |
|
| 403 |
- } |
|
| 404 |
- |
|
| 405 |
- // Delete entity |
|
| 406 |
- if _, err := tx.Exec("DELETE FROM entity where id = ?;", id); err != nil {
|
|
| 407 |
- tx.Rollback() |
|
| 408 |
- return -1, err |
|
| 409 |
- } |
|
| 410 |
- |
|
| 411 |
- if err := tx.Commit(); err != nil {
|
|
| 412 |
- return -1, err |
|
| 413 |
- } |
|
| 414 |
- |
|
| 415 |
- return int(changes + refsCount), nil |
|
| 416 |
-} |
|
| 417 |
- |
|
| 418 |
-// Rename an edge for a given path |
|
| 419 |
-func (db *Database) Rename(currentName, newName string) error {
|
|
| 420 |
- db.mux.Lock() |
|
| 421 |
- defer db.mux.Unlock() |
|
| 422 |
- |
|
| 423 |
- parentPath, name := splitPath(currentName) |
|
| 424 |
- newParentPath, newEdgeName := splitPath(newName) |
|
| 425 |
- |
|
| 426 |
- if parentPath != newParentPath {
|
|
| 427 |
- return fmt.Errorf("Cannot rename when root paths do not match %s != %s", parentPath, newParentPath)
|
|
| 428 |
- } |
|
| 429 |
- |
|
| 430 |
- parent, err := db.get(parentPath) |
|
| 431 |
- if err != nil {
|
|
| 432 |
- return err |
|
| 433 |
- } |
|
| 434 |
- |
|
| 435 |
- rows, err := db.conn.Exec("UPDATE edge SET name = ? WHERE parent_id = ? AND name = ?;", newEdgeName, parent.id, name)
|
|
| 436 |
- if err != nil {
|
|
| 437 |
- return err |
|
| 438 |
- } |
|
| 439 |
- i, err := rows.RowsAffected() |
|
| 440 |
- if err != nil {
|
|
| 441 |
- return err |
|
| 442 |
- } |
|
| 443 |
- if i == 0 {
|
|
| 444 |
- return fmt.Errorf("Cannot locate edge for %s %s", parent.id, name)
|
|
| 445 |
- } |
|
| 446 |
- return nil |
|
| 447 |
-} |
|
| 448 |
- |
|
| 449 |
-// WalkMeta stores the walk metadata. |
|
| 450 |
-type WalkMeta struct {
|
|
| 451 |
- Parent *Entity |
|
| 452 |
- Entity *Entity |
|
| 453 |
- FullPath string |
|
| 454 |
- Edge *Edge |
|
| 455 |
-} |
|
| 456 |
- |
|
| 457 |
-func (db *Database) children(e *Entity, name string, depth int, entities []WalkMeta) ([]WalkMeta, error) {
|
|
| 458 |
- if e == nil {
|
|
| 459 |
- return entities, nil |
|
| 460 |
- } |
|
| 461 |
- |
|
| 462 |
- rows, err := db.conn.Query("SELECT entity_id, name FROM edge where parent_id = ?;", e.id)
|
|
| 463 |
- if err != nil {
|
|
| 464 |
- return nil, err |
|
| 465 |
- } |
|
| 466 |
- defer rows.Close() |
|
| 467 |
- |
|
| 468 |
- for rows.Next() {
|
|
| 469 |
- var entityID, entityName string |
|
| 470 |
- if err := rows.Scan(&entityID, &entityName); err != nil {
|
|
| 471 |
- return nil, err |
|
| 472 |
- } |
|
| 473 |
- child := &Entity{entityID}
|
|
| 474 |
- edge := &Edge{
|
|
| 475 |
- ParentID: e.id, |
|
| 476 |
- Name: entityName, |
|
| 477 |
- EntityID: child.id, |
|
| 478 |
- } |
|
| 479 |
- |
|
| 480 |
- meta := WalkMeta{
|
|
| 481 |
- Parent: e, |
|
| 482 |
- Entity: child, |
|
| 483 |
- FullPath: path.Join(name, edge.Name), |
|
| 484 |
- Edge: edge, |
|
| 485 |
- } |
|
| 486 |
- |
|
| 487 |
- entities = append(entities, meta) |
|
| 488 |
- |
|
| 489 |
- if depth != 0 {
|
|
| 490 |
- nDepth := depth |
|
| 491 |
- if depth != -1 {
|
|
| 492 |
- nDepth-- |
|
| 493 |
- } |
|
| 494 |
- entities, err = db.children(child, meta.FullPath, nDepth, entities) |
|
| 495 |
- if err != nil {
|
|
| 496 |
- return nil, err |
|
| 497 |
- } |
|
| 498 |
- } |
|
| 499 |
- } |
|
| 500 |
- |
|
| 501 |
- return entities, nil |
|
| 502 |
-} |
|
| 503 |
- |
|
| 504 |
-func (db *Database) parents(e *Entity) (parents []string, err error) {
|
|
| 505 |
- if e == nil {
|
|
| 506 |
- return parents, nil |
|
| 507 |
- } |
|
| 508 |
- |
|
| 509 |
- rows, err := db.conn.Query("SELECT parent_id FROM edge where entity_id = ?;", e.id)
|
|
| 510 |
- if err != nil {
|
|
| 511 |
- return nil, err |
|
| 512 |
- } |
|
| 513 |
- defer rows.Close() |
|
| 514 |
- |
|
| 515 |
- for rows.Next() {
|
|
| 516 |
- var parentID string |
|
| 517 |
- if err := rows.Scan(&parentID); err != nil {
|
|
| 518 |
- return nil, err |
|
| 519 |
- } |
|
| 520 |
- parents = append(parents, parentID) |
|
| 521 |
- } |
|
| 522 |
- |
|
| 523 |
- return parents, nil |
|
| 524 |
-} |
|
| 525 |
- |
|
| 526 |
-// Return the entity based on the parent path and name. |
|
| 527 |
-func (db *Database) child(parent *Entity, name string) *Entity {
|
|
| 528 |
- var id string |
|
| 529 |
- if err := db.conn.QueryRow("SELECT entity_id FROM edge WHERE parent_id = ? AND name = ?;", parent.id, name).Scan(&id); err != nil {
|
|
| 530 |
- return nil |
|
| 531 |
- } |
|
| 532 |
- return &Entity{id}
|
|
| 533 |
-} |
|
| 534 |
- |
|
| 535 |
-// ID returns the id used to reference this entity. |
|
| 536 |
-func (e *Entity) ID() string {
|
|
| 537 |
- return e.id |
|
| 538 |
-} |
|
| 539 |
- |
|
| 540 |
-// Paths returns the paths sorted by depth. |
|
| 541 |
-func (e Entities) Paths() []string {
|
|
| 542 |
- out := make([]string, len(e)) |
|
| 543 |
- var i int |
|
| 544 |
- for k := range e {
|
|
| 545 |
- out[i] = k |
|
| 546 |
- i++ |
|
| 547 |
- } |
|
| 548 |
- sortByDepth(out) |
|
| 549 |
- |
|
| 550 |
- return out |
|
| 551 |
-} |
| 552 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,551 @@ |
| 0 |
+package graphdb |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "database/sql" |
|
| 4 |
+ "fmt" |
|
| 5 |
+ "path" |
|
| 6 |
+ "strings" |
|
| 7 |
+ "sync" |
|
| 8 |
+) |
|
| 9 |
+ |
|
| 10 |
+const ( |
|
| 11 |
+ createEntityTable = ` |
|
| 12 |
+ CREATE TABLE IF NOT EXISTS entity ( |
|
| 13 |
+ id text NOT NULL PRIMARY KEY |
|
| 14 |
+ );` |
|
| 15 |
+ |
|
| 16 |
+ createEdgeTable = ` |
|
| 17 |
+ CREATE TABLE IF NOT EXISTS edge ( |
|
| 18 |
+ "entity_id" text NOT NULL, |
|
| 19 |
+ "parent_id" text NULL, |
|
| 20 |
+ "name" text NOT NULL, |
|
| 21 |
+ CONSTRAINT "parent_fk" FOREIGN KEY ("parent_id") REFERENCES "entity" ("id"),
|
|
| 22 |
+ CONSTRAINT "entity_fk" FOREIGN KEY ("entity_id") REFERENCES "entity" ("id")
|
|
| 23 |
+ ); |
|
| 24 |
+ ` |
|
| 25 |
+ |
|
| 26 |
+ createEdgeIndices = ` |
|
| 27 |
+ CREATE UNIQUE INDEX IF NOT EXISTS "name_parent_ix" ON "edge" (parent_id, name); |
|
| 28 |
+ ` |
|
| 29 |
+) |
|
| 30 |
+ |
|
| 31 |
+// Entity with a unique id. |
|
| 32 |
+type Entity struct {
|
|
| 33 |
+ id string |
|
| 34 |
+} |
|
| 35 |
+ |
|
| 36 |
+// An Edge connects two entities together. |
|
| 37 |
+type Edge struct {
|
|
| 38 |
+ EntityID string |
|
| 39 |
+ Name string |
|
| 40 |
+ ParentID string |
|
| 41 |
+} |
|
| 42 |
+ |
|
| 43 |
+// Entities stores the list of entities. |
|
| 44 |
+type Entities map[string]*Entity |
|
| 45 |
+ |
|
| 46 |
+// Edges stores the relationships between entities. |
|
| 47 |
+type Edges []*Edge |
|
| 48 |
+ |
|
| 49 |
+// WalkFunc is a function invoked to process an individual entity. |
|
| 50 |
+type WalkFunc func(fullPath string, entity *Entity) error |
|
| 51 |
+ |
|
| 52 |
+// Database is a graph database for storing entities and their relationships. |
|
| 53 |
+type Database struct {
|
|
| 54 |
+ conn *sql.DB |
|
| 55 |
+ mux sync.RWMutex |
|
| 56 |
+} |
|
| 57 |
+ |
|
| 58 |
+// IsNonUniqueNameError processes the error to check if it's caused by |
|
| 59 |
+// a constraint violation. |
|
| 60 |
+// This is necessary because the error isn't the same across various |
|
| 61 |
+// sqlite versions. |
|
| 62 |
+func IsNonUniqueNameError(err error) bool {
|
|
| 63 |
+ str := err.Error() |
|
| 64 |
+ // sqlite 3.7.17-1ubuntu1 returns: |
|
| 65 |
+ // Set failure: Abort due to constraint violation: columns parent_id, name are not unique |
|
| 66 |
+ if strings.HasSuffix(str, "name are not unique") {
|
|
| 67 |
+ return true |
|
| 68 |
+ } |
|
| 69 |
+ // sqlite-3.8.3-1.fc20 returns: |
|
| 70 |
+ // Set failure: Abort due to constraint violation: UNIQUE constraint failed: edge.parent_id, edge.name |
|
| 71 |
+ if strings.Contains(str, "UNIQUE constraint failed") && strings.Contains(str, "edge.name") {
|
|
| 72 |
+ return true |
|
| 73 |
+ } |
|
| 74 |
+ // sqlite-3.6.20-1.el6 returns: |
|
| 75 |
+ // Set failure: Abort due to constraint violation: constraint failed |
|
| 76 |
+ if strings.HasSuffix(str, "constraint failed") {
|
|
| 77 |
+ return true |
|
| 78 |
+ } |
|
| 79 |
+ return false |
|
| 80 |
+} |
|
| 81 |
+ |
|
| 82 |
+// NewDatabase creates a new graph database initialized with a root entity. |
|
| 83 |
+func NewDatabase(conn *sql.DB) (*Database, error) {
|
|
| 84 |
+ if conn == nil {
|
|
| 85 |
+ return nil, fmt.Errorf("Database connection cannot be nil")
|
|
| 86 |
+ } |
|
| 87 |
+ db := &Database{conn: conn}
|
|
| 88 |
+ |
|
| 89 |
+ // Create root entities |
|
| 90 |
+ tx, err := conn.Begin() |
|
| 91 |
+ if err != nil {
|
|
| 92 |
+ return nil, err |
|
| 93 |
+ } |
|
| 94 |
+ |
|
| 95 |
+ if _, err := tx.Exec(createEntityTable); err != nil {
|
|
| 96 |
+ return nil, err |
|
| 97 |
+ } |
|
| 98 |
+ if _, err := tx.Exec(createEdgeTable); err != nil {
|
|
| 99 |
+ return nil, err |
|
| 100 |
+ } |
|
| 101 |
+ if _, err := tx.Exec(createEdgeIndices); err != nil {
|
|
| 102 |
+ return nil, err |
|
| 103 |
+ } |
|
| 104 |
+ |
|
| 105 |
+ if _, err := tx.Exec("DELETE FROM entity where id = ?", "0"); err != nil {
|
|
| 106 |
+ tx.Rollback() |
|
| 107 |
+ return nil, err |
|
| 108 |
+ } |
|
| 109 |
+ |
|
| 110 |
+ if _, err := tx.Exec("INSERT INTO entity (id) VALUES (?);", "0"); err != nil {
|
|
| 111 |
+ tx.Rollback() |
|
| 112 |
+ return nil, err |
|
| 113 |
+ } |
|
| 114 |
+ |
|
| 115 |
+ if _, err := tx.Exec("DELETE FROM edge where entity_id=? and name=?", "0", "/"); err != nil {
|
|
| 116 |
+ tx.Rollback() |
|
| 117 |
+ return nil, err |
|
| 118 |
+ } |
|
| 119 |
+ |
|
| 120 |
+ if _, err := tx.Exec("INSERT INTO edge (entity_id, name) VALUES(?,?);", "0", "/"); err != nil {
|
|
| 121 |
+ tx.Rollback() |
|
| 122 |
+ return nil, err |
|
| 123 |
+ } |
|
| 124 |
+ |
|
| 125 |
+ if err := tx.Commit(); err != nil {
|
|
| 126 |
+ return nil, err |
|
| 127 |
+ } |
|
| 128 |
+ |
|
| 129 |
+ return db, nil |
|
| 130 |
+} |
|
| 131 |
+ |
|
| 132 |
+// Close the underlying connection to the database. |
|
| 133 |
+func (db *Database) Close() error {
|
|
| 134 |
+ return db.conn.Close() |
|
| 135 |
+} |
|
| 136 |
+ |
|
| 137 |
+// Set the entity id for a given path. |
|
| 138 |
+func (db *Database) Set(fullPath, id string) (*Entity, error) {
|
|
| 139 |
+ db.mux.Lock() |
|
| 140 |
+ defer db.mux.Unlock() |
|
| 141 |
+ |
|
| 142 |
+ tx, err := db.conn.Begin() |
|
| 143 |
+ if err != nil {
|
|
| 144 |
+ return nil, err |
|
| 145 |
+ } |
|
| 146 |
+ |
|
| 147 |
+ var entityID string |
|
| 148 |
+ if err := tx.QueryRow("SELECT id FROM entity WHERE id = ?;", id).Scan(&entityID); err != nil {
|
|
| 149 |
+ if err == sql.ErrNoRows {
|
|
| 150 |
+ if _, err := tx.Exec("INSERT INTO entity (id) VALUES(?);", id); err != nil {
|
|
| 151 |
+ tx.Rollback() |
|
| 152 |
+ return nil, err |
|
| 153 |
+ } |
|
| 154 |
+ } else {
|
|
| 155 |
+ tx.Rollback() |
|
| 156 |
+ return nil, err |
|
| 157 |
+ } |
|
| 158 |
+ } |
|
| 159 |
+ e := &Entity{id}
|
|
| 160 |
+ |
|
| 161 |
+ parentPath, name := splitPath(fullPath) |
|
| 162 |
+ if err := db.setEdge(parentPath, name, e, tx); err != nil {
|
|
| 163 |
+ tx.Rollback() |
|
| 164 |
+ return nil, err |
|
| 165 |
+ } |
|
| 166 |
+ |
|
| 167 |
+ if err := tx.Commit(); err != nil {
|
|
| 168 |
+ return nil, err |
|
| 169 |
+ } |
|
| 170 |
+ return e, nil |
|
| 171 |
+} |
|
| 172 |
+ |
|
| 173 |
+// Exists returns true if a name already exists in the database. |
|
| 174 |
+func (db *Database) Exists(name string) bool {
|
|
| 175 |
+ db.mux.RLock() |
|
| 176 |
+ defer db.mux.RUnlock() |
|
| 177 |
+ |
|
| 178 |
+ e, err := db.get(name) |
|
| 179 |
+ if err != nil {
|
|
| 180 |
+ return false |
|
| 181 |
+ } |
|
| 182 |
+ return e != nil |
|
| 183 |
+} |
|
| 184 |
+ |
|
| 185 |
+func (db *Database) setEdge(parentPath, name string, e *Entity, tx *sql.Tx) error {
|
|
| 186 |
+ parent, err := db.get(parentPath) |
|
| 187 |
+ if err != nil {
|
|
| 188 |
+ return err |
|
| 189 |
+ } |
|
| 190 |
+ if parent.id == e.id {
|
|
| 191 |
+ return fmt.Errorf("Cannot set self as child")
|
|
| 192 |
+ } |
|
| 193 |
+ |
|
| 194 |
+ if _, err := tx.Exec("INSERT INTO edge (parent_id, name, entity_id) VALUES (?,?,?);", parent.id, name, e.id); err != nil {
|
|
| 195 |
+ return err |
|
| 196 |
+ } |
|
| 197 |
+ return nil |
|
| 198 |
+} |
|
| 199 |
+ |
|
| 200 |
+// RootEntity returns the root "/" entity for the database. |
|
| 201 |
+func (db *Database) RootEntity() *Entity {
|
|
| 202 |
+ return &Entity{
|
|
| 203 |
+ id: "0", |
|
| 204 |
+ } |
|
| 205 |
+} |
|
| 206 |
+ |
|
| 207 |
+// Get returns the entity for a given path. |
|
| 208 |
+func (db *Database) Get(name string) *Entity {
|
|
| 209 |
+ db.mux.RLock() |
|
| 210 |
+ defer db.mux.RUnlock() |
|
| 211 |
+ |
|
| 212 |
+ e, err := db.get(name) |
|
| 213 |
+ if err != nil {
|
|
| 214 |
+ return nil |
|
| 215 |
+ } |
|
| 216 |
+ return e |
|
| 217 |
+} |
|
| 218 |
+ |
|
| 219 |
+func (db *Database) get(name string) (*Entity, error) {
|
|
| 220 |
+ e := db.RootEntity() |
|
| 221 |
+ // We always know the root name so return it if |
|
| 222 |
+ // it is requested |
|
| 223 |
+ if name == "/" {
|
|
| 224 |
+ return e, nil |
|
| 225 |
+ } |
|
| 226 |
+ |
|
| 227 |
+ parts := split(name) |
|
| 228 |
+ for i := 1; i < len(parts); i++ {
|
|
| 229 |
+ p := parts[i] |
|
| 230 |
+ if p == "" {
|
|
| 231 |
+ continue |
|
| 232 |
+ } |
|
| 233 |
+ |
|
| 234 |
+ next := db.child(e, p) |
|
| 235 |
+ if next == nil {
|
|
| 236 |
+ return nil, fmt.Errorf("Cannot find child for %s", name)
|
|
| 237 |
+ } |
|
| 238 |
+ e = next |
|
| 239 |
+ } |
|
| 240 |
+ return e, nil |
|
| 241 |
+ |
|
| 242 |
+} |
|
| 243 |
+ |
|
| 244 |
+// List all entities by from the name. |
|
| 245 |
+// The key will be the full path of the entity. |
|
| 246 |
+func (db *Database) List(name string, depth int) Entities {
|
|
| 247 |
+ db.mux.RLock() |
|
| 248 |
+ defer db.mux.RUnlock() |
|
| 249 |
+ |
|
| 250 |
+ out := Entities{}
|
|
| 251 |
+ e, err := db.get(name) |
|
| 252 |
+ if err != nil {
|
|
| 253 |
+ return out |
|
| 254 |
+ } |
|
| 255 |
+ |
|
| 256 |
+ children, err := db.children(e, name, depth, nil) |
|
| 257 |
+ if err != nil {
|
|
| 258 |
+ return out |
|
| 259 |
+ } |
|
| 260 |
+ |
|
| 261 |
+ for _, c := range children {
|
|
| 262 |
+ out[c.FullPath] = c.Entity |
|
| 263 |
+ } |
|
| 264 |
+ return out |
|
| 265 |
+} |
|
| 266 |
+ |
|
| 267 |
+// Walk through the child graph of an entity, calling walkFunc for each child entity. |
|
| 268 |
+// It is safe for walkFunc to call graph functions. |
|
| 269 |
+func (db *Database) Walk(name string, walkFunc WalkFunc, depth int) error {
|
|
| 270 |
+ children, err := db.Children(name, depth) |
|
| 271 |
+ if err != nil {
|
|
| 272 |
+ return err |
|
| 273 |
+ } |
|
| 274 |
+ |
|
| 275 |
+ // Note: the database lock must not be held while calling walkFunc |
|
| 276 |
+ for _, c := range children {
|
|
| 277 |
+ if err := walkFunc(c.FullPath, c.Entity); err != nil {
|
|
| 278 |
+ return err |
|
| 279 |
+ } |
|
| 280 |
+ } |
|
| 281 |
+ return nil |
|
| 282 |
+} |
|
| 283 |
+ |
|
| 284 |
+// Children returns the children of the specified entity. |
|
| 285 |
+func (db *Database) Children(name string, depth int) ([]WalkMeta, error) {
|
|
| 286 |
+ db.mux.RLock() |
|
| 287 |
+ defer db.mux.RUnlock() |
|
| 288 |
+ |
|
| 289 |
+ e, err := db.get(name) |
|
| 290 |
+ if err != nil {
|
|
| 291 |
+ return nil, err |
|
| 292 |
+ } |
|
| 293 |
+ |
|
| 294 |
+ return db.children(e, name, depth, nil) |
|
| 295 |
+} |
|
| 296 |
+ |
|
| 297 |
+// Parents returns the parents of a specified entity. |
|
| 298 |
+func (db *Database) Parents(name string) ([]string, error) {
|
|
| 299 |
+ db.mux.RLock() |
|
| 300 |
+ defer db.mux.RUnlock() |
|
| 301 |
+ |
|
| 302 |
+ e, err := db.get(name) |
|
| 303 |
+ if err != nil {
|
|
| 304 |
+ return nil, err |
|
| 305 |
+ } |
|
| 306 |
+ return db.parents(e) |
|
| 307 |
+} |
|
| 308 |
+ |
|
| 309 |
+// Refs returns the reference count for a specified id. |
|
| 310 |
+func (db *Database) Refs(id string) int {
|
|
| 311 |
+ db.mux.RLock() |
|
| 312 |
+ defer db.mux.RUnlock() |
|
| 313 |
+ |
|
| 314 |
+ var count int |
|
| 315 |
+ if err := db.conn.QueryRow("SELECT COUNT(*) FROM edge WHERE entity_id = ?;", id).Scan(&count); err != nil {
|
|
| 316 |
+ return 0 |
|
| 317 |
+ } |
|
| 318 |
+ return count |
|
| 319 |
+} |
|
| 320 |
+ |
|
| 321 |
+// RefPaths returns all the id's path references. |
|
| 322 |
+func (db *Database) RefPaths(id string) Edges {
|
|
| 323 |
+ db.mux.RLock() |
|
| 324 |
+ defer db.mux.RUnlock() |
|
| 325 |
+ |
|
| 326 |
+ refs := Edges{}
|
|
| 327 |
+ |
|
| 328 |
+ rows, err := db.conn.Query("SELECT name, parent_id FROM edge WHERE entity_id = ?;", id)
|
|
| 329 |
+ if err != nil {
|
|
| 330 |
+ return refs |
|
| 331 |
+ } |
|
| 332 |
+ defer rows.Close() |
|
| 333 |
+ |
|
| 334 |
+ for rows.Next() {
|
|
| 335 |
+ var name string |
|
| 336 |
+ var parentID string |
|
| 337 |
+ if err := rows.Scan(&name, &parentID); err != nil {
|
|
| 338 |
+ return refs |
|
| 339 |
+ } |
|
| 340 |
+ refs = append(refs, &Edge{
|
|
| 341 |
+ EntityID: id, |
|
| 342 |
+ Name: name, |
|
| 343 |
+ ParentID: parentID, |
|
| 344 |
+ }) |
|
| 345 |
+ } |
|
| 346 |
+ return refs |
|
| 347 |
+} |
|
| 348 |
+ |
|
| 349 |
+// Delete the reference to an entity at a given path. |
|
| 350 |
+func (db *Database) Delete(name string) error {
|
|
| 351 |
+ db.mux.Lock() |
|
| 352 |
+ defer db.mux.Unlock() |
|
| 353 |
+ |
|
| 354 |
+ if name == "/" {
|
|
| 355 |
+ return fmt.Errorf("Cannot delete root entity")
|
|
| 356 |
+ } |
|
| 357 |
+ |
|
| 358 |
+ parentPath, n := splitPath(name) |
|
| 359 |
+ parent, err := db.get(parentPath) |
|
| 360 |
+ if err != nil {
|
|
| 361 |
+ return err |
|
| 362 |
+ } |
|
| 363 |
+ |
|
| 364 |
+ if _, err := db.conn.Exec("DELETE FROM edge WHERE parent_id = ? AND name = ?;", parent.id, n); err != nil {
|
|
| 365 |
+ return err |
|
| 366 |
+ } |
|
| 367 |
+ return nil |
|
| 368 |
+} |
|
| 369 |
+ |
|
| 370 |
+// Purge removes the entity with the specified id |
|
| 371 |
+// Walk the graph to make sure all references to the entity |
|
| 372 |
+// are removed and return the number of references removed |
|
| 373 |
+func (db *Database) Purge(id string) (int, error) {
|
|
| 374 |
+ db.mux.Lock() |
|
| 375 |
+ defer db.mux.Unlock() |
|
| 376 |
+ |
|
| 377 |
+ tx, err := db.conn.Begin() |
|
| 378 |
+ if err != nil {
|
|
| 379 |
+ return -1, err |
|
| 380 |
+ } |
|
| 381 |
+ |
|
| 382 |
+ // Delete all edges |
|
| 383 |
+ rows, err := tx.Exec("DELETE FROM edge WHERE entity_id = ?;", id)
|
|
| 384 |
+ if err != nil {
|
|
| 385 |
+ tx.Rollback() |
|
| 386 |
+ return -1, err |
|
| 387 |
+ } |
|
| 388 |
+ changes, err := rows.RowsAffected() |
|
| 389 |
+ if err != nil {
|
|
| 390 |
+ return -1, err |
|
| 391 |
+ } |
|
| 392 |
+ |
|
| 393 |
+ // Clear who's using this id as parent |
|
| 394 |
+ refs, err := tx.Exec("DELETE FROM edge WHERE parent_id = ?;", id)
|
|
| 395 |
+ if err != nil {
|
|
| 396 |
+ tx.Rollback() |
|
| 397 |
+ return -1, err |
|
| 398 |
+ } |
|
| 399 |
+ refsCount, err := refs.RowsAffected() |
|
| 400 |
+ if err != nil {
|
|
| 401 |
+ return -1, err |
|
| 402 |
+ } |
|
| 403 |
+ |
|
| 404 |
+ // Delete entity |
|
| 405 |
+ if _, err := tx.Exec("DELETE FROM entity where id = ?;", id); err != nil {
|
|
| 406 |
+ tx.Rollback() |
|
| 407 |
+ return -1, err |
|
| 408 |
+ } |
|
| 409 |
+ |
|
| 410 |
+ if err := tx.Commit(); err != nil {
|
|
| 411 |
+ return -1, err |
|
| 412 |
+ } |
|
| 413 |
+ |
|
| 414 |
+ return int(changes + refsCount), nil |
|
| 415 |
+} |
|
| 416 |
+ |
|
| 417 |
+// Rename an edge for a given path |
|
| 418 |
+func (db *Database) Rename(currentName, newName string) error {
|
|
| 419 |
+ db.mux.Lock() |
|
| 420 |
+ defer db.mux.Unlock() |
|
| 421 |
+ |
|
| 422 |
+ parentPath, name := splitPath(currentName) |
|
| 423 |
+ newParentPath, newEdgeName := splitPath(newName) |
|
| 424 |
+ |
|
| 425 |
+ if parentPath != newParentPath {
|
|
| 426 |
+ return fmt.Errorf("Cannot rename when root paths do not match %s != %s", parentPath, newParentPath)
|
|
| 427 |
+ } |
|
| 428 |
+ |
|
| 429 |
+ parent, err := db.get(parentPath) |
|
| 430 |
+ if err != nil {
|
|
| 431 |
+ return err |
|
| 432 |
+ } |
|
| 433 |
+ |
|
| 434 |
+ rows, err := db.conn.Exec("UPDATE edge SET name = ? WHERE parent_id = ? AND name = ?;", newEdgeName, parent.id, name)
|
|
| 435 |
+ if err != nil {
|
|
| 436 |
+ return err |
|
| 437 |
+ } |
|
| 438 |
+ i, err := rows.RowsAffected() |
|
| 439 |
+ if err != nil {
|
|
| 440 |
+ return err |
|
| 441 |
+ } |
|
| 442 |
+ if i == 0 {
|
|
| 443 |
+ return fmt.Errorf("Cannot locate edge for %s %s", parent.id, name)
|
|
| 444 |
+ } |
|
| 445 |
+ return nil |
|
| 446 |
+} |
|
| 447 |
+ |
|
| 448 |
+// WalkMeta stores the walk metadata. |
|
| 449 |
+type WalkMeta struct {
|
|
| 450 |
+ Parent *Entity |
|
| 451 |
+ Entity *Entity |
|
| 452 |
+ FullPath string |
|
| 453 |
+ Edge *Edge |
|
| 454 |
+} |
|
| 455 |
+ |
|
| 456 |
+func (db *Database) children(e *Entity, name string, depth int, entities []WalkMeta) ([]WalkMeta, error) {
|
|
| 457 |
+ if e == nil {
|
|
| 458 |
+ return entities, nil |
|
| 459 |
+ } |
|
| 460 |
+ |
|
| 461 |
+ rows, err := db.conn.Query("SELECT entity_id, name FROM edge where parent_id = ?;", e.id)
|
|
| 462 |
+ if err != nil {
|
|
| 463 |
+ return nil, err |
|
| 464 |
+ } |
|
| 465 |
+ defer rows.Close() |
|
| 466 |
+ |
|
| 467 |
+ for rows.Next() {
|
|
| 468 |
+ var entityID, entityName string |
|
| 469 |
+ if err := rows.Scan(&entityID, &entityName); err != nil {
|
|
| 470 |
+ return nil, err |
|
| 471 |
+ } |
|
| 472 |
+ child := &Entity{entityID}
|
|
| 473 |
+ edge := &Edge{
|
|
| 474 |
+ ParentID: e.id, |
|
| 475 |
+ Name: entityName, |
|
| 476 |
+ EntityID: child.id, |
|
| 477 |
+ } |
|
| 478 |
+ |
|
| 479 |
+ meta := WalkMeta{
|
|
| 480 |
+ Parent: e, |
|
| 481 |
+ Entity: child, |
|
| 482 |
+ FullPath: path.Join(name, edge.Name), |
|
| 483 |
+ Edge: edge, |
|
| 484 |
+ } |
|
| 485 |
+ |
|
| 486 |
+ entities = append(entities, meta) |
|
| 487 |
+ |
|
| 488 |
+ if depth != 0 {
|
|
| 489 |
+ nDepth := depth |
|
| 490 |
+ if depth != -1 {
|
|
| 491 |
+ nDepth-- |
|
| 492 |
+ } |
|
| 493 |
+ entities, err = db.children(child, meta.FullPath, nDepth, entities) |
|
| 494 |
+ if err != nil {
|
|
| 495 |
+ return nil, err |
|
| 496 |
+ } |
|
| 497 |
+ } |
|
| 498 |
+ } |
|
| 499 |
+ |
|
| 500 |
+ return entities, nil |
|
| 501 |
+} |
|
| 502 |
+ |
|
| 503 |
+func (db *Database) parents(e *Entity) (parents []string, err error) {
|
|
| 504 |
+ if e == nil {
|
|
| 505 |
+ return parents, nil |
|
| 506 |
+ } |
|
| 507 |
+ |
|
| 508 |
+ rows, err := db.conn.Query("SELECT parent_id FROM edge where entity_id = ?;", e.id)
|
|
| 509 |
+ if err != nil {
|
|
| 510 |
+ return nil, err |
|
| 511 |
+ } |
|
| 512 |
+ defer rows.Close() |
|
| 513 |
+ |
|
| 514 |
+ for rows.Next() {
|
|
| 515 |
+ var parentID string |
|
| 516 |
+ if err := rows.Scan(&parentID); err != nil {
|
|
| 517 |
+ return nil, err |
|
| 518 |
+ } |
|
| 519 |
+ parents = append(parents, parentID) |
|
| 520 |
+ } |
|
| 521 |
+ |
|
| 522 |
+ return parents, nil |
|
| 523 |
+} |
|
| 524 |
+ |
|
| 525 |
+// Return the entity based on the parent path and name. |
|
| 526 |
+func (db *Database) child(parent *Entity, name string) *Entity {
|
|
| 527 |
+ var id string |
|
| 528 |
+ if err := db.conn.QueryRow("SELECT entity_id FROM edge WHERE parent_id = ? AND name = ?;", parent.id, name).Scan(&id); err != nil {
|
|
| 529 |
+ return nil |
|
| 530 |
+ } |
|
| 531 |
+ return &Entity{id}
|
|
| 532 |
+} |
|
| 533 |
+ |
|
| 534 |
+// ID returns the id used to reference this entity. |
|
| 535 |
+func (e *Entity) ID() string {
|
|
| 536 |
+ return e.id |
|
| 537 |
+} |
|
| 538 |
+ |
|
| 539 |
+// Paths returns the paths sorted by depth. |
|
| 540 |
+func (e Entities) Paths() []string {
|
|
| 541 |
+ out := make([]string, len(e)) |
|
| 542 |
+ var i int |
|
| 543 |
+ for k := range e {
|
|
| 544 |
+ out[i] = k |
|
| 545 |
+ i++ |
|
| 546 |
+ } |
|
| 547 |
+ sortByDepth(out) |
|
| 548 |
+ |
|
| 549 |
+ return out |
|
| 550 |
+} |
| 0 | 551 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,721 @@ |
| 0 |
+package graphdb |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "database/sql" |
|
| 4 |
+ "fmt" |
|
| 5 |
+ "os" |
|
| 6 |
+ "path" |
|
| 7 |
+ "runtime" |
|
| 8 |
+ "strconv" |
|
| 9 |
+ "testing" |
|
| 10 |
+ |
|
| 11 |
+ _ "github.com/mattn/go-sqlite3" |
|
| 12 |
+) |
|
| 13 |
+ |
|
| 14 |
+func newTestDb(t *testing.T) (*Database, string) {
|
|
| 15 |
+ p := path.Join(os.TempDir(), "sqlite.db") |
|
| 16 |
+ conn, err := sql.Open("sqlite3", p)
|
|
| 17 |
+ db, err := NewDatabase(conn) |
|
| 18 |
+ if err != nil {
|
|
| 19 |
+ t.Fatal(err) |
|
| 20 |
+ } |
|
| 21 |
+ return db, p |
|
| 22 |
+} |
|
| 23 |
+ |
|
| 24 |
+func destroyTestDb(dbPath string) {
|
|
| 25 |
+ os.Remove(dbPath) |
|
| 26 |
+} |
|
| 27 |
+ |
|
| 28 |
+func TestNewDatabase(t *testing.T) {
|
|
| 29 |
+ db, dbpath := newTestDb(t) |
|
| 30 |
+ if db == nil {
|
|
| 31 |
+ t.Fatal("Database should not be nil")
|
|
| 32 |
+ } |
|
| 33 |
+ db.Close() |
|
| 34 |
+ defer destroyTestDb(dbpath) |
|
| 35 |
+} |
|
| 36 |
+ |
|
| 37 |
+func TestCreateRootEntity(t *testing.T) {
|
|
| 38 |
+ db, dbpath := newTestDb(t) |
|
| 39 |
+ defer destroyTestDb(dbpath) |
|
| 40 |
+ root := db.RootEntity() |
|
| 41 |
+ if root == nil {
|
|
| 42 |
+ t.Fatal("Root entity should not be nil")
|
|
| 43 |
+ } |
|
| 44 |
+} |
|
| 45 |
+ |
|
| 46 |
+func TestGetRootEntity(t *testing.T) {
|
|
| 47 |
+ db, dbpath := newTestDb(t) |
|
| 48 |
+ defer destroyTestDb(dbpath) |
|
| 49 |
+ |
|
| 50 |
+ e := db.Get("/")
|
|
| 51 |
+ if e == nil {
|
|
| 52 |
+ t.Fatal("Entity should not be nil")
|
|
| 53 |
+ } |
|
| 54 |
+ if e.ID() != "0" {
|
|
| 55 |
+ t.Fatalf("Entity id should be 0, got %s", e.ID())
|
|
| 56 |
+ } |
|
| 57 |
+} |
|
| 58 |
+ |
|
| 59 |
+func TestSetEntityWithDifferentName(t *testing.T) {
|
|
| 60 |
+ db, dbpath := newTestDb(t) |
|
| 61 |
+ defer destroyTestDb(dbpath) |
|
| 62 |
+ |
|
| 63 |
+ db.Set("/test", "1")
|
|
| 64 |
+ if _, err := db.Set("/other", "1"); err != nil {
|
|
| 65 |
+ t.Fatal(err) |
|
| 66 |
+ } |
|
| 67 |
+} |
|
| 68 |
+ |
|
| 69 |
+func TestSetDuplicateEntity(t *testing.T) {
|
|
| 70 |
+ db, dbpath := newTestDb(t) |
|
| 71 |
+ defer destroyTestDb(dbpath) |
|
| 72 |
+ |
|
| 73 |
+ if _, err := db.Set("/foo", "42"); err != nil {
|
|
| 74 |
+ t.Fatal(err) |
|
| 75 |
+ } |
|
| 76 |
+ if _, err := db.Set("/foo", "43"); err == nil {
|
|
| 77 |
+ t.Fatalf("Creating an entry with a duplicate path did not cause an error")
|
|
| 78 |
+ } |
|
| 79 |
+} |
|
| 80 |
+ |
|
| 81 |
+func TestCreateChild(t *testing.T) {
|
|
| 82 |
+ db, dbpath := newTestDb(t) |
|
| 83 |
+ defer destroyTestDb(dbpath) |
|
| 84 |
+ |
|
| 85 |
+ child, err := db.Set("/db", "1")
|
|
| 86 |
+ if err != nil {
|
|
| 87 |
+ t.Fatal(err) |
|
| 88 |
+ } |
|
| 89 |
+ if child == nil {
|
|
| 90 |
+ t.Fatal("Child should not be nil")
|
|
| 91 |
+ } |
|
| 92 |
+ if child.ID() != "1" {
|
|
| 93 |
+ t.Fail() |
|
| 94 |
+ } |
|
| 95 |
+} |
|
| 96 |
+ |
|
| 97 |
+func TestParents(t *testing.T) {
|
|
| 98 |
+ db, dbpath := newTestDb(t) |
|
| 99 |
+ defer destroyTestDb(dbpath) |
|
| 100 |
+ |
|
| 101 |
+ for i := 1; i < 6; i++ {
|
|
| 102 |
+ a := strconv.Itoa(i) |
|
| 103 |
+ if _, err := db.Set("/"+a, a); err != nil {
|
|
| 104 |
+ t.Fatal(err) |
|
| 105 |
+ } |
|
| 106 |
+ } |
|
| 107 |
+ |
|
| 108 |
+ for i := 6; i < 11; i++ {
|
|
| 109 |
+ a := strconv.Itoa(i) |
|
| 110 |
+ p := strconv.Itoa(i - 5) |
|
| 111 |
+ |
|
| 112 |
+ key := fmt.Sprintf("/%s/%s", p, a)
|
|
| 113 |
+ |
|
| 114 |
+ if _, err := db.Set(key, a); err != nil {
|
|
| 115 |
+ t.Fatal(err) |
|
| 116 |
+ } |
|
| 117 |
+ |
|
| 118 |
+ parents, err := db.Parents(key) |
|
| 119 |
+ if err != nil {
|
|
| 120 |
+ t.Fatal(err) |
|
| 121 |
+ } |
|
| 122 |
+ |
|
| 123 |
+ if len(parents) != 1 {
|
|
| 124 |
+ t.Fatalf("Expected 1 entry for %s got %d", key, len(parents))
|
|
| 125 |
+ } |
|
| 126 |
+ |
|
| 127 |
+ if parents[0] != p {
|
|
| 128 |
+ t.Fatalf("ID %s received, %s expected", parents[0], p)
|
|
| 129 |
+ } |
|
| 130 |
+ } |
|
| 131 |
+} |
|
| 132 |
+ |
|
| 133 |
+func TestChildren(t *testing.T) {
|
|
| 134 |
+ // TODO Windows: Port this test |
|
| 135 |
+ if runtime.GOOS == "windows" {
|
|
| 136 |
+ t.Skip("Needs porting to Windows")
|
|
| 137 |
+ } |
|
| 138 |
+ db, dbpath := newTestDb(t) |
|
| 139 |
+ defer destroyTestDb(dbpath) |
|
| 140 |
+ |
|
| 141 |
+ str := "/" |
|
| 142 |
+ for i := 1; i < 6; i++ {
|
|
| 143 |
+ a := strconv.Itoa(i) |
|
| 144 |
+ if _, err := db.Set(str+a, a); err != nil {
|
|
| 145 |
+ t.Fatal(err) |
|
| 146 |
+ } |
|
| 147 |
+ |
|
| 148 |
+ str = str + a + "/" |
|
| 149 |
+ } |
|
| 150 |
+ |
|
| 151 |
+ str = "/" |
|
| 152 |
+ for i := 10; i < 30; i++ { // 20 entities
|
|
| 153 |
+ a := strconv.Itoa(i) |
|
| 154 |
+ if _, err := db.Set(str+a, a); err != nil {
|
|
| 155 |
+ t.Fatal(err) |
|
| 156 |
+ } |
|
| 157 |
+ |
|
| 158 |
+ str = str + a + "/" |
|
| 159 |
+ } |
|
| 160 |
+ entries, err := db.Children("/", 5)
|
|
| 161 |
+ if err != nil {
|
|
| 162 |
+ t.Fatal(err) |
|
| 163 |
+ } |
|
| 164 |
+ |
|
| 165 |
+ if len(entries) != 11 {
|
|
| 166 |
+ t.Fatalf("Expect 11 entries for / got %d", len(entries))
|
|
| 167 |
+ } |
|
| 168 |
+ |
|
| 169 |
+ entries, err = db.Children("/", 20)
|
|
| 170 |
+ if err != nil {
|
|
| 171 |
+ t.Fatal(err) |
|
| 172 |
+ } |
|
| 173 |
+ |
|
| 174 |
+ if len(entries) != 25 {
|
|
| 175 |
+ t.Fatalf("Expect 25 entries for / got %d", len(entries))
|
|
| 176 |
+ } |
|
| 177 |
+} |
|
| 178 |
+ |
|
| 179 |
+func TestListAllRootChildren(t *testing.T) {
|
|
| 180 |
+ // TODO Windows: Port this test |
|
| 181 |
+ if runtime.GOOS == "windows" {
|
|
| 182 |
+ t.Skip("Needs porting to Windows")
|
|
| 183 |
+ } |
|
| 184 |
+ |
|
| 185 |
+ db, dbpath := newTestDb(t) |
|
| 186 |
+ defer destroyTestDb(dbpath) |
|
| 187 |
+ |
|
| 188 |
+ for i := 1; i < 6; i++ {
|
|
| 189 |
+ a := strconv.Itoa(i) |
|
| 190 |
+ if _, err := db.Set("/"+a, a); err != nil {
|
|
| 191 |
+ t.Fatal(err) |
|
| 192 |
+ } |
|
| 193 |
+ } |
|
| 194 |
+ entries := db.List("/", -1)
|
|
| 195 |
+ if len(entries) != 5 {
|
|
| 196 |
+ t.Fatalf("Expect 5 entries for / got %d", len(entries))
|
|
| 197 |
+ } |
|
| 198 |
+} |
|
| 199 |
+ |
|
| 200 |
+func TestListAllSubChildren(t *testing.T) {
|
|
| 201 |
+ // TODO Windows: Port this test |
|
| 202 |
+ if runtime.GOOS == "windows" {
|
|
| 203 |
+ t.Skip("Needs porting to Windows")
|
|
| 204 |
+ } |
|
| 205 |
+ db, dbpath := newTestDb(t) |
|
| 206 |
+ defer destroyTestDb(dbpath) |
|
| 207 |
+ |
|
| 208 |
+ _, err := db.Set("/webapp", "1")
|
|
| 209 |
+ if err != nil {
|
|
| 210 |
+ t.Fatal(err) |
|
| 211 |
+ } |
|
| 212 |
+ child2, err := db.Set("/db", "2")
|
|
| 213 |
+ if err != nil {
|
|
| 214 |
+ t.Fatal(err) |
|
| 215 |
+ } |
|
| 216 |
+ child4, err := db.Set("/logs", "4")
|
|
| 217 |
+ if err != nil {
|
|
| 218 |
+ t.Fatal(err) |
|
| 219 |
+ } |
|
| 220 |
+ if _, err := db.Set("/db/logs", child4.ID()); err != nil {
|
|
| 221 |
+ t.Fatal(err) |
|
| 222 |
+ } |
|
| 223 |
+ |
|
| 224 |
+ child3, err := db.Set("/sentry", "3")
|
|
| 225 |
+ if err != nil {
|
|
| 226 |
+ t.Fatal(err) |
|
| 227 |
+ } |
|
| 228 |
+ if _, err := db.Set("/webapp/sentry", child3.ID()); err != nil {
|
|
| 229 |
+ t.Fatal(err) |
|
| 230 |
+ } |
|
| 231 |
+ if _, err := db.Set("/webapp/db", child2.ID()); err != nil {
|
|
| 232 |
+ t.Fatal(err) |
|
| 233 |
+ } |
|
| 234 |
+ |
|
| 235 |
+ entries := db.List("/webapp", 1)
|
|
| 236 |
+ if len(entries) != 3 {
|
|
| 237 |
+ t.Fatalf("Expect 3 entries for / got %d", len(entries))
|
|
| 238 |
+ } |
|
| 239 |
+ |
|
| 240 |
+ entries = db.List("/webapp", 0)
|
|
| 241 |
+ if len(entries) != 2 {
|
|
| 242 |
+ t.Fatalf("Expect 2 entries for / got %d", len(entries))
|
|
| 243 |
+ } |
|
| 244 |
+} |
|
| 245 |
+ |
|
| 246 |
+func TestAddSelfAsChild(t *testing.T) {
|
|
| 247 |
+ // TODO Windows: Port this test |
|
| 248 |
+ if runtime.GOOS == "windows" {
|
|
| 249 |
+ t.Skip("Needs porting to Windows")
|
|
| 250 |
+ } |
|
| 251 |
+ db, dbpath := newTestDb(t) |
|
| 252 |
+ defer destroyTestDb(dbpath) |
|
| 253 |
+ |
|
| 254 |
+ child, err := db.Set("/test", "1")
|
|
| 255 |
+ if err != nil {
|
|
| 256 |
+ t.Fatal(err) |
|
| 257 |
+ } |
|
| 258 |
+ if _, err := db.Set("/test/other", child.ID()); err == nil {
|
|
| 259 |
+ t.Fatal("Error should not be nil")
|
|
| 260 |
+ } |
|
| 261 |
+} |
|
| 262 |
+ |
|
| 263 |
+func TestAddChildToNonExistentRoot(t *testing.T) {
|
|
| 264 |
+ db, dbpath := newTestDb(t) |
|
| 265 |
+ defer destroyTestDb(dbpath) |
|
| 266 |
+ |
|
| 267 |
+ if _, err := db.Set("/myapp", "1"); err != nil {
|
|
| 268 |
+ t.Fatal(err) |
|
| 269 |
+ } |
|
| 270 |
+ |
|
| 271 |
+ if _, err := db.Set("/myapp/proxy/db", "2"); err == nil {
|
|
| 272 |
+ t.Fatal("Error should not be nil")
|
|
| 273 |
+ } |
|
| 274 |
+} |
|
| 275 |
+ |
|
| 276 |
+func TestWalkAll(t *testing.T) {
|
|
| 277 |
+ // TODO Windows: Port this test |
|
| 278 |
+ if runtime.GOOS == "windows" {
|
|
| 279 |
+ t.Skip("Needs porting to Windows")
|
|
| 280 |
+ } |
|
| 281 |
+ db, dbpath := newTestDb(t) |
|
| 282 |
+ defer destroyTestDb(dbpath) |
|
| 283 |
+ _, err := db.Set("/webapp", "1")
|
|
| 284 |
+ if err != nil {
|
|
| 285 |
+ t.Fatal(err) |
|
| 286 |
+ } |
|
| 287 |
+ child2, err := db.Set("/db", "2")
|
|
| 288 |
+ if err != nil {
|
|
| 289 |
+ t.Fatal(err) |
|
| 290 |
+ } |
|
| 291 |
+ child4, err := db.Set("/db/logs", "4")
|
|
| 292 |
+ if err != nil {
|
|
| 293 |
+ t.Fatal(err) |
|
| 294 |
+ } |
|
| 295 |
+ if _, err := db.Set("/webapp/logs", child4.ID()); err != nil {
|
|
| 296 |
+ t.Fatal(err) |
|
| 297 |
+ } |
|
| 298 |
+ |
|
| 299 |
+ child3, err := db.Set("/sentry", "3")
|
|
| 300 |
+ if err != nil {
|
|
| 301 |
+ t.Fatal(err) |
|
| 302 |
+ } |
|
| 303 |
+ if _, err := db.Set("/webapp/sentry", child3.ID()); err != nil {
|
|
| 304 |
+ t.Fatal(err) |
|
| 305 |
+ } |
|
| 306 |
+ if _, err := db.Set("/webapp/db", child2.ID()); err != nil {
|
|
| 307 |
+ t.Fatal(err) |
|
| 308 |
+ } |
|
| 309 |
+ |
|
| 310 |
+ child5, err := db.Set("/gograph", "5")
|
|
| 311 |
+ if err != nil {
|
|
| 312 |
+ t.Fatal(err) |
|
| 313 |
+ } |
|
| 314 |
+ if _, err := db.Set("/webapp/same-ref-diff-name", child5.ID()); err != nil {
|
|
| 315 |
+ t.Fatal(err) |
|
| 316 |
+ } |
|
| 317 |
+ |
|
| 318 |
+ if err := db.Walk("/", func(p string, e *Entity) error {
|
|
| 319 |
+ t.Logf("Path: %s Entity: %s", p, e.ID())
|
|
| 320 |
+ return nil |
|
| 321 |
+ }, -1); err != nil {
|
|
| 322 |
+ t.Fatal(err) |
|
| 323 |
+ } |
|
| 324 |
+} |
|
| 325 |
+ |
|
| 326 |
+func TestGetEntityByPath(t *testing.T) {
|
|
| 327 |
+ // TODO Windows: Port this test |
|
| 328 |
+ if runtime.GOOS == "windows" {
|
|
| 329 |
+ t.Skip("Needs porting to Windows")
|
|
| 330 |
+ } |
|
| 331 |
+ db, dbpath := newTestDb(t) |
|
| 332 |
+ defer destroyTestDb(dbpath) |
|
| 333 |
+ _, err := db.Set("/webapp", "1")
|
|
| 334 |
+ if err != nil {
|
|
| 335 |
+ t.Fatal(err) |
|
| 336 |
+ } |
|
| 337 |
+ child2, err := db.Set("/db", "2")
|
|
| 338 |
+ if err != nil {
|
|
| 339 |
+ t.Fatal(err) |
|
| 340 |
+ } |
|
| 341 |
+ child4, err := db.Set("/logs", "4")
|
|
| 342 |
+ if err != nil {
|
|
| 343 |
+ t.Fatal(err) |
|
| 344 |
+ } |
|
| 345 |
+ if _, err := db.Set("/db/logs", child4.ID()); err != nil {
|
|
| 346 |
+ t.Fatal(err) |
|
| 347 |
+ } |
|
| 348 |
+ |
|
| 349 |
+ child3, err := db.Set("/sentry", "3")
|
|
| 350 |
+ if err != nil {
|
|
| 351 |
+ t.Fatal(err) |
|
| 352 |
+ } |
|
| 353 |
+ if _, err := db.Set("/webapp/sentry", child3.ID()); err != nil {
|
|
| 354 |
+ t.Fatal(err) |
|
| 355 |
+ } |
|
| 356 |
+ if _, err := db.Set("/webapp/db", child2.ID()); err != nil {
|
|
| 357 |
+ t.Fatal(err) |
|
| 358 |
+ } |
|
| 359 |
+ |
|
| 360 |
+ child5, err := db.Set("/gograph", "5")
|
|
| 361 |
+ if err != nil {
|
|
| 362 |
+ t.Fatal(err) |
|
| 363 |
+ } |
|
| 364 |
+ if _, err := db.Set("/webapp/same-ref-diff-name", child5.ID()); err != nil {
|
|
| 365 |
+ t.Fatal(err) |
|
| 366 |
+ } |
|
| 367 |
+ |
|
| 368 |
+ entity := db.Get("/webapp/db/logs")
|
|
| 369 |
+ if entity == nil {
|
|
| 370 |
+ t.Fatal("Entity should not be nil")
|
|
| 371 |
+ } |
|
| 372 |
+ if entity.ID() != "4" {
|
|
| 373 |
+ t.Fatalf("Expected to get entity with id 4, got %s", entity.ID())
|
|
| 374 |
+ } |
|
| 375 |
+} |
|
| 376 |
+ |
|
| 377 |
+func TestEnitiesPaths(t *testing.T) {
|
|
| 378 |
+ // TODO Windows: Port this test |
|
| 379 |
+ if runtime.GOOS == "windows" {
|
|
| 380 |
+ t.Skip("Needs porting to Windows")
|
|
| 381 |
+ } |
|
| 382 |
+ db, dbpath := newTestDb(t) |
|
| 383 |
+ defer destroyTestDb(dbpath) |
|
| 384 |
+ _, err := db.Set("/webapp", "1")
|
|
| 385 |
+ if err != nil {
|
|
| 386 |
+ t.Fatal(err) |
|
| 387 |
+ } |
|
| 388 |
+ child2, err := db.Set("/db", "2")
|
|
| 389 |
+ if err != nil {
|
|
| 390 |
+ t.Fatal(err) |
|
| 391 |
+ } |
|
| 392 |
+ child4, err := db.Set("/logs", "4")
|
|
| 393 |
+ if err != nil {
|
|
| 394 |
+ t.Fatal(err) |
|
| 395 |
+ } |
|
| 396 |
+ if _, err := db.Set("/db/logs", child4.ID()); err != nil {
|
|
| 397 |
+ t.Fatal(err) |
|
| 398 |
+ } |
|
| 399 |
+ |
|
| 400 |
+ child3, err := db.Set("/sentry", "3")
|
|
| 401 |
+ if err != nil {
|
|
| 402 |
+ t.Fatal(err) |
|
| 403 |
+ } |
|
| 404 |
+ if _, err := db.Set("/webapp/sentry", child3.ID()); err != nil {
|
|
| 405 |
+ t.Fatal(err) |
|
| 406 |
+ } |
|
| 407 |
+ if _, err := db.Set("/webapp/db", child2.ID()); err != nil {
|
|
| 408 |
+ t.Fatal(err) |
|
| 409 |
+ } |
|
| 410 |
+ |
|
| 411 |
+ child5, err := db.Set("/gograph", "5")
|
|
| 412 |
+ if err != nil {
|
|
| 413 |
+ t.Fatal(err) |
|
| 414 |
+ } |
|
| 415 |
+ if _, err := db.Set("/webapp/same-ref-diff-name", child5.ID()); err != nil {
|
|
| 416 |
+ t.Fatal(err) |
|
| 417 |
+ } |
|
| 418 |
+ |
|
| 419 |
+ out := db.List("/", -1)
|
|
| 420 |
+ for _, p := range out.Paths() {
|
|
| 421 |
+ t.Log(p) |
|
| 422 |
+ } |
|
| 423 |
+} |
|
| 424 |
+ |
|
| 425 |
+func TestDeleteRootEntity(t *testing.T) {
|
|
| 426 |
+ db, dbpath := newTestDb(t) |
|
| 427 |
+ defer destroyTestDb(dbpath) |
|
| 428 |
+ |
|
| 429 |
+ if err := db.Delete("/"); err == nil {
|
|
| 430 |
+ t.Fatal("Error should not be nil")
|
|
| 431 |
+ } |
|
| 432 |
+} |
|
| 433 |
+ |
|
| 434 |
+func TestDeleteEntity(t *testing.T) {
|
|
| 435 |
+ // TODO Windows: Port this test |
|
| 436 |
+ if runtime.GOOS == "windows" {
|
|
| 437 |
+ t.Skip("Needs porting to Windows")
|
|
| 438 |
+ } |
|
| 439 |
+ db, dbpath := newTestDb(t) |
|
| 440 |
+ defer destroyTestDb(dbpath) |
|
| 441 |
+ _, err := db.Set("/webapp", "1")
|
|
| 442 |
+ if err != nil {
|
|
| 443 |
+ t.Fatal(err) |
|
| 444 |
+ } |
|
| 445 |
+ child2, err := db.Set("/db", "2")
|
|
| 446 |
+ if err != nil {
|
|
| 447 |
+ t.Fatal(err) |
|
| 448 |
+ } |
|
| 449 |
+ child4, err := db.Set("/logs", "4")
|
|
| 450 |
+ if err != nil {
|
|
| 451 |
+ t.Fatal(err) |
|
| 452 |
+ } |
|
| 453 |
+ if _, err := db.Set("/db/logs", child4.ID()); err != nil {
|
|
| 454 |
+ t.Fatal(err) |
|
| 455 |
+ } |
|
| 456 |
+ |
|
| 457 |
+ child3, err := db.Set("/sentry", "3")
|
|
| 458 |
+ if err != nil {
|
|
| 459 |
+ t.Fatal(err) |
|
| 460 |
+ } |
|
| 461 |
+ if _, err := db.Set("/webapp/sentry", child3.ID()); err != nil {
|
|
| 462 |
+ t.Fatal(err) |
|
| 463 |
+ } |
|
| 464 |
+ if _, err := db.Set("/webapp/db", child2.ID()); err != nil {
|
|
| 465 |
+ t.Fatal(err) |
|
| 466 |
+ } |
|
| 467 |
+ |
|
| 468 |
+ child5, err := db.Set("/gograph", "5")
|
|
| 469 |
+ if err != nil {
|
|
| 470 |
+ t.Fatal(err) |
|
| 471 |
+ } |
|
| 472 |
+ if _, err := db.Set("/webapp/same-ref-diff-name", child5.ID()); err != nil {
|
|
| 473 |
+ t.Fatal(err) |
|
| 474 |
+ } |
|
| 475 |
+ |
|
| 476 |
+ if err := db.Delete("/webapp/sentry"); err != nil {
|
|
| 477 |
+ t.Fatal(err) |
|
| 478 |
+ } |
|
| 479 |
+ entity := db.Get("/webapp/sentry")
|
|
| 480 |
+ if entity != nil {
|
|
| 481 |
+ t.Fatal("Entity /webapp/sentry should be nil")
|
|
| 482 |
+ } |
|
| 483 |
+} |
|
| 484 |
+ |
|
| 485 |
+func TestCountRefs(t *testing.T) {
|
|
| 486 |
+ // TODO Windows: Port this test |
|
| 487 |
+ if runtime.GOOS == "windows" {
|
|
| 488 |
+ t.Skip("Needs porting to Windows")
|
|
| 489 |
+ } |
|
| 490 |
+ db, dbpath := newTestDb(t) |
|
| 491 |
+ defer destroyTestDb(dbpath) |
|
| 492 |
+ |
|
| 493 |
+ db.Set("/webapp", "1")
|
|
| 494 |
+ |
|
| 495 |
+ if db.Refs("1") != 1 {
|
|
| 496 |
+ t.Fatal("Expect reference count to be 1")
|
|
| 497 |
+ } |
|
| 498 |
+ |
|
| 499 |
+ db.Set("/db", "2")
|
|
| 500 |
+ db.Set("/webapp/db", "2")
|
|
| 501 |
+ if db.Refs("2") != 2 {
|
|
| 502 |
+ t.Fatal("Expect reference count to be 2")
|
|
| 503 |
+ } |
|
| 504 |
+} |
|
| 505 |
+ |
|
| 506 |
+func TestPurgeId(t *testing.T) {
|
|
| 507 |
+ // TODO Windows: Port this test |
|
| 508 |
+ if runtime.GOOS == "windows" {
|
|
| 509 |
+ t.Skip("Needs porting to Windows")
|
|
| 510 |
+ } |
|
| 511 |
+ |
|
| 512 |
+ db, dbpath := newTestDb(t) |
|
| 513 |
+ defer destroyTestDb(dbpath) |
|
| 514 |
+ |
|
| 515 |
+ db.Set("/webapp", "1")
|
|
| 516 |
+ |
|
| 517 |
+ if c := db.Refs("1"); c != 1 {
|
|
| 518 |
+ t.Fatalf("Expect reference count to be 1, got %d", c)
|
|
| 519 |
+ } |
|
| 520 |
+ |
|
| 521 |
+ db.Set("/db", "2")
|
|
| 522 |
+ db.Set("/webapp/db", "2")
|
|
| 523 |
+ |
|
| 524 |
+ count, err := db.Purge("2")
|
|
| 525 |
+ if err != nil {
|
|
| 526 |
+ t.Fatal(err) |
|
| 527 |
+ } |
|
| 528 |
+ if count != 2 {
|
|
| 529 |
+ t.Fatalf("Expected 2 references to be removed, got %d", count)
|
|
| 530 |
+ } |
|
| 531 |
+} |
|
| 532 |
+ |
|
| 533 |
+// Regression test https://github.com/docker/docker/issues/12334 |
|
| 534 |
+func TestPurgeIdRefPaths(t *testing.T) {
|
|
| 535 |
+ // TODO Windows: Port this test |
|
| 536 |
+ if runtime.GOOS == "windows" {
|
|
| 537 |
+ t.Skip("Needs porting to Windows")
|
|
| 538 |
+ } |
|
| 539 |
+ db, dbpath := newTestDb(t) |
|
| 540 |
+ defer destroyTestDb(dbpath) |
|
| 541 |
+ |
|
| 542 |
+ db.Set("/webapp", "1")
|
|
| 543 |
+ db.Set("/db", "2")
|
|
| 544 |
+ |
|
| 545 |
+ db.Set("/db/webapp", "1")
|
|
| 546 |
+ |
|
| 547 |
+ if c := db.Refs("1"); c != 2 {
|
|
| 548 |
+ t.Fatalf("Expected 2 reference for webapp, got %d", c)
|
|
| 549 |
+ } |
|
| 550 |
+ if c := db.Refs("2"); c != 1 {
|
|
| 551 |
+ t.Fatalf("Expected 1 reference for db, got %d", c)
|
|
| 552 |
+ } |
|
| 553 |
+ |
|
| 554 |
+ if rp := db.RefPaths("2"); len(rp) != 1 {
|
|
| 555 |
+ t.Fatalf("Expected 1 reference path for db, got %d", len(rp))
|
|
| 556 |
+ } |
|
| 557 |
+ |
|
| 558 |
+ count, err := db.Purge("2")
|
|
| 559 |
+ if err != nil {
|
|
| 560 |
+ t.Fatal(err) |
|
| 561 |
+ } |
|
| 562 |
+ |
|
| 563 |
+ if count != 2 {
|
|
| 564 |
+ t.Fatalf("Expected 2 rows to be removed, got %d", count)
|
|
| 565 |
+ } |
|
| 566 |
+ |
|
| 567 |
+ if c := db.Refs("2"); c != 0 {
|
|
| 568 |
+ t.Fatalf("Expected 0 reference for db, got %d", c)
|
|
| 569 |
+ } |
|
| 570 |
+ if c := db.Refs("1"); c != 1 {
|
|
| 571 |
+ t.Fatalf("Expected 1 reference for webapp, got %d", c)
|
|
| 572 |
+ } |
|
| 573 |
+} |
|
| 574 |
+ |
|
| 575 |
+func TestRename(t *testing.T) {
|
|
| 576 |
+ // TODO Windows: Port this test |
|
| 577 |
+ if runtime.GOOS == "windows" {
|
|
| 578 |
+ t.Skip("Needs porting to Windows")
|
|
| 579 |
+ } |
|
| 580 |
+ db, dbpath := newTestDb(t) |
|
| 581 |
+ defer destroyTestDb(dbpath) |
|
| 582 |
+ |
|
| 583 |
+ db.Set("/webapp", "1")
|
|
| 584 |
+ |
|
| 585 |
+ if db.Refs("1") != 1 {
|
|
| 586 |
+ t.Fatal("Expect reference count to be 1")
|
|
| 587 |
+ } |
|
| 588 |
+ |
|
| 589 |
+ db.Set("/db", "2")
|
|
| 590 |
+ db.Set("/webapp/db", "2")
|
|
| 591 |
+ |
|
| 592 |
+ if db.Get("/webapp/db") == nil {
|
|
| 593 |
+ t.Fatal("Cannot find entity at path /webapp/db")
|
|
| 594 |
+ } |
|
| 595 |
+ |
|
| 596 |
+ if err := db.Rename("/webapp/db", "/webapp/newdb"); err != nil {
|
|
| 597 |
+ t.Fatal(err) |
|
| 598 |
+ } |
|
| 599 |
+ if db.Get("/webapp/db") != nil {
|
|
| 600 |
+ t.Fatal("Entity should not exist at /webapp/db")
|
|
| 601 |
+ } |
|
| 602 |
+ if db.Get("/webapp/newdb") == nil {
|
|
| 603 |
+ t.Fatal("Cannot find entity at path /webapp/newdb")
|
|
| 604 |
+ } |
|
| 605 |
+ |
|
| 606 |
+} |
|
| 607 |
+ |
|
| 608 |
+func TestCreateMultipleNames(t *testing.T) {
|
|
| 609 |
+ // TODO Windows: Port this test |
|
| 610 |
+ if runtime.GOOS == "windows" {
|
|
| 611 |
+ t.Skip("Needs porting to Windows")
|
|
| 612 |
+ } |
|
| 613 |
+ |
|
| 614 |
+ db, dbpath := newTestDb(t) |
|
| 615 |
+ defer destroyTestDb(dbpath) |
|
| 616 |
+ |
|
| 617 |
+ db.Set("/db", "1")
|
|
| 618 |
+ if _, err := db.Set("/myapp", "1"); err != nil {
|
|
| 619 |
+ t.Fatal(err) |
|
| 620 |
+ } |
|
| 621 |
+ |
|
| 622 |
+ db.Walk("/", func(p string, e *Entity) error {
|
|
| 623 |
+ t.Logf("%s\n", p)
|
|
| 624 |
+ return nil |
|
| 625 |
+ }, -1) |
|
| 626 |
+} |
|
| 627 |
+ |
|
| 628 |
+func TestRefPaths(t *testing.T) {
|
|
| 629 |
+ db, dbpath := newTestDb(t) |
|
| 630 |
+ defer destroyTestDb(dbpath) |
|
| 631 |
+ |
|
| 632 |
+ db.Set("/webapp", "1")
|
|
| 633 |
+ |
|
| 634 |
+ db.Set("/db", "2")
|
|
| 635 |
+ db.Set("/webapp/db", "2")
|
|
| 636 |
+ |
|
| 637 |
+ refs := db.RefPaths("2")
|
|
| 638 |
+ if len(refs) != 2 {
|
|
| 639 |
+ t.Fatalf("Expected reference count to be 2, got %d", len(refs))
|
|
| 640 |
+ } |
|
| 641 |
+} |
|
| 642 |
+ |
|
| 643 |
+func TestExistsTrue(t *testing.T) {
|
|
| 644 |
+ db, dbpath := newTestDb(t) |
|
| 645 |
+ defer destroyTestDb(dbpath) |
|
| 646 |
+ |
|
| 647 |
+ db.Set("/testing", "1")
|
|
| 648 |
+ |
|
| 649 |
+ if !db.Exists("/testing") {
|
|
| 650 |
+ t.Fatalf("/tesing should exist")
|
|
| 651 |
+ } |
|
| 652 |
+} |
|
| 653 |
+ |
|
| 654 |
+func TestExistsFalse(t *testing.T) {
|
|
| 655 |
+ // TODO Windows: Port this test |
|
| 656 |
+ if runtime.GOOS == "windows" {
|
|
| 657 |
+ t.Skip("Needs porting to Windows")
|
|
| 658 |
+ } |
|
| 659 |
+ db, dbpath := newTestDb(t) |
|
| 660 |
+ defer destroyTestDb(dbpath) |
|
| 661 |
+ |
|
| 662 |
+ db.Set("/toerhe", "1")
|
|
| 663 |
+ |
|
| 664 |
+ if db.Exists("/testing") {
|
|
| 665 |
+ t.Fatalf("/tesing should not exist")
|
|
| 666 |
+ } |
|
| 667 |
+ |
|
| 668 |
+} |
|
| 669 |
+ |
|
| 670 |
+func TestGetNameWithTrailingSlash(t *testing.T) {
|
|
| 671 |
+ db, dbpath := newTestDb(t) |
|
| 672 |
+ defer destroyTestDb(dbpath) |
|
| 673 |
+ |
|
| 674 |
+ db.Set("/todo", "1")
|
|
| 675 |
+ |
|
| 676 |
+ e := db.Get("/todo/")
|
|
| 677 |
+ if e == nil {
|
|
| 678 |
+ t.Fatalf("Entity should not be nil")
|
|
| 679 |
+ } |
|
| 680 |
+} |
|
| 681 |
+ |
|
| 682 |
+func TestConcurrentWrites(t *testing.T) {
|
|
| 683 |
+ // TODO Windows: Port this test |
|
| 684 |
+ if runtime.GOOS == "windows" {
|
|
| 685 |
+ t.Skip("Needs porting to Windows")
|
|
| 686 |
+ } |
|
| 687 |
+ db, dbpath := newTestDb(t) |
|
| 688 |
+ defer destroyTestDb(dbpath) |
|
| 689 |
+ |
|
| 690 |
+ errs := make(chan error, 2) |
|
| 691 |
+ |
|
| 692 |
+ save := func(name string, id string) {
|
|
| 693 |
+ if _, err := db.Set(fmt.Sprintf("/%s", name), id); err != nil {
|
|
| 694 |
+ errs <- err |
|
| 695 |
+ } |
|
| 696 |
+ errs <- nil |
|
| 697 |
+ } |
|
| 698 |
+ purge := func(id string) {
|
|
| 699 |
+ if _, err := db.Purge(id); err != nil {
|
|
| 700 |
+ errs <- err |
|
| 701 |
+ } |
|
| 702 |
+ errs <- nil |
|
| 703 |
+ } |
|
| 704 |
+ |
|
| 705 |
+ save("/1", "1")
|
|
| 706 |
+ |
|
| 707 |
+ go purge("1")
|
|
| 708 |
+ go save("/2", "2")
|
|
| 709 |
+ |
|
| 710 |
+ any := false |
|
| 711 |
+ for i := 0; i < 2; i++ {
|
|
| 712 |
+ if err := <-errs; err != nil {
|
|
| 713 |
+ any = true |
|
| 714 |
+ t.Log(err) |
|
| 715 |
+ } |
|
| 716 |
+ } |
|
| 717 |
+ if any {
|
|
| 718 |
+ t.Fail() |
|
| 719 |
+ } |
|
| 720 |
+} |
| 0 | 721 |
deleted file mode 100644 |
| ... | ... |
@@ -1,721 +0,0 @@ |
| 1 |
-package graphdb |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "database/sql" |
|
| 5 |
- "fmt" |
|
| 6 |
- "os" |
|
| 7 |
- "path" |
|
| 8 |
- "runtime" |
|
| 9 |
- "strconv" |
|
| 10 |
- "testing" |
|
| 11 |
- |
|
| 12 |
- _ "github.com/mattn/go-sqlite3" |
|
| 13 |
-) |
|
| 14 |
- |
|
| 15 |
-func newTestDb(t *testing.T) (*Database, string) {
|
|
| 16 |
- p := path.Join(os.TempDir(), "sqlite.db") |
|
| 17 |
- conn, err := sql.Open("sqlite3", p)
|
|
| 18 |
- db, err := NewDatabase(conn) |
|
| 19 |
- if err != nil {
|
|
| 20 |
- t.Fatal(err) |
|
| 21 |
- } |
|
| 22 |
- return db, p |
|
| 23 |
-} |
|
| 24 |
- |
|
| 25 |
-func destroyTestDb(dbPath string) {
|
|
| 26 |
- os.Remove(dbPath) |
|
| 27 |
-} |
|
| 28 |
- |
|
| 29 |
-func TestNewDatabase(t *testing.T) {
|
|
| 30 |
- db, dbpath := newTestDb(t) |
|
| 31 |
- if db == nil {
|
|
| 32 |
- t.Fatal("Database should not be nil")
|
|
| 33 |
- } |
|
| 34 |
- db.Close() |
|
| 35 |
- defer destroyTestDb(dbpath) |
|
| 36 |
-} |
|
| 37 |
- |
|
| 38 |
-func TestCreateRootEntity(t *testing.T) {
|
|
| 39 |
- db, dbpath := newTestDb(t) |
|
| 40 |
- defer destroyTestDb(dbpath) |
|
| 41 |
- root := db.RootEntity() |
|
| 42 |
- if root == nil {
|
|
| 43 |
- t.Fatal("Root entity should not be nil")
|
|
| 44 |
- } |
|
| 45 |
-} |
|
| 46 |
- |
|
| 47 |
-func TestGetRootEntity(t *testing.T) {
|
|
| 48 |
- db, dbpath := newTestDb(t) |
|
| 49 |
- defer destroyTestDb(dbpath) |
|
| 50 |
- |
|
| 51 |
- e := db.Get("/")
|
|
| 52 |
- if e == nil {
|
|
| 53 |
- t.Fatal("Entity should not be nil")
|
|
| 54 |
- } |
|
| 55 |
- if e.ID() != "0" {
|
|
| 56 |
- t.Fatalf("Entity id should be 0, got %s", e.ID())
|
|
| 57 |
- } |
|
| 58 |
-} |
|
| 59 |
- |
|
| 60 |
-func TestSetEntityWithDifferentName(t *testing.T) {
|
|
| 61 |
- db, dbpath := newTestDb(t) |
|
| 62 |
- defer destroyTestDb(dbpath) |
|
| 63 |
- |
|
| 64 |
- db.Set("/test", "1")
|
|
| 65 |
- if _, err := db.Set("/other", "1"); err != nil {
|
|
| 66 |
- t.Fatal(err) |
|
| 67 |
- } |
|
| 68 |
-} |
|
| 69 |
- |
|
| 70 |
-func TestSetDuplicateEntity(t *testing.T) {
|
|
| 71 |
- db, dbpath := newTestDb(t) |
|
| 72 |
- defer destroyTestDb(dbpath) |
|
| 73 |
- |
|
| 74 |
- if _, err := db.Set("/foo", "42"); err != nil {
|
|
| 75 |
- t.Fatal(err) |
|
| 76 |
- } |
|
| 77 |
- if _, err := db.Set("/foo", "43"); err == nil {
|
|
| 78 |
- t.Fatalf("Creating an entry with a duplicate path did not cause an error")
|
|
| 79 |
- } |
|
| 80 |
-} |
|
| 81 |
- |
|
| 82 |
-func TestCreateChild(t *testing.T) {
|
|
| 83 |
- db, dbpath := newTestDb(t) |
|
| 84 |
- defer destroyTestDb(dbpath) |
|
| 85 |
- |
|
| 86 |
- child, err := db.Set("/db", "1")
|
|
| 87 |
- if err != nil {
|
|
| 88 |
- t.Fatal(err) |
|
| 89 |
- } |
|
| 90 |
- if child == nil {
|
|
| 91 |
- t.Fatal("Child should not be nil")
|
|
| 92 |
- } |
|
| 93 |
- if child.ID() != "1" {
|
|
| 94 |
- t.Fail() |
|
| 95 |
- } |
|
| 96 |
-} |
|
| 97 |
- |
|
| 98 |
-func TestParents(t *testing.T) {
|
|
| 99 |
- db, dbpath := newTestDb(t) |
|
| 100 |
- defer destroyTestDb(dbpath) |
|
| 101 |
- |
|
| 102 |
- for i := 1; i < 6; i++ {
|
|
| 103 |
- a := strconv.Itoa(i) |
|
| 104 |
- if _, err := db.Set("/"+a, a); err != nil {
|
|
| 105 |
- t.Fatal(err) |
|
| 106 |
- } |
|
| 107 |
- } |
|
| 108 |
- |
|
| 109 |
- for i := 6; i < 11; i++ {
|
|
| 110 |
- a := strconv.Itoa(i) |
|
| 111 |
- p := strconv.Itoa(i - 5) |
|
| 112 |
- |
|
| 113 |
- key := fmt.Sprintf("/%s/%s", p, a)
|
|
| 114 |
- |
|
| 115 |
- if _, err := db.Set(key, a); err != nil {
|
|
| 116 |
- t.Fatal(err) |
|
| 117 |
- } |
|
| 118 |
- |
|
| 119 |
- parents, err := db.Parents(key) |
|
| 120 |
- if err != nil {
|
|
| 121 |
- t.Fatal(err) |
|
| 122 |
- } |
|
| 123 |
- |
|
| 124 |
- if len(parents) != 1 {
|
|
| 125 |
- t.Fatalf("Expected 1 entry for %s got %d", key, len(parents))
|
|
| 126 |
- } |
|
| 127 |
- |
|
| 128 |
- if parents[0] != p {
|
|
| 129 |
- t.Fatalf("ID %s received, %s expected", parents[0], p)
|
|
| 130 |
- } |
|
| 131 |
- } |
|
| 132 |
-} |
|
| 133 |
- |
|
| 134 |
-func TestChildren(t *testing.T) {
|
|
| 135 |
- // TODO Windows: Port this test |
|
| 136 |
- if runtime.GOOS == "windows" {
|
|
| 137 |
- t.Skip("Needs porting to Windows")
|
|
| 138 |
- } |
|
| 139 |
- db, dbpath := newTestDb(t) |
|
| 140 |
- defer destroyTestDb(dbpath) |
|
| 141 |
- |
|
| 142 |
- str := "/" |
|
| 143 |
- for i := 1; i < 6; i++ {
|
|
| 144 |
- a := strconv.Itoa(i) |
|
| 145 |
- if _, err := db.Set(str+a, a); err != nil {
|
|
| 146 |
- t.Fatal(err) |
|
| 147 |
- } |
|
| 148 |
- |
|
| 149 |
- str = str + a + "/" |
|
| 150 |
- } |
|
| 151 |
- |
|
| 152 |
- str = "/" |
|
| 153 |
- for i := 10; i < 30; i++ { // 20 entities
|
|
| 154 |
- a := strconv.Itoa(i) |
|
| 155 |
- if _, err := db.Set(str+a, a); err != nil {
|
|
| 156 |
- t.Fatal(err) |
|
| 157 |
- } |
|
| 158 |
- |
|
| 159 |
- str = str + a + "/" |
|
| 160 |
- } |
|
| 161 |
- entries, err := db.Children("/", 5)
|
|
| 162 |
- if err != nil {
|
|
| 163 |
- t.Fatal(err) |
|
| 164 |
- } |
|
| 165 |
- |
|
| 166 |
- if len(entries) != 11 {
|
|
| 167 |
- t.Fatalf("Expect 11 entries for / got %d", len(entries))
|
|
| 168 |
- } |
|
| 169 |
- |
|
| 170 |
- entries, err = db.Children("/", 20)
|
|
| 171 |
- if err != nil {
|
|
| 172 |
- t.Fatal(err) |
|
| 173 |
- } |
|
| 174 |
- |
|
| 175 |
- if len(entries) != 25 {
|
|
| 176 |
- t.Fatalf("Expect 25 entries for / got %d", len(entries))
|
|
| 177 |
- } |
|
| 178 |
-} |
|
| 179 |
- |
|
| 180 |
-func TestListAllRootChildren(t *testing.T) {
|
|
| 181 |
- // TODO Windows: Port this test |
|
| 182 |
- if runtime.GOOS == "windows" {
|
|
| 183 |
- t.Skip("Needs porting to Windows")
|
|
| 184 |
- } |
|
| 185 |
- |
|
| 186 |
- db, dbpath := newTestDb(t) |
|
| 187 |
- defer destroyTestDb(dbpath) |
|
| 188 |
- |
|
| 189 |
- for i := 1; i < 6; i++ {
|
|
| 190 |
- a := strconv.Itoa(i) |
|
| 191 |
- if _, err := db.Set("/"+a, a); err != nil {
|
|
| 192 |
- t.Fatal(err) |
|
| 193 |
- } |
|
| 194 |
- } |
|
| 195 |
- entries := db.List("/", -1)
|
|
| 196 |
- if len(entries) != 5 {
|
|
| 197 |
- t.Fatalf("Expect 5 entries for / got %d", len(entries))
|
|
| 198 |
- } |
|
| 199 |
-} |
|
| 200 |
- |
|
| 201 |
-func TestListAllSubChildren(t *testing.T) {
|
|
| 202 |
- // TODO Windows: Port this test |
|
| 203 |
- if runtime.GOOS == "windows" {
|
|
| 204 |
- t.Skip("Needs porting to Windows")
|
|
| 205 |
- } |
|
| 206 |
- db, dbpath := newTestDb(t) |
|
| 207 |
- defer destroyTestDb(dbpath) |
|
| 208 |
- |
|
| 209 |
- _, err := db.Set("/webapp", "1")
|
|
| 210 |
- if err != nil {
|
|
| 211 |
- t.Fatal(err) |
|
| 212 |
- } |
|
| 213 |
- child2, err := db.Set("/db", "2")
|
|
| 214 |
- if err != nil {
|
|
| 215 |
- t.Fatal(err) |
|
| 216 |
- } |
|
| 217 |
- child4, err := db.Set("/logs", "4")
|
|
| 218 |
- if err != nil {
|
|
| 219 |
- t.Fatal(err) |
|
| 220 |
- } |
|
| 221 |
- if _, err := db.Set("/db/logs", child4.ID()); err != nil {
|
|
| 222 |
- t.Fatal(err) |
|
| 223 |
- } |
|
| 224 |
- |
|
| 225 |
- child3, err := db.Set("/sentry", "3")
|
|
| 226 |
- if err != nil {
|
|
| 227 |
- t.Fatal(err) |
|
| 228 |
- } |
|
| 229 |
- if _, err := db.Set("/webapp/sentry", child3.ID()); err != nil {
|
|
| 230 |
- t.Fatal(err) |
|
| 231 |
- } |
|
| 232 |
- if _, err := db.Set("/webapp/db", child2.ID()); err != nil {
|
|
| 233 |
- t.Fatal(err) |
|
| 234 |
- } |
|
| 235 |
- |
|
| 236 |
- entries := db.List("/webapp", 1)
|
|
| 237 |
- if len(entries) != 3 {
|
|
| 238 |
- t.Fatalf("Expect 3 entries for / got %d", len(entries))
|
|
| 239 |
- } |
|
| 240 |
- |
|
| 241 |
- entries = db.List("/webapp", 0)
|
|
| 242 |
- if len(entries) != 2 {
|
|
| 243 |
- t.Fatalf("Expect 2 entries for / got %d", len(entries))
|
|
| 244 |
- } |
|
| 245 |
-} |
|
| 246 |
- |
|
| 247 |
-func TestAddSelfAsChild(t *testing.T) {
|
|
| 248 |
- // TODO Windows: Port this test |
|
| 249 |
- if runtime.GOOS == "windows" {
|
|
| 250 |
- t.Skip("Needs porting to Windows")
|
|
| 251 |
- } |
|
| 252 |
- db, dbpath := newTestDb(t) |
|
| 253 |
- defer destroyTestDb(dbpath) |
|
| 254 |
- |
|
| 255 |
- child, err := db.Set("/test", "1")
|
|
| 256 |
- if err != nil {
|
|
| 257 |
- t.Fatal(err) |
|
| 258 |
- } |
|
| 259 |
- if _, err := db.Set("/test/other", child.ID()); err == nil {
|
|
| 260 |
- t.Fatal("Error should not be nil")
|
|
| 261 |
- } |
|
| 262 |
-} |
|
| 263 |
- |
|
| 264 |
-func TestAddChildToNonExistentRoot(t *testing.T) {
|
|
| 265 |
- db, dbpath := newTestDb(t) |
|
| 266 |
- defer destroyTestDb(dbpath) |
|
| 267 |
- |
|
| 268 |
- if _, err := db.Set("/myapp", "1"); err != nil {
|
|
| 269 |
- t.Fatal(err) |
|
| 270 |
- } |
|
| 271 |
- |
|
| 272 |
- if _, err := db.Set("/myapp/proxy/db", "2"); err == nil {
|
|
| 273 |
- t.Fatal("Error should not be nil")
|
|
| 274 |
- } |
|
| 275 |
-} |
|
| 276 |
- |
|
| 277 |
-func TestWalkAll(t *testing.T) {
|
|
| 278 |
- // TODO Windows: Port this test |
|
| 279 |
- if runtime.GOOS == "windows" {
|
|
| 280 |
- t.Skip("Needs porting to Windows")
|
|
| 281 |
- } |
|
| 282 |
- db, dbpath := newTestDb(t) |
|
| 283 |
- defer destroyTestDb(dbpath) |
|
| 284 |
- _, err := db.Set("/webapp", "1")
|
|
| 285 |
- if err != nil {
|
|
| 286 |
- t.Fatal(err) |
|
| 287 |
- } |
|
| 288 |
- child2, err := db.Set("/db", "2")
|
|
| 289 |
- if err != nil {
|
|
| 290 |
- t.Fatal(err) |
|
| 291 |
- } |
|
| 292 |
- child4, err := db.Set("/db/logs", "4")
|
|
| 293 |
- if err != nil {
|
|
| 294 |
- t.Fatal(err) |
|
| 295 |
- } |
|
| 296 |
- if _, err := db.Set("/webapp/logs", child4.ID()); err != nil {
|
|
| 297 |
- t.Fatal(err) |
|
| 298 |
- } |
|
| 299 |
- |
|
| 300 |
- child3, err := db.Set("/sentry", "3")
|
|
| 301 |
- if err != nil {
|
|
| 302 |
- t.Fatal(err) |
|
| 303 |
- } |
|
| 304 |
- if _, err := db.Set("/webapp/sentry", child3.ID()); err != nil {
|
|
| 305 |
- t.Fatal(err) |
|
| 306 |
- } |
|
| 307 |
- if _, err := db.Set("/webapp/db", child2.ID()); err != nil {
|
|
| 308 |
- t.Fatal(err) |
|
| 309 |
- } |
|
| 310 |
- |
|
| 311 |
- child5, err := db.Set("/gograph", "5")
|
|
| 312 |
- if err != nil {
|
|
| 313 |
- t.Fatal(err) |
|
| 314 |
- } |
|
| 315 |
- if _, err := db.Set("/webapp/same-ref-diff-name", child5.ID()); err != nil {
|
|
| 316 |
- t.Fatal(err) |
|
| 317 |
- } |
|
| 318 |
- |
|
| 319 |
- if err := db.Walk("/", func(p string, e *Entity) error {
|
|
| 320 |
- t.Logf("Path: %s Entity: %s", p, e.ID())
|
|
| 321 |
- return nil |
|
| 322 |
- }, -1); err != nil {
|
|
| 323 |
- t.Fatal(err) |
|
| 324 |
- } |
|
| 325 |
-} |
|
| 326 |
- |
|
| 327 |
-func TestGetEntityByPath(t *testing.T) {
|
|
| 328 |
- // TODO Windows: Port this test |
|
| 329 |
- if runtime.GOOS == "windows" {
|
|
| 330 |
- t.Skip("Needs porting to Windows")
|
|
| 331 |
- } |
|
| 332 |
- db, dbpath := newTestDb(t) |
|
| 333 |
- defer destroyTestDb(dbpath) |
|
| 334 |
- _, err := db.Set("/webapp", "1")
|
|
| 335 |
- if err != nil {
|
|
| 336 |
- t.Fatal(err) |
|
| 337 |
- } |
|
| 338 |
- child2, err := db.Set("/db", "2")
|
|
| 339 |
- if err != nil {
|
|
| 340 |
- t.Fatal(err) |
|
| 341 |
- } |
|
| 342 |
- child4, err := db.Set("/logs", "4")
|
|
| 343 |
- if err != nil {
|
|
| 344 |
- t.Fatal(err) |
|
| 345 |
- } |
|
| 346 |
- if _, err := db.Set("/db/logs", child4.ID()); err != nil {
|
|
| 347 |
- t.Fatal(err) |
|
| 348 |
- } |
|
| 349 |
- |
|
| 350 |
- child3, err := db.Set("/sentry", "3")
|
|
| 351 |
- if err != nil {
|
|
| 352 |
- t.Fatal(err) |
|
| 353 |
- } |
|
| 354 |
- if _, err := db.Set("/webapp/sentry", child3.ID()); err != nil {
|
|
| 355 |
- t.Fatal(err) |
|
| 356 |
- } |
|
| 357 |
- if _, err := db.Set("/webapp/db", child2.ID()); err != nil {
|
|
| 358 |
- t.Fatal(err) |
|
| 359 |
- } |
|
| 360 |
- |
|
| 361 |
- child5, err := db.Set("/gograph", "5")
|
|
| 362 |
- if err != nil {
|
|
| 363 |
- t.Fatal(err) |
|
| 364 |
- } |
|
| 365 |
- if _, err := db.Set("/webapp/same-ref-diff-name", child5.ID()); err != nil {
|
|
| 366 |
- t.Fatal(err) |
|
| 367 |
- } |
|
| 368 |
- |
|
| 369 |
- entity := db.Get("/webapp/db/logs")
|
|
| 370 |
- if entity == nil {
|
|
| 371 |
- t.Fatal("Entity should not be nil")
|
|
| 372 |
- } |
|
| 373 |
- if entity.ID() != "4" {
|
|
| 374 |
- t.Fatalf("Expected to get entity with id 4, got %s", entity.ID())
|
|
| 375 |
- } |
|
| 376 |
-} |
|
| 377 |
- |
|
| 378 |
-func TestEnitiesPaths(t *testing.T) {
|
|
| 379 |
- // TODO Windows: Port this test |
|
| 380 |
- if runtime.GOOS == "windows" {
|
|
| 381 |
- t.Skip("Needs porting to Windows")
|
|
| 382 |
- } |
|
| 383 |
- db, dbpath := newTestDb(t) |
|
| 384 |
- defer destroyTestDb(dbpath) |
|
| 385 |
- _, err := db.Set("/webapp", "1")
|
|
| 386 |
- if err != nil {
|
|
| 387 |
- t.Fatal(err) |
|
| 388 |
- } |
|
| 389 |
- child2, err := db.Set("/db", "2")
|
|
| 390 |
- if err != nil {
|
|
| 391 |
- t.Fatal(err) |
|
| 392 |
- } |
|
| 393 |
- child4, err := db.Set("/logs", "4")
|
|
| 394 |
- if err != nil {
|
|
| 395 |
- t.Fatal(err) |
|
| 396 |
- } |
|
| 397 |
- if _, err := db.Set("/db/logs", child4.ID()); err != nil {
|
|
| 398 |
- t.Fatal(err) |
|
| 399 |
- } |
|
| 400 |
- |
|
| 401 |
- child3, err := db.Set("/sentry", "3")
|
|
| 402 |
- if err != nil {
|
|
| 403 |
- t.Fatal(err) |
|
| 404 |
- } |
|
| 405 |
- if _, err := db.Set("/webapp/sentry", child3.ID()); err != nil {
|
|
| 406 |
- t.Fatal(err) |
|
| 407 |
- } |
|
| 408 |
- if _, err := db.Set("/webapp/db", child2.ID()); err != nil {
|
|
| 409 |
- t.Fatal(err) |
|
| 410 |
- } |
|
| 411 |
- |
|
| 412 |
- child5, err := db.Set("/gograph", "5")
|
|
| 413 |
- if err != nil {
|
|
| 414 |
- t.Fatal(err) |
|
| 415 |
- } |
|
| 416 |
- if _, err := db.Set("/webapp/same-ref-diff-name", child5.ID()); err != nil {
|
|
| 417 |
- t.Fatal(err) |
|
| 418 |
- } |
|
| 419 |
- |
|
| 420 |
- out := db.List("/", -1)
|
|
| 421 |
- for _, p := range out.Paths() {
|
|
| 422 |
- t.Log(p) |
|
| 423 |
- } |
|
| 424 |
-} |
|
| 425 |
- |
|
| 426 |
-func TestDeleteRootEntity(t *testing.T) {
|
|
| 427 |
- db, dbpath := newTestDb(t) |
|
| 428 |
- defer destroyTestDb(dbpath) |
|
| 429 |
- |
|
| 430 |
- if err := db.Delete("/"); err == nil {
|
|
| 431 |
- t.Fatal("Error should not be nil")
|
|
| 432 |
- } |
|
| 433 |
-} |
|
| 434 |
- |
|
| 435 |
-func TestDeleteEntity(t *testing.T) {
|
|
| 436 |
- // TODO Windows: Port this test |
|
| 437 |
- if runtime.GOOS == "windows" {
|
|
| 438 |
- t.Skip("Needs porting to Windows")
|
|
| 439 |
- } |
|
| 440 |
- db, dbpath := newTestDb(t) |
|
| 441 |
- defer destroyTestDb(dbpath) |
|
| 442 |
- _, err := db.Set("/webapp", "1")
|
|
| 443 |
- if err != nil {
|
|
| 444 |
- t.Fatal(err) |
|
| 445 |
- } |
|
| 446 |
- child2, err := db.Set("/db", "2")
|
|
| 447 |
- if err != nil {
|
|
| 448 |
- t.Fatal(err) |
|
| 449 |
- } |
|
| 450 |
- child4, err := db.Set("/logs", "4")
|
|
| 451 |
- if err != nil {
|
|
| 452 |
- t.Fatal(err) |
|
| 453 |
- } |
|
| 454 |
- if _, err := db.Set("/db/logs", child4.ID()); err != nil {
|
|
| 455 |
- t.Fatal(err) |
|
| 456 |
- } |
|
| 457 |
- |
|
| 458 |
- child3, err := db.Set("/sentry", "3")
|
|
| 459 |
- if err != nil {
|
|
| 460 |
- t.Fatal(err) |
|
| 461 |
- } |
|
| 462 |
- if _, err := db.Set("/webapp/sentry", child3.ID()); err != nil {
|
|
| 463 |
- t.Fatal(err) |
|
| 464 |
- } |
|
| 465 |
- if _, err := db.Set("/webapp/db", child2.ID()); err != nil {
|
|
| 466 |
- t.Fatal(err) |
|
| 467 |
- } |
|
| 468 |
- |
|
| 469 |
- child5, err := db.Set("/gograph", "5")
|
|
| 470 |
- if err != nil {
|
|
| 471 |
- t.Fatal(err) |
|
| 472 |
- } |
|
| 473 |
- if _, err := db.Set("/webapp/same-ref-diff-name", child5.ID()); err != nil {
|
|
| 474 |
- t.Fatal(err) |
|
| 475 |
- } |
|
| 476 |
- |
|
| 477 |
- if err := db.Delete("/webapp/sentry"); err != nil {
|
|
| 478 |
- t.Fatal(err) |
|
| 479 |
- } |
|
| 480 |
- entity := db.Get("/webapp/sentry")
|
|
| 481 |
- if entity != nil {
|
|
| 482 |
- t.Fatal("Entity /webapp/sentry should be nil")
|
|
| 483 |
- } |
|
| 484 |
-} |
|
| 485 |
- |
|
| 486 |
-func TestCountRefs(t *testing.T) {
|
|
| 487 |
- // TODO Windows: Port this test |
|
| 488 |
- if runtime.GOOS == "windows" {
|
|
| 489 |
- t.Skip("Needs porting to Windows")
|
|
| 490 |
- } |
|
| 491 |
- db, dbpath := newTestDb(t) |
|
| 492 |
- defer destroyTestDb(dbpath) |
|
| 493 |
- |
|
| 494 |
- db.Set("/webapp", "1")
|
|
| 495 |
- |
|
| 496 |
- if db.Refs("1") != 1 {
|
|
| 497 |
- t.Fatal("Expect reference count to be 1")
|
|
| 498 |
- } |
|
| 499 |
- |
|
| 500 |
- db.Set("/db", "2")
|
|
| 501 |
- db.Set("/webapp/db", "2")
|
|
| 502 |
- if db.Refs("2") != 2 {
|
|
| 503 |
- t.Fatal("Expect reference count to be 2")
|
|
| 504 |
- } |
|
| 505 |
-} |
|
| 506 |
- |
|
| 507 |
-func TestPurgeId(t *testing.T) {
|
|
| 508 |
- // TODO Windows: Port this test |
|
| 509 |
- if runtime.GOOS == "windows" {
|
|
| 510 |
- t.Skip("Needs porting to Windows")
|
|
| 511 |
- } |
|
| 512 |
- |
|
| 513 |
- db, dbpath := newTestDb(t) |
|
| 514 |
- defer destroyTestDb(dbpath) |
|
| 515 |
- |
|
| 516 |
- db.Set("/webapp", "1")
|
|
| 517 |
- |
|
| 518 |
- if c := db.Refs("1"); c != 1 {
|
|
| 519 |
- t.Fatalf("Expect reference count to be 1, got %d", c)
|
|
| 520 |
- } |
|
| 521 |
- |
|
| 522 |
- db.Set("/db", "2")
|
|
| 523 |
- db.Set("/webapp/db", "2")
|
|
| 524 |
- |
|
| 525 |
- count, err := db.Purge("2")
|
|
| 526 |
- if err != nil {
|
|
| 527 |
- t.Fatal(err) |
|
| 528 |
- } |
|
| 529 |
- if count != 2 {
|
|
| 530 |
- t.Fatalf("Expected 2 references to be removed, got %d", count)
|
|
| 531 |
- } |
|
| 532 |
-} |
|
| 533 |
- |
|
| 534 |
-// Regression test https://github.com/docker/docker/issues/12334 |
|
| 535 |
-func TestPurgeIdRefPaths(t *testing.T) {
|
|
| 536 |
- // TODO Windows: Port this test |
|
| 537 |
- if runtime.GOOS == "windows" {
|
|
| 538 |
- t.Skip("Needs porting to Windows")
|
|
| 539 |
- } |
|
| 540 |
- db, dbpath := newTestDb(t) |
|
| 541 |
- defer destroyTestDb(dbpath) |
|
| 542 |
- |
|
| 543 |
- db.Set("/webapp", "1")
|
|
| 544 |
- db.Set("/db", "2")
|
|
| 545 |
- |
|
| 546 |
- db.Set("/db/webapp", "1")
|
|
| 547 |
- |
|
| 548 |
- if c := db.Refs("1"); c != 2 {
|
|
| 549 |
- t.Fatalf("Expected 2 reference for webapp, got %d", c)
|
|
| 550 |
- } |
|
| 551 |
- if c := db.Refs("2"); c != 1 {
|
|
| 552 |
- t.Fatalf("Expected 1 reference for db, got %d", c)
|
|
| 553 |
- } |
|
| 554 |
- |
|
| 555 |
- if rp := db.RefPaths("2"); len(rp) != 1 {
|
|
| 556 |
- t.Fatalf("Expected 1 reference path for db, got %d", len(rp))
|
|
| 557 |
- } |
|
| 558 |
- |
|
| 559 |
- count, err := db.Purge("2")
|
|
| 560 |
- if err != nil {
|
|
| 561 |
- t.Fatal(err) |
|
| 562 |
- } |
|
| 563 |
- |
|
| 564 |
- if count != 2 {
|
|
| 565 |
- t.Fatalf("Expected 2 rows to be removed, got %d", count)
|
|
| 566 |
- } |
|
| 567 |
- |
|
| 568 |
- if c := db.Refs("2"); c != 0 {
|
|
| 569 |
- t.Fatalf("Expected 0 reference for db, got %d", c)
|
|
| 570 |
- } |
|
| 571 |
- if c := db.Refs("1"); c != 1 {
|
|
| 572 |
- t.Fatalf("Expected 1 reference for webapp, got %d", c)
|
|
| 573 |
- } |
|
| 574 |
-} |
|
| 575 |
- |
|
| 576 |
-func TestRename(t *testing.T) {
|
|
| 577 |
- // TODO Windows: Port this test |
|
| 578 |
- if runtime.GOOS == "windows" {
|
|
| 579 |
- t.Skip("Needs porting to Windows")
|
|
| 580 |
- } |
|
| 581 |
- db, dbpath := newTestDb(t) |
|
| 582 |
- defer destroyTestDb(dbpath) |
|
| 583 |
- |
|
| 584 |
- db.Set("/webapp", "1")
|
|
| 585 |
- |
|
| 586 |
- if db.Refs("1") != 1 {
|
|
| 587 |
- t.Fatal("Expect reference count to be 1")
|
|
| 588 |
- } |
|
| 589 |
- |
|
| 590 |
- db.Set("/db", "2")
|
|
| 591 |
- db.Set("/webapp/db", "2")
|
|
| 592 |
- |
|
| 593 |
- if db.Get("/webapp/db") == nil {
|
|
| 594 |
- t.Fatal("Cannot find entity at path /webapp/db")
|
|
| 595 |
- } |
|
| 596 |
- |
|
| 597 |
- if err := db.Rename("/webapp/db", "/webapp/newdb"); err != nil {
|
|
| 598 |
- t.Fatal(err) |
|
| 599 |
- } |
|
| 600 |
- if db.Get("/webapp/db") != nil {
|
|
| 601 |
- t.Fatal("Entity should not exist at /webapp/db")
|
|
| 602 |
- } |
|
| 603 |
- if db.Get("/webapp/newdb") == nil {
|
|
| 604 |
- t.Fatal("Cannot find entity at path /webapp/newdb")
|
|
| 605 |
- } |
|
| 606 |
- |
|
| 607 |
-} |
|
| 608 |
- |
|
| 609 |
-func TestCreateMultipleNames(t *testing.T) {
|
|
| 610 |
- // TODO Windows: Port this test |
|
| 611 |
- if runtime.GOOS == "windows" {
|
|
| 612 |
- t.Skip("Needs porting to Windows")
|
|
| 613 |
- } |
|
| 614 |
- |
|
| 615 |
- db, dbpath := newTestDb(t) |
|
| 616 |
- defer destroyTestDb(dbpath) |
|
| 617 |
- |
|
| 618 |
- db.Set("/db", "1")
|
|
| 619 |
- if _, err := db.Set("/myapp", "1"); err != nil {
|
|
| 620 |
- t.Fatal(err) |
|
| 621 |
- } |
|
| 622 |
- |
|
| 623 |
- db.Walk("/", func(p string, e *Entity) error {
|
|
| 624 |
- t.Logf("%s\n", p)
|
|
| 625 |
- return nil |
|
| 626 |
- }, -1) |
|
| 627 |
-} |
|
| 628 |
- |
|
| 629 |
-func TestRefPaths(t *testing.T) {
|
|
| 630 |
- db, dbpath := newTestDb(t) |
|
| 631 |
- defer destroyTestDb(dbpath) |
|
| 632 |
- |
|
| 633 |
- db.Set("/webapp", "1")
|
|
| 634 |
- |
|
| 635 |
- db.Set("/db", "2")
|
|
| 636 |
- db.Set("/webapp/db", "2")
|
|
| 637 |
- |
|
| 638 |
- refs := db.RefPaths("2")
|
|
| 639 |
- if len(refs) != 2 {
|
|
| 640 |
- t.Fatalf("Expected reference count to be 2, got %d", len(refs))
|
|
| 641 |
- } |
|
| 642 |
-} |
|
| 643 |
- |
|
| 644 |
-func TestExistsTrue(t *testing.T) {
|
|
| 645 |
- db, dbpath := newTestDb(t) |
|
| 646 |
- defer destroyTestDb(dbpath) |
|
| 647 |
- |
|
| 648 |
- db.Set("/testing", "1")
|
|
| 649 |
- |
|
| 650 |
- if !db.Exists("/testing") {
|
|
| 651 |
- t.Fatalf("/tesing should exist")
|
|
| 652 |
- } |
|
| 653 |
-} |
|
| 654 |
- |
|
| 655 |
-func TestExistsFalse(t *testing.T) {
|
|
| 656 |
- // TODO Windows: Port this test |
|
| 657 |
- if runtime.GOOS == "windows" {
|
|
| 658 |
- t.Skip("Needs porting to Windows")
|
|
| 659 |
- } |
|
| 660 |
- db, dbpath := newTestDb(t) |
|
| 661 |
- defer destroyTestDb(dbpath) |
|
| 662 |
- |
|
| 663 |
- db.Set("/toerhe", "1")
|
|
| 664 |
- |
|
| 665 |
- if db.Exists("/testing") {
|
|
| 666 |
- t.Fatalf("/tesing should not exist")
|
|
| 667 |
- } |
|
| 668 |
- |
|
| 669 |
-} |
|
| 670 |
- |
|
| 671 |
-func TestGetNameWithTrailingSlash(t *testing.T) {
|
|
| 672 |
- db, dbpath := newTestDb(t) |
|
| 673 |
- defer destroyTestDb(dbpath) |
|
| 674 |
- |
|
| 675 |
- db.Set("/todo", "1")
|
|
| 676 |
- |
|
| 677 |
- e := db.Get("/todo/")
|
|
| 678 |
- if e == nil {
|
|
| 679 |
- t.Fatalf("Entity should not be nil")
|
|
| 680 |
- } |
|
| 681 |
-} |
|
| 682 |
- |
|
| 683 |
-func TestConcurrentWrites(t *testing.T) {
|
|
| 684 |
- // TODO Windows: Port this test |
|
| 685 |
- if runtime.GOOS == "windows" {
|
|
| 686 |
- t.Skip("Needs porting to Windows")
|
|
| 687 |
- } |
|
| 688 |
- db, dbpath := newTestDb(t) |
|
| 689 |
- defer destroyTestDb(dbpath) |
|
| 690 |
- |
|
| 691 |
- errs := make(chan error, 2) |
|
| 692 |
- |
|
| 693 |
- save := func(name string, id string) {
|
|
| 694 |
- if _, err := db.Set(fmt.Sprintf("/%s", name), id); err != nil {
|
|
| 695 |
- errs <- err |
|
| 696 |
- } |
|
| 697 |
- errs <- nil |
|
| 698 |
- } |
|
| 699 |
- purge := func(id string) {
|
|
| 700 |
- if _, err := db.Purge(id); err != nil {
|
|
| 701 |
- errs <- err |
|
| 702 |
- } |
|
| 703 |
- errs <- nil |
|
| 704 |
- } |
|
| 705 |
- |
|
| 706 |
- save("/1", "1")
|
|
| 707 |
- |
|
| 708 |
- go purge("1")
|
|
| 709 |
- go save("/2", "2")
|
|
| 710 |
- |
|
| 711 |
- any := false |
|
| 712 |
- for i := 0; i < 2; i++ {
|
|
| 713 |
- if err := <-errs; err != nil {
|
|
| 714 |
- any = true |
|
| 715 |
- t.Log(err) |
|
| 716 |
- } |
|
| 717 |
- } |
|
| 718 |
- if any {
|
|
| 719 |
- t.Fail() |
|
| 720 |
- } |
|
| 721 |
-} |
| 722 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,27 +0,0 @@ |
| 1 |
-package graphdb |
|
| 2 |
- |
|
| 3 |
-import "sort" |
|
| 4 |
- |
|
| 5 |
-type pathSorter struct {
|
|
| 6 |
- paths []string |
|
| 7 |
- by func(i, j string) bool |
|
| 8 |
-} |
|
| 9 |
- |
|
| 10 |
-func sortByDepth(paths []string) {
|
|
| 11 |
- s := &pathSorter{paths, func(i, j string) bool {
|
|
| 12 |
- return PathDepth(i) > PathDepth(j) |
|
| 13 |
- }} |
|
| 14 |
- sort.Sort(s) |
|
| 15 |
-} |
|
| 16 |
- |
|
| 17 |
-func (s *pathSorter) Len() int {
|
|
| 18 |
- return len(s.paths) |
|
| 19 |
-} |
|
| 20 |
- |
|
| 21 |
-func (s *pathSorter) Swap(i, j int) {
|
|
| 22 |
- s.paths[i], s.paths[j] = s.paths[j], s.paths[i] |
|
| 23 |
-} |
|
| 24 |
- |
|
| 25 |
-func (s *pathSorter) Less(i, j int) bool {
|
|
| 26 |
- return s.by(s.paths[i], s.paths[j]) |
|
| 27 |
-} |
| 28 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,27 @@ |
| 0 |
+package graphdb |
|
| 1 |
+ |
|
| 2 |
+import "sort" |
|
| 3 |
+ |
|
| 4 |
+type pathSorter struct {
|
|
| 5 |
+ paths []string |
|
| 6 |
+ by func(i, j string) bool |
|
| 7 |
+} |
|
| 8 |
+ |
|
| 9 |
+func sortByDepth(paths []string) {
|
|
| 10 |
+ s := &pathSorter{paths, func(i, j string) bool {
|
|
| 11 |
+ return PathDepth(i) > PathDepth(j) |
|
| 12 |
+ }} |
|
| 13 |
+ sort.Sort(s) |
|
| 14 |
+} |
|
| 15 |
+ |
|
| 16 |
+func (s *pathSorter) Len() int {
|
|
| 17 |
+ return len(s.paths) |
|
| 18 |
+} |
|
| 19 |
+ |
|
| 20 |
+func (s *pathSorter) Swap(i, j int) {
|
|
| 21 |
+ s.paths[i], s.paths[j] = s.paths[j], s.paths[i] |
|
| 22 |
+} |
|
| 23 |
+ |
|
| 24 |
+func (s *pathSorter) Less(i, j int) bool {
|
|
| 25 |
+ return s.by(s.paths[i], s.paths[j]) |
|
| 26 |
+} |
| 0 | 27 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,29 @@ |
| 0 |
+package graphdb |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "testing" |
|
| 4 |
+) |
|
| 5 |
+ |
|
| 6 |
+func TestSort(t *testing.T) {
|
|
| 7 |
+ paths := []string{
|
|
| 8 |
+ "/", |
|
| 9 |
+ "/myreallylongname", |
|
| 10 |
+ "/app/db", |
|
| 11 |
+ } |
|
| 12 |
+ |
|
| 13 |
+ sortByDepth(paths) |
|
| 14 |
+ |
|
| 15 |
+ if len(paths) != 3 {
|
|
| 16 |
+ t.Fatalf("Expected 3 parts got %d", len(paths))
|
|
| 17 |
+ } |
|
| 18 |
+ |
|
| 19 |
+ if paths[0] != "/app/db" {
|
|
| 20 |
+ t.Fatalf("Expected /app/db got %s", paths[0])
|
|
| 21 |
+ } |
|
| 22 |
+ if paths[1] != "/myreallylongname" {
|
|
| 23 |
+ t.Fatalf("Expected /myreallylongname got %s", paths[1])
|
|
| 24 |
+ } |
|
| 25 |
+ if paths[2] != "/" {
|
|
| 26 |
+ t.Fatalf("Expected / got %s", paths[2])
|
|
| 27 |
+ } |
|
| 28 |
+} |
| 0 | 29 |
deleted file mode 100644 |
| ... | ... |
@@ -1,29 +0,0 @@ |
| 1 |
-package graphdb |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "testing" |
|
| 5 |
-) |
|
| 6 |
- |
|
| 7 |
-func TestSort(t *testing.T) {
|
|
| 8 |
- paths := []string{
|
|
| 9 |
- "/", |
|
| 10 |
- "/myreallylongname", |
|
| 11 |
- "/app/db", |
|
| 12 |
- } |
|
| 13 |
- |
|
| 14 |
- sortByDepth(paths) |
|
| 15 |
- |
|
| 16 |
- if len(paths) != 3 {
|
|
| 17 |
- t.Fatalf("Expected 3 parts got %d", len(paths))
|
|
| 18 |
- } |
|
| 19 |
- |
|
| 20 |
- if paths[0] != "/app/db" {
|
|
| 21 |
- t.Fatalf("Expected /app/db got %s", paths[0])
|
|
| 22 |
- } |
|
| 23 |
- if paths[1] != "/myreallylongname" {
|
|
| 24 |
- t.Fatalf("Expected /myreallylongname got %s", paths[1])
|
|
| 25 |
- } |
|
| 26 |
- if paths[2] != "/" {
|
|
| 27 |
- t.Fatalf("Expected / got %s", paths[2])
|
|
| 28 |
- } |
|
| 29 |
-} |
| 0 | 3 |
deleted file mode 100644 |
| ... | ... |
@@ -1,32 +0,0 @@ |
| 1 |
-package graphdb |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "path" |
|
| 5 |
- "strings" |
|
| 6 |
-) |
|
| 7 |
- |
|
| 8 |
-// Split p on / |
|
| 9 |
-func split(p string) []string {
|
|
| 10 |
- return strings.Split(p, "/") |
|
| 11 |
-} |
|
| 12 |
- |
|
| 13 |
-// PathDepth returns the depth or number of / in a given path |
|
| 14 |
-func PathDepth(p string) int {
|
|
| 15 |
- parts := split(p) |
|
| 16 |
- if len(parts) == 2 && parts[1] == "" {
|
|
| 17 |
- return 1 |
|
| 18 |
- } |
|
| 19 |
- return len(parts) |
|
| 20 |
-} |
|
| 21 |
- |
|
| 22 |
-func splitPath(p string) (parent, name string) {
|
|
| 23 |
- if p[0] != '/' {
|
|
| 24 |
- p = "/" + p |
|
| 25 |
- } |
|
| 26 |
- parent, name = path.Split(p) |
|
| 27 |
- l := len(parent) |
|
| 28 |
- if parent[l-1] == '/' {
|
|
| 29 |
- parent = parent[:l-1] |
|
| 30 |
- } |
|
| 31 |
- return |
|
| 32 |
-} |
| 33 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,32 @@ |
| 0 |
+package graphdb |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "path" |
|
| 4 |
+ "strings" |
|
| 5 |
+) |
|
| 6 |
+ |
|
| 7 |
+// Split p on / |
|
| 8 |
+func split(p string) []string {
|
|
| 9 |
+ return strings.Split(p, "/") |
|
| 10 |
+} |
|
| 11 |
+ |
|
| 12 |
+// PathDepth returns the depth or number of / in a given path |
|
| 13 |
+func PathDepth(p string) int {
|
|
| 14 |
+ parts := split(p) |
|
| 15 |
+ if len(parts) == 2 && parts[1] == "" {
|
|
| 16 |
+ return 1 |
|
| 17 |
+ } |
|
| 18 |
+ return len(parts) |
|
| 19 |
+} |
|
| 20 |
+ |
|
| 21 |
+func splitPath(p string) (parent, name string) {
|
|
| 22 |
+ if p[0] != '/' {
|
|
| 23 |
+ p = "/" + p |
|
| 24 |
+ } |
|
| 25 |
+ parent, name = path.Split(p) |
|
| 26 |
+ l := len(parent) |
|
| 27 |
+ if parent[l-1] == '/' {
|
|
| 28 |
+ parent = parent[:l-1] |
|
| 29 |
+ } |
|
| 30 |
+ return |
|
| 31 |
+} |
| ... | ... |
@@ -15,68 +15,91 @@ var ( |
| 15 | 15 |
"amazing", |
| 16 | 16 |
"angry", |
| 17 | 17 |
"awesome", |
| 18 |
- "backstabbing", |
|
| 19 |
- "berserk", |
|
| 20 |
- "big", |
|
| 18 |
+ "blissful", |
|
| 21 | 19 |
"boring", |
| 20 |
+ "brave", |
|
| 22 | 21 |
"clever", |
| 23 | 22 |
"cocky", |
| 24 | 23 |
"compassionate", |
| 24 |
+ "competent", |
|
| 25 | 25 |
"condescending", |
| 26 |
+ "confident", |
|
| 26 | 27 |
"cranky", |
| 27 |
- "desperate", |
|
| 28 |
+ "dazzling", |
|
| 28 | 29 |
"determined", |
| 29 | 30 |
"distracted", |
| 30 | 31 |
"dreamy", |
| 31 |
- "drunk", |
|
| 32 | 32 |
"eager", |
| 33 | 33 |
"ecstatic", |
| 34 | 34 |
"elastic", |
| 35 | 35 |
"elated", |
| 36 | 36 |
"elegant", |
| 37 |
- "evil", |
|
| 37 |
+ "eloquent", |
|
| 38 |
+ "epic", |
|
| 38 | 39 |
"fervent", |
| 40 |
+ "festive", |
|
| 41 |
+ "flamboyant", |
|
| 39 | 42 |
"focused", |
| 40 |
- "furious", |
|
| 41 |
- "gigantic", |
|
| 42 |
- "gloomy", |
|
| 43 |
+ "friendly", |
|
| 44 |
+ "frosty", |
|
| 45 |
+ "gallant", |
|
| 46 |
+ "gifted", |
|
| 43 | 47 |
"goofy", |
| 44 |
- "grave", |
|
| 48 |
+ "gracious", |
|
| 45 | 49 |
"happy", |
| 46 |
- "high", |
|
| 50 |
+ "hardcore", |
|
| 51 |
+ "heuristic", |
|
| 47 | 52 |
"hopeful", |
| 48 | 53 |
"hungry", |
| 49 | 54 |
"infallible", |
| 55 |
+ "inspiring", |
|
| 50 | 56 |
"jolly", |
| 51 | 57 |
"jovial", |
| 58 |
+ "keen", |
|
| 52 | 59 |
"kickass", |
| 53 |
- "lonely", |
|
| 60 |
+ "kind", |
|
| 61 |
+ "laughing", |
|
| 54 | 62 |
"loving", |
| 55 |
- "mad", |
|
| 63 |
+ "lucid", |
|
| 64 |
+ "mystifying", |
|
| 56 | 65 |
"modest", |
| 66 |
+ "musing", |
|
| 57 | 67 |
"naughty", |
| 58 |
- "nauseous", |
|
| 68 |
+ "nervous", |
|
| 69 |
+ "nifty", |
|
| 59 | 70 |
"nostalgic", |
| 71 |
+ "objective", |
|
| 72 |
+ "optimistic", |
|
| 60 | 73 |
"peaceful", |
| 61 | 74 |
"pedantic", |
| 62 | 75 |
"pensive", |
| 63 |
- "prickly", |
|
| 76 |
+ "practical", |
|
| 77 |
+ "priceless", |
|
| 78 |
+ "quirky", |
|
| 79 |
+ "quizzical", |
|
| 80 |
+ "relaxed", |
|
| 64 | 81 |
"reverent", |
| 65 | 82 |
"romantic", |
| 66 | 83 |
"sad", |
| 67 | 84 |
"serene", |
| 68 | 85 |
"sharp", |
| 69 |
- "sick", |
|
| 70 | 86 |
"silly", |
| 71 | 87 |
"sleepy", |
| 72 |
- "small", |
|
| 73 | 88 |
"stoic", |
| 74 | 89 |
"stupefied", |
| 75 | 90 |
"suspicious", |
| 76 | 91 |
"tender", |
| 77 | 92 |
"thirsty", |
| 78 |
- "tiny", |
|
| 79 | 93 |
"trusting", |
| 94 |
+ "unruffled", |
|
| 95 |
+ "upbeat", |
|
| 96 |
+ "vibrant", |
|
| 97 |
+ "vigilant", |
|
| 98 |
+ "wizardly", |
|
| 99 |
+ "wonderful", |
|
| 100 |
+ "xenodochial", |
|
| 101 |
+ "youthful", |
|
| 102 |
+ "zealous", |
|
| 80 | 103 |
"zen", |
| 81 | 104 |
} |
| 82 | 105 |
|
| ... | ... |
@@ -83,15 +83,21 @@ func DumpStacks(dir string) (string, error) {
|
| 83 | 83 |
bufferLen *= 2 |
| 84 | 84 |
} |
| 85 | 85 |
buf = buf[:stackSize] |
| 86 |
- path := filepath.Join(dir, fmt.Sprintf(stacksLogNameTemplate, strings.Replace(time.Now().Format(time.RFC3339), ":", "", -1))) |
|
| 87 |
- f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0666) |
|
| 88 |
- if err != nil {
|
|
| 89 |
- return "", errors.Wrap(err, "failed to open file to write the goroutine stacks") |
|
| 86 |
+ var f *os.File |
|
| 87 |
+ if dir != "" {
|
|
| 88 |
+ path := filepath.Join(dir, fmt.Sprintf(stacksLogNameTemplate, strings.Replace(time.Now().Format(time.RFC3339), ":", "", -1))) |
|
| 89 |
+ var err error |
|
| 90 |
+ f, err = os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0666) |
|
| 91 |
+ if err != nil {
|
|
| 92 |
+ return "", errors.Wrap(err, "failed to open file to write the goroutine stacks") |
|
| 93 |
+ } |
|
| 94 |
+ defer f.Close() |
|
| 95 |
+ defer f.Sync() |
|
| 96 |
+ } else {
|
|
| 97 |
+ f = os.Stderr |
|
| 90 | 98 |
} |
| 91 |
- defer f.Close() |
|
| 92 | 99 |
if _, err := f.Write(buf); err != nil {
|
| 93 | 100 |
return "", errors.Wrap(err, "failed to write goroutine stacks") |
| 94 | 101 |
} |
| 95 |
- f.Sync() |
|
| 96 |
- return path, nil |
|
| 102 |
+ return f.Name(), nil |
|
| 97 | 103 |
} |
| ... | ... |
@@ -11,6 +11,7 @@ import ( |
| 11 | 11 |
"net/http" |
| 12 | 12 |
"os" |
| 13 | 13 |
"path/filepath" |
| 14 |
+ "regexp" |
|
| 14 | 15 |
|
| 15 | 16 |
"github.com/Sirupsen/logrus" |
| 16 | 17 |
"github.com/docker/docker/api/types" |
| ... | ... |
@@ -23,6 +24,11 @@ import ( |
| 23 | 23 |
"golang.org/x/net/context" |
| 24 | 24 |
) |
| 25 | 25 |
|
| 26 |
+var ( |
|
| 27 |
+ validFullID = regexp.MustCompile(`^([a-f0-9]{64})$`)
|
|
| 28 |
+ validPartialID = regexp.MustCompile(`^([a-f0-9]{1,64})$`)
|
|
| 29 |
+) |
|
| 30 |
+ |
|
| 26 | 31 |
// Disable deactivates a plugin, which implies that they cannot be used by containers. |
| 27 | 32 |
func (pm *Manager) Disable(name string) error {
|
| 28 | 33 |
p, err := pm.pluginStore.GetByName(name) |
| ... | ... |
@@ -53,12 +59,32 @@ func (pm *Manager) Enable(name string, config *types.PluginEnableConfig) error {
|
| 53 | 53 |
} |
| 54 | 54 |
|
| 55 | 55 |
// Inspect examines a plugin config |
| 56 |
-func (pm *Manager) Inspect(name string) (tp types.Plugin, err error) {
|
|
| 57 |
- p, err := pm.pluginStore.GetByName(name) |
|
| 58 |
- if err != nil {
|
|
| 56 |
+func (pm *Manager) Inspect(refOrID string) (tp types.Plugin, err error) {
|
|
| 57 |
+ // Match on full ID |
|
| 58 |
+ if validFullID.MatchString(refOrID) {
|
|
| 59 |
+ p, err := pm.pluginStore.GetByID(refOrID) |
|
| 60 |
+ if err == nil {
|
|
| 61 |
+ return p.PluginObj, nil |
|
| 62 |
+ } |
|
| 63 |
+ } |
|
| 64 |
+ |
|
| 65 |
+ // Match on full name |
|
| 66 |
+ if pluginName, err := getPluginName(refOrID); err == nil {
|
|
| 67 |
+ if p, err := pm.pluginStore.GetByName(pluginName); err == nil {
|
|
| 68 |
+ return p.PluginObj, nil |
|
| 69 |
+ } |
|
| 70 |
+ } |
|
| 71 |
+ |
|
| 72 |
+ // Match on partial ID |
|
| 73 |
+ if validPartialID.MatchString(refOrID) {
|
|
| 74 |
+ p, err := pm.pluginStore.Search(refOrID) |
|
| 75 |
+ if err == nil {
|
|
| 76 |
+ return p.PluginObj, nil |
|
| 77 |
+ } |
|
| 59 | 78 |
return tp, err |
| 60 | 79 |
} |
| 61 |
- return p.PluginObj, nil |
|
| 80 |
+ |
|
| 81 |
+ return tp, fmt.Errorf("no plugin name or ID associated with %q", refOrID)
|
|
| 62 | 82 |
} |
| 63 | 83 |
|
| 64 | 84 |
func (pm *Manager) pull(ref reference.Named, metaHeader http.Header, authConfig *types.AuthConfig, pluginID string) (types.PluginPrivileges, error) {
|
| ... | ... |
@@ -244,3 +270,18 @@ func (pm *Manager) createFromContext(ctx context.Context, pluginID, pluginDir st |
| 244 | 244 |
|
| 245 | 245 |
return nil |
| 246 | 246 |
} |
| 247 |
+ |
|
| 248 |
+func getPluginName(name string) (string, error) {
|
|
| 249 |
+ named, err := reference.ParseNamed(name) // FIXME: validate |
|
| 250 |
+ if err != nil {
|
|
| 251 |
+ return "", err |
|
| 252 |
+ } |
|
| 253 |
+ if reference.IsNameOnly(named) {
|
|
| 254 |
+ named = reference.WithDefaultTag(named) |
|
| 255 |
+ } |
|
| 256 |
+ ref, ok := named.(reference.NamedTagged) |
|
| 257 |
+ if !ok {
|
|
| 258 |
+ return "", fmt.Errorf("invalid name: %s", named.String())
|
|
| 259 |
+ } |
|
| 260 |
+ return ref.String(), nil |
|
| 261 |
+} |
| ... | ... |
@@ -30,6 +30,13 @@ type ErrNotFound string |
| 30 | 30 |
|
| 31 | 31 |
func (name ErrNotFound) Error() string { return fmt.Sprintf("plugin %q not found", string(name)) }
|
| 32 | 32 |
|
| 33 |
+// ErrAmbiguous indicates that a plugin was not found locally. |
|
| 34 |
+type ErrAmbiguous string |
|
| 35 |
+ |
|
| 36 |
+func (name ErrAmbiguous) Error() string {
|
|
| 37 |
+ return fmt.Sprintf("multiple plugins found for %q", string(name))
|
|
| 38 |
+} |
|
| 39 |
+ |
|
| 33 | 40 |
// GetByName retreives a plugin by name. |
| 34 | 41 |
func (ps *Store) GetByName(name string) (*v2.Plugin, error) {
|
| 35 | 42 |
ps.RLock() |
| ... | ... |
@@ -253,3 +260,25 @@ func (ps *Store) CallHandler(p *v2.Plugin) {
|
| 253 | 253 |
} |
| 254 | 254 |
} |
| 255 | 255 |
} |
| 256 |
+ |
|
| 257 |
+// Search retreives a plugin by ID Prefix |
|
| 258 |
+// If no plugin is found, then ErrNotFound is returned |
|
| 259 |
+// If multiple plugins are found, then ErrAmbiguous is returned |
|
| 260 |
+func (ps *Store) Search(partialID string) (*v2.Plugin, error) {
|
|
| 261 |
+ ps.RLock() |
|
| 262 |
+ defer ps.RUnlock() |
|
| 263 |
+ |
|
| 264 |
+ var found *v2.Plugin |
|
| 265 |
+ for id, p := range ps.plugins {
|
|
| 266 |
+ if strings.HasPrefix(id, partialID) {
|
|
| 267 |
+ if found != nil {
|
|
| 268 |
+ return nil, ErrAmbiguous(partialID) |
|
| 269 |
+ } |
|
| 270 |
+ found = p |
|
| 271 |
+ } |
|
| 272 |
+ } |
|
| 273 |
+ if found == nil {
|
|
| 274 |
+ return nil, ErrNotFound(partialID) |
|
| 275 |
+ } |
|
| 276 |
+ return found, nil |
|
| 277 |
+} |
| ... | ... |
@@ -25,7 +25,6 @@ type ContainerOptions struct {
|
| 25 | 25 |
attach opts.ListOpts |
| 26 | 26 |
volumes opts.ListOpts |
| 27 | 27 |
tmpfs opts.ListOpts |
| 28 |
- mounts opts.MountOpt |
|
| 29 | 28 |
blkioWeightDevice WeightdeviceOpt |
| 30 | 29 |
deviceReadBps ThrottledeviceOpt |
| 31 | 30 |
deviceWriteBps ThrottledeviceOpt |
| ... | ... |
@@ -217,7 +216,6 @@ func AddFlags(flags *pflag.FlagSet) *ContainerOptions {
|
| 217 | 217 |
flags.Var(&copts.tmpfs, "tmpfs", "Mount a tmpfs directory") |
| 218 | 218 |
flags.Var(&copts.volumesFrom, "volumes-from", "Mount volumes from the specified container(s)") |
| 219 | 219 |
flags.VarP(&copts.volumes, "volume", "v", "Bind mount a volume") |
| 220 |
- flags.Var(&copts.mounts, "mount", "Attach a filesystem mount to the container") |
|
| 221 | 220 |
|
| 222 | 221 |
// Health-checking |
| 223 | 222 |
flags.StringVar(&copts.healthCmd, "health-cmd", "", "Command to run to check health") |
| ... | ... |
@@ -357,8 +355,6 @@ func Parse(flags *pflag.FlagSet, copts *ContainerOptions) (*container.Config, *c |
| 357 | 357 |
} |
| 358 | 358 |
} |
| 359 | 359 |
|
| 360 |
- mounts := copts.mounts.Value() |
|
| 361 |
- |
|
| 362 | 360 |
var binds []string |
| 363 | 361 |
volumes := copts.volumes.GetMap() |
| 364 | 362 |
// add any bind targets to the list of container volumes |
| ... | ... |
@@ -623,7 +619,6 @@ func Parse(flags *pflag.FlagSet, copts *ContainerOptions) (*container.Config, *c |
| 623 | 623 |
Tmpfs: tmpfs, |
| 624 | 624 |
Sysctls: copts.sysctls.GetAll(), |
| 625 | 625 |
Runtime: copts.runtime, |
| 626 |
- Mounts: mounts, |
|
| 627 | 626 |
} |
| 628 | 627 |
|
| 629 | 628 |
// only set this value if the user provided the flag, else it should default to nil |