diff --git a/api.go b/api.go index 23a63a4b33..11c722f507 100644 --- a/api.go +++ b/api.go @@ -52,6 +52,7 @@ func ListenAndServe(addr string, srv *Server) error { if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } else { + w.Header().Set("Content-Type", "application/json") w.Write(b) } }) @@ -81,6 +82,7 @@ func ListenAndServe(addr string, srv *Server) error { if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } else { + w.Header().Set("Content-Type", "application/json") w.Write(b) } } else { @@ -95,6 +97,7 @@ func ListenAndServe(addr string, srv *Server) error { if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } else { + w.Header().Set("Content-Type", "application/json") w.Write(b) } }) @@ -136,6 +139,7 @@ func ListenAndServe(addr string, srv *Server) error { log.Println(r.Method, r.RequestURI) if err := r.ParseForm(); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) + return } all := r.Form.Get("all") filter := r.Form.Get("filter") @@ -144,11 +148,13 @@ func ListenAndServe(addr string, srv *Server) error { outs, err := srv.Images(all, filter, quiet) if err != nil { httpError(w, err) + return } b, err := json.Marshal(outs) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } else { + w.Header().Set("Content-Type", "application/json") w.Write(b) } }) @@ -160,6 +166,7 @@ func ListenAndServe(addr string, srv *Server) error { if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } else { + w.Header().Set("Content-Type", "application/json") w.Write(b) } }) @@ -171,11 +178,13 @@ func ListenAndServe(addr string, srv *Server) error { outs, err := srv.ImageHistory(name) if err != nil { httpError(w, err) + return } b, err := json.Marshal(outs) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } else { + w.Header().Set("Content-Type", "application/json") w.Write(b) } }) @@ -187,11 +196,13 @@ func ListenAndServe(addr string, srv *Server) error { changesStr, err := srv.ContainerChanges(name) if err != nil { httpError(w, err) + return } b, err := json.Marshal(changesStr) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } else { + w.Header().Set("Content-Type", "application/json") w.Write(b) } }) @@ -200,17 +211,20 @@ func ListenAndServe(addr string, srv *Server) error { log.Println(r.Method, r.RequestURI) if err := r.ParseForm(); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) + return } vars := mux.Vars(r) name := vars["name"] out, err := srv.ContainerPort(name, r.Form.Get("port")) if err != nil { httpError(w, err) + return } b, err := json.Marshal(ApiPort{out}) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } else { + w.Header().Set("Content-Type", "application/json") w.Write(b) } @@ -220,6 +234,7 @@ func ListenAndServe(addr string, srv *Server) error { log.Println(r.Method, r.RequestURI) if err := r.ParseForm(); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) + return } all := r.Form.Get("all") notrunc := r.Form.Get("notrunc") @@ -234,6 +249,7 @@ func ListenAndServe(addr string, srv *Server) error { if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } else { + w.Header().Set("Content-Type", "application/json") w.Write(b) } }) @@ -242,6 +258,7 @@ func ListenAndServe(addr string, srv *Server) error { log.Println(r.Method, r.RequestURI) if err := r.ParseForm(); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) + return } repo := r.Form.Get("repo") tag := r.Form.Get("tag") @@ -259,62 +276,68 @@ func ListenAndServe(addr string, srv *Server) error { w.WriteHeader(http.StatusCreated) }) + r.Path("/commit").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + log.Println(r.Method, r.RequestURI) + if err := r.ParseForm(); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + var config Config + if err := json.NewDecoder(r.Body).Decode(&config); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + repo := r.Form.Get("repo") + tag := r.Form.Get("tag") + container := r.Form.Get("container") + author := r.Form.Get("author") + comment := r.Form.Get("comment") + id, err := srv.ContainerCommit(container, repo, tag, author, comment, &config) + if err != nil { + httpError(w, err) + return + } + b, err := json.Marshal(ApiId{id}) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } else { + w.Header().Set("Content-Type", "application/json") + w.Write(b) + } + }) + r.Path("/images").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { log.Println(r.Method, r.RequestURI) if err := r.ParseForm(); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) + return } src := r.Form.Get("fromSrc") image := r.Form.Get("fromImage") - container := r.Form.Get("fromContainer") repo := r.Form.Get("repo") tag := r.Form.Get("tag") - if container != "" { //commit - var config Config - if err := json.NewDecoder(r.Body).Decode(&config); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return + file, rwc, err := hijackServer(w) + if file != nil { + defer file.Close() + } + if rwc != nil { + defer rwc.Close() + } + if err != nil { + httpError(w, err) + return + } + fmt.Fprintf(file, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n") + if image != "" { //pull + if err := srv.ImagePull(image, file); err != nil { + fmt.Fprintln(file, "Error: "+err.Error()) } - author := r.Form.Get("author") - comment := r.Form.Get("comment") - - id, err := srv.ContainerCommit(container, repo, tag, author, comment, &config) - if err != nil { - httpError(w, err) + } else { //import + if err := srv.ImageImport(src, repo, tag, file); err != nil { + fmt.Fprintln(file, "Error: "+err.Error()) } - b, err := json.Marshal(ApiId{id}) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - } else { - w.Write(b) - } - } else if image != "" || src != "" { - file, rwc, err := hijackServer(w) - if file != nil { - defer file.Close() - } - if rwc != nil { - defer rwc.Close() - } - if err != nil { - httpError(w, err) - return - } - fmt.Fprintf(file, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n") - - if image != "" { //pull - if err := srv.ImagePull(image, file); err != nil { - fmt.Fprintln(file, "Error: "+err.Error()) - } - } else { //import - if err := srv.ImageImport(src, repo, tag, file); err != nil { - fmt.Fprintln(file, "Error: "+err.Error()) - } - } - } else { - w.WriteHeader(http.StatusNotFound) } }) @@ -364,6 +387,7 @@ func ListenAndServe(addr string, srv *Server) error { if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } else { + w.Header().Set("Content-Type", "application/json") w.Write(b) } }) @@ -372,6 +396,7 @@ func ListenAndServe(addr string, srv *Server) error { log.Println(r.Method, r.RequestURI) if err := r.ParseForm(); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) + return } t, err := strconv.Atoi(r.Form.Get("t")) if err != nil || t < 0 { @@ -390,6 +415,7 @@ func ListenAndServe(addr string, srv *Server) error { log.Println(r.Method, r.RequestURI) if err := r.ParseForm(); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) + return } vars := mux.Vars(r) name := vars["name"] @@ -430,6 +456,7 @@ func ListenAndServe(addr string, srv *Server) error { log.Println(r.Method, r.RequestURI) if err := r.ParseForm(); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) + return } t, err := strconv.Atoi(r.Form.Get("t")) if err != nil || t < 0 { @@ -452,11 +479,13 @@ func ListenAndServe(addr string, srv *Server) error { status, err := srv.ContainerWait(name) if err != nil { httpError(w, err) + return } b, err := json.Marshal(ApiWait{status}) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } else { + w.Header().Set("Content-Type", "application/json") w.Write(b) } }) @@ -465,6 +494,7 @@ func ListenAndServe(addr string, srv *Server) error { log.Println(r.Method, r.RequestURI) if err := r.ParseForm(); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) + return } logs := r.Form.Get("logs") stream := r.Form.Get("stream") @@ -500,11 +530,13 @@ func ListenAndServe(addr string, srv *Server) error { container, err := srv.ContainerInspect(name) if err != nil { httpError(w, err) + return } b, err := json.Marshal(container) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } else { + w.Header().Set("Content-Type", "application/json") w.Write(b) } }) @@ -517,11 +549,13 @@ func ListenAndServe(addr string, srv *Server) error { image, err := srv.ImageInspect(name) if err != nil { httpError(w, err) + return } b, err := json.Marshal(image) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } else { + w.Header().Set("Content-Type", "application/json") w.Write(b) } }) diff --git a/commands.go b/commands.go index 3103f52766..510ab849cf 100644 --- a/commands.go +++ b/commands.go @@ -541,7 +541,6 @@ func CmdKill(args ...string) error { return nil } -/* /!\ W.I.P /!\ */ func CmdImport(args ...string) error { cmd := Subcmd("import", "URL|- [REPOSITORY [TAG]]", "Create a new filesystem image from the contents of a tarball") @@ -614,7 +613,7 @@ func CmdPush(args ...string) error { out.Username, name) } - if err := hijack("POST", "/images"+name+"/pull", false); err != nil { + if err := hijack("POST", "/images"+name+"/push", false); err != nil { return err } return nil @@ -764,7 +763,7 @@ func CmdCommit(args ...string) error { } v := url.Values{} - v.Set("fromContainer", name) + v.Set("container", name) v.Set("repo", repository) v.Set("tag", tag) v.Set("comment", *flComment) @@ -777,7 +776,7 @@ func CmdCommit(args ...string) error { } } - body, _, err := call("POST", "/images?"+v.Encode(), config) + body, _, err := call("POST", "/commit?"+v.Encode(), config) if err != nil { return err } @@ -1072,6 +1071,7 @@ func call(method, path string, data interface{}) ([]byte, int, error) { } params = bytes.NewBuffer(buf) } + req, err := http.NewRequest(method, "http://0.0.0.0:4243"+path, params) if err != nil { return nil, -1, err diff --git a/docs/sources/conf.py b/docs/sources/conf.py index c05c7d10a4..4c54d8bb62 100644 --- a/docs/sources/conf.py +++ b/docs/sources/conf.py @@ -25,7 +25,7 @@ import sys, os # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = [] +extensions = ['sphinxcontrib.httpdomain'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/docs/sources/index.rst b/docs/sources/index.rst index 4e724a0cd2..bbd879334c 100644 --- a/docs/sources/index.rst +++ b/docs/sources/index.rst @@ -16,7 +16,8 @@ This documentation has the following resources: contributing/index commandline/index registry/index + remote-api/index faq -.. image:: http://www.docker.io/_static/lego_docker.jpg \ No newline at end of file +.. image:: http://www.docker.io/_static/lego_docker.jpg diff --git a/docs/sources/remote-api/api.rst b/docs/sources/remote-api/api.rst new file mode 100644 index 0000000000..361289010b --- /dev/null +++ b/docs/sources/remote-api/api.rst @@ -0,0 +1,878 @@ +================= +Docker Remote API +================= + +.. contents:: Table of Contents + +1. Brief introduction +===================== + +- The Remote API is replacing rcli +- Default port in the docker deamon is 4243 +- The API tends to be REST, but for some complex commands, like attach or pull, the HTTP connection in hijacked to transport stdout stdin and stderr + +2. Endpoints +============ + +2.1 Containers +-------------- + +List containers +*************** + +.. http:get:: /containers + + List containers + + **Example request**: + + .. sourcecode:: http + + GET /containers?notrunc=1&all=1&quiet=0 HTTP/1.1 + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + + [ + { + "Id": "8dfafdbc3a40", + "Image": "base:latest", + "Command": "echo 1", + "Created": 1367854155, + "Status": "Exit 0" + }, + { + "Id": "9cd87474be90", + "Image": "base:latest", + "Command": "echo 2", + "Created": 1367854155, + "Status": "Exit 0" + }, + { + "Id": "3176a2479c92", + "Image": "base:latest", + "Command": "echo 3", + "Created": 1367854154, + "Status": "Exit 0" + }, + { + "Id": "4cb07b47f9fb", + "Image": "base:latest", + "Command": "echo 4", + "Created": 1367854152, + "Status": "Exit 0" + } + ] + + :query quiet: 1 or 0, Only display numeric IDs. Not quiet by default + :query all: 1 or 0, Show all containers. Only running containers are shown by default + :query notrunc: 1 or 0, Don't truncate output. Output is truncated by default + :query n: limit number, Show n last created containers, include non-running ones. + :statuscode 200: no error + :statuscode 500: server error + + +Create a container +****************** + +.. http:post:: /containers + + Create a container + + **Example request**: + + .. sourcecode:: http + + POST /containers HTTP/1.1 + + { + "Hostname":"", + "User":"", + "Memory":0, + "MemorySwap":0, + "AttachStdin":false, + "AttachStdout":true, + "AttachStderr":true, + "PortSpecs":null, + "Tty":false, + "OpenStdin":false, + "StdinOnce":false, + "Env":null, + "Cmd":[ + "date" + ], + "Dns":null, + "Image":"base", + "Volumes":{}, + "VolumesFrom":"" + } + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + + { + "Id":"e90e34656806" + "Warnings":[] + } + + :jsonparam config: the container's configuration + :statuscode 200: no error + :statuscode 400: no such container + :statuscode 500: server error + + +Inspect a container +******************* + +.. http:get:: /containers/(id) + + Return low-level information on the container ``id`` + + **Example request**: + + .. sourcecode:: http + + GET /containers/4fa6e0f0c678 HTTP/1.1 + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + + { + "Id": "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2", + "Created": "2013-05-07T14:51:42.041847+02:00", + "Path": "date", + "Args": [], + "Config": { + "Hostname": "4fa6e0f0c678", + "User": "", + "Memory": 0, + "MemorySwap": 0, + "AttachStdin": false, + "AttachStdout": true, + "AttachStderr": true, + "PortSpecs": null, + "Tty": false, + "OpenStdin": false, + "StdinOnce": false, + "Env": null, + "Cmd": [ + "date" + ], + "Dns": null, + "Image": "base", + "Volumes": {}, + "VolumesFrom": "" + }, + "State": { + "Running": false, + "Pid": 0, + "ExitCode": 0, + "StartedAt": "2013-05-07T14:51:42.087658+02:01360", + "Ghost": false + }, + "Image": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc", + "NetworkSettings": { + "IpAddress": "", + "IpPrefixLen": 0, + "Gateway": "", + "Bridge": "", + "PortMapping": null + }, + "SysInitPath": "/home/kitty/go/src/github.com/dotcloud/docker/bin/docker", + "ResolvConfPath": "/etc/resolv.conf", + "Volumes": {} + } + + :statuscode 200: no error + :statuscode 400: no such container + :statuscode 500: server error + + +Inspect changes on a container's filesystem +******************************************* + +.. http:get:: /containers/(id)/changes + + Inspect changes on container ``id`` 's filesystem + + **Example request**: + + .. sourcecode:: http + + GET /containers/4fa6e0f0c678/changes HTTP/1.1 + + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + + [ + "C /dev", + "A /dev/kmsg" + ] + + :statuscode 200: no error + :statuscode 400: no such container + :statuscode 500: server error + + +Export a container +****************** + +.. http:get:: /containers/(id)/export + + Export the contents of container ``id`` + + **Example request**: + + .. sourcecode:: http + + GET /containers/4fa6e0f0c678/export HTTP/1.1 + + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + Content-Type: raw-stream-hijack + + {{ STREAM }} + + :statuscode 200: no error + :statuscode 400: no such container + :statuscode 500: server error + + +Map container's private ports +***************************** + +.. http:get:: /containers/(id)/port + + Map a private port of container ``id`` + + **Example request**: + + .. sourcecode:: http + + GET /containers/4fa6e0f0c678/port?port=80 HTTP/1.1 + + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + + {"Port":"80"} + + :query port: the container private port you want to get + :statuscode 200: no error + :statuscode 400: no such container + :statuscode 500: server error + + +Start a container +***************** + +.. http:post:: /containers/(id)/start + + Start the container ``id`` + + **Example request**: + + .. sourcecode:: http + + POST /containers/e90e34656806/start HTTP/1.1 + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + + :statuscode 200: no error + :statuscode 400: no such container + :statuscode 500: server error + + +Stop a contaier +*************** + +.. http:post:: /containers/(id)/stop + + Stop the container ``id`` + + **Example request**: + + .. sourcecode:: http + + POST /containers/e90e34656806/stop?t=5 HTTP/1.1 + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + + :query t: number of seconds to wait before killing the container + :statuscode 200: no error + :statuscode 400: no such container + :statuscode 500: server error + + +Restart a container +******************* + +.. http:post:: /containers/(id)/restart + + Restart the container ``id`` + + **Example request**: + + .. sourcecode:: http + + POST /containers/e90e34656806/restart?t=5 HTTP/1.1 + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + + :query t: number of seconds to wait before killing the container + :statuscode 200: no error + :statuscode 400: no such container + :statuscode 500: server error + + +Kill a container +**************** + +.. http:post:: /containers/(id)/kill + + Kill the container ``id`` + + **Example request**: + + .. sourcecode:: http + + POST /containers/e90e34656806/kill HTTP/1.1 + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + + :statuscode 200: no error + :statuscode 400: no such container + :statuscode 500: server error + + +Attach to a container +********************* + +.. http:post:: /containers/(id)/attach + + Stop the container ``id`` + + **Example request**: + + .. sourcecode:: http + + POST /containers/16253994b7c4/attach?logs=1&stream=0&stdout=1 HTTP/1.1 + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + Content-Type: raw-stream-hijack + + {{ STREAM }} + + :query logs: 1 or 0, return logs. Default 0 + :query stream: 1 or 0, return stream. Default 0 + :query stdin: 1 or 0, if stream=1, attach to stdin. Default 0 + :query stdout: 1 or 0, if logs=1, return stdout log, if stream=1, attach to stdout. Default 0 + :query stderr: 1 or 0, if logs=1, return stderr log, if stream=1, attach to stderr. Default 0 + :statuscode 200: no error + :statuscode 400: no such container + :statuscode 500: server error + + +Wait a container +**************** + +.. http:post:: /containers/(id)/wait + + Block until container ``id`` stops, then returns the exit code + + **Example request**: + + .. sourcecode:: http + + POST /containers/16253994b7c4/wait HTTP/1.1 + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + + {"StatusCode":0} + + :statuscode 200: no error + :statuscode 400: no such container + :statuscode 500: server error + + +Remove a container +******************* + +.. http:delete:: /container/(id) + + Remove the container ``id`` from the filesystem + + **Example request**: + + .. sourcecode:: http + + DELETE /containers/16253994b7c4?v=1 HTTP/1.1 + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + + :query v: 1 or 0, Remove the volumes associated to the container. Default 0 + :statuscode 200: no error + :statuscode 400: no such container + :statuscode 500: server error + + +2.2 Images +---------- + +List Images +*********** + +.. http:get:: /images + + List images + + **Example request**: + + .. sourcecode:: http + + GET /images?all=0&quiet=0 HTTP/1.1 + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + + [ + { + "Repository":"base", + "Tag":"ubuntu-12.10", + "Id":"b750fe79269d", + "Created":1364102658 + }, + { + "Repository":"base", + "Tag":"ubuntu-quantal", + "Id":"b750fe79269d", + "Created":1364102658 + } + ] + + :query quiet: 1 or 0, Only display numeric IDs. Not quiet by default + :query all: 1 or 0, Show all containers. Only running containers are shown by default + :statuscode 200: no error + :statuscode 500: server error + + +Create an image +*************** + +.. http:post:: /images + + Create an image, either by pull it from the registry or by importing it + + **Example request**: + + .. sourcecode:: http + + POST /images?fromImage=base HTTP/1.1 + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + Content-Type: raw-stream-hijack + + {{ STREAM }} + + :query fromImage: name of the image to pull + :query fromSrc: source to import, - means stdin + :query repo: repository + :query tag: tag + :statuscode 200: no error + :statuscode 500: server error + +Inspect an image +**************** + +.. http:get:: /images/(name) + + Return low-level information on the image ``name`` + + **Example request**: + + .. sourcecode:: http + + GET /images/base HTTP/1.1 + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + + { + "id":"b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc", + "parent":"27cf784147099545", + "created":"2013-03-23T22:24:18.818426-07:00", + "container":"3d67245a8d72ecf13f33dffac9f79dcdf70f75acb84d308770391510e0c23ad0", + "container_config": + { + "Hostname":"", + "User":"", + "Memory":0, + "MemorySwap":0, + "AttachStdin":false, + "AttachStdout":false, + "AttachStderr":false, + "PortSpecs":null, + "Tty":true, + "OpenStdin":true, + "StdinOnce":false, + "Env":null, + "Cmd": ["/bin/bash"] + ,"Dns":null, + "Image":"base", + "Volumes":null, + "VolumesFrom":"" + } + } + + :statuscode 200: no error + :statuscode 404: no such image + :statuscode 500: server error + + +Get the history of an image +*************************** + +.. http:get:: /images/(name) + + Return the history of the image ``name`` + + **Example request**: + + .. sourcecode:: http + + GET /images/base/history HTTP/1.1 + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + + [ + { + "Id":"b750fe79269d", + "Created":1364102658, + "CreatedBy":"/bin/bash" + }, + { + "Id":"27cf78414709", + "Created":1364068391, + "CreatedBy":"" + } + ] + + :statuscode 200: no error + :statuscode 404: no such image + :statuscode 500: server error + + +Push an image on the registry +***************************** + +.. http:post:: /images/(name)/push + + Push the image ``name`` on the registry + + **Example request**: + + .. sourcecode:: http + + POST /images/test/push HTTP/1.1 + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + Content-Type: raw-stream-hijack + + {{ STREAM }} + + :statuscode 200: no error + :statuscode 404: no such image + :statuscode 500: server error + + +Tag an image into a repository +****************************** + +.. http:post:: /images/(name)/tag + + Tag the image ``name`` into a repository + + **Example request**: + + .. sourcecode:: http + + POST /images/test/tag?repo=myrepo&force=0 HTTP/1.1 + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + + :query repo: The repository to tag in + :query force: 1 or 0, default 0 + :statuscode 200: no error + :statuscode 404: no such image + :statuscode 500: server error + + +Remove an image +*************** + +.. http:delete:: /images/(name) + + Remove the image ``name`` from the filesystem + + **Example request**: + + .. sourcecode:: http + + DELETE /images/test HTTP/1.1 + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + + :statuscode 200: no error + :statuscode 404: no such image + :statuscode 500: server error + + +2.3 Misc +-------- + +Get default username and email +****************************** + +.. http:get:: /auth + + Get the default username and email + + **Example request**: + + .. sourcecode:: http + + GET /auth HTTP/1.1 + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + + { + "username":"hannibal", + "email":"hannibal@a-team.com" + } + + :statuscode 200: no error + :statuscode 500: server error + + +Set auth configuration +********************** + +.. http:post:: /auth + + Get the default username and email + + **Example request**: + + .. sourcecode:: http + + POST /auth HTTP/1.1 + + { + "username":"hannibal", + "password:"xxxx", + "email":"hannibal@a-team.com" + } + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + + :statuscode 200: no error + :statuscode 500: server error + + +Display system-wide information +******************************* + +.. http:get:: /info + + Display system-wide information + + **Example request**: + + .. sourcecode:: http + + GET /info HTTP/1.1 + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + + { + "Containers":11, + "Version":"0.2.2", + "Images":16, + "Debug":false + } + + :statuscode 200: no error + :statuscode 500: server error + +Show the docker version information +*********************************** + +.. http:get:: /version + + Show the docker version information + + **Example request**: + + .. sourcecode:: http + + GET /version HTTP/1.1 + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + + { + "Version":"0.2.2", + "GitCommit":"5a2a5cc+CHANGES", + "MemoryLimit":true, + "SwapLimit":false + } + + :statuscode 200: no error + :statuscode 500: server error + + +Create a new image from a container's changes +********************************************* + +.. http:post:: /commit + + Create a new image from a container's changes + + **Example request**: + + .. sourcecode:: http + + POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1 + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + Content-Type: raw-stream-hijack + + {{ STREAM }} + + :query container: source container + :query repo: repository + :query tag: tag + :query m: commit message + :query author: author (eg. "John Hannibal Smith ") + :query run: config automatically applied when the image is run. (ex: {"Cmd": ["cat", "/world"], "PortSpecs":["22"]}) + :statuscode 200: no error + :statuscode 404: no such container + :statuscode 500: server error + + +3. Going further +================ + +3.1 Inside 'docker run' +----------------------- + +Here are the steps of 'docker run' : + +* Create the container +* If the status code is 404, it means the image doesn't exists: + * Try to pull it + * Then retry to create the container +* Start the container +* If you are not in detached mode: + * Attach to the container, using logs=1 (to have stdout and stderr from the container's start) and stream=1 + * Call /wait to get the exit code and exit with it + + +3.2 Hijacking +------------- + +In this first version of the API, some of the endpoints, like /attach, /pull or /push uses hijacking to transport stdin, +stdout and stderr on the same socket. This might change in the future. diff --git a/docs/sources/remote-api/index.rst b/docs/sources/remote-api/index.rst new file mode 100644 index 0000000000..5b3b790b56 --- /dev/null +++ b/docs/sources/remote-api/index.rst @@ -0,0 +1,15 @@ +:title: docker Remote API documentation +:description: Documentation for docker Remote API +:keywords: docker, rest, api, http + + + +Remote API +========== + +Contents: + +.. toctree:: + :maxdepth: 2 + + api