Bladeren bron

first draft of the doc, split commit and fix some issues in spi.go

Victor Vieux 12 jaren geleden
bovenliggende
commit
0b6c79b303
6 gewijzigde bestanden met toevoegingen van 977 en 49 verwijderingen
  1. 77 43
      api.go
  2. 4 4
      commands.go
  3. 1 1
      docs/sources/conf.py
  4. 2 1
      docs/sources/index.rst
  5. 878 0
      docs/sources/remote-api/api.rst
  6. 15 0
      docs/sources/remote-api/index.rst

+ 77 - 43
api.go

@@ -52,6 +52,7 @@ func ListenAndServe(addr string, srv *Server) error {
 		if err != nil {
 		if err != nil {
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 		} else {
 		} else {
+			w.Header().Set("Content-Type", "application/json")
 			w.Write(b)
 			w.Write(b)
 		}
 		}
 	})
 	})
@@ -81,6 +82,7 @@ func ListenAndServe(addr string, srv *Server) error {
 			if err != nil {
 			if err != nil {
 				http.Error(w, err.Error(), http.StatusInternalServerError)
 				http.Error(w, err.Error(), http.StatusInternalServerError)
 			} else {
 			} else {
+				w.Header().Set("Content-Type", "application/json")
 				w.Write(b)
 				w.Write(b)
 			}
 			}
 		} else {
 		} else {
@@ -95,6 +97,7 @@ func ListenAndServe(addr string, srv *Server) error {
 		if err != nil {
 		if err != nil {
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 		} else {
 		} else {
+			w.Header().Set("Content-Type", "application/json")
 			w.Write(b)
 			w.Write(b)
 		}
 		}
 	})
 	})
@@ -136,6 +139,7 @@ func ListenAndServe(addr string, srv *Server) error {
 		log.Println(r.Method, r.RequestURI)
 		log.Println(r.Method, r.RequestURI)
 		if err := r.ParseForm(); err != nil {
 		if err := r.ParseForm(); err != nil {
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
 		}
 		}
 		all := r.Form.Get("all")
 		all := r.Form.Get("all")
 		filter := r.Form.Get("filter")
 		filter := r.Form.Get("filter")
@@ -144,11 +148,13 @@ func ListenAndServe(addr string, srv *Server) error {
 		outs, err := srv.Images(all, filter, quiet)
 		outs, err := srv.Images(all, filter, quiet)
 		if err != nil {
 		if err != nil {
 			httpError(w, err)
 			httpError(w, err)
+			return
 		}
 		}
 		b, err := json.Marshal(outs)
 		b, err := json.Marshal(outs)
 		if err != nil {
 		if err != nil {
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 		} else {
 		} else {
+			w.Header().Set("Content-Type", "application/json")
 			w.Write(b)
 			w.Write(b)
 		}
 		}
 	})
 	})
@@ -160,6 +166,7 @@ func ListenAndServe(addr string, srv *Server) error {
 		if err != nil {
 		if err != nil {
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 		} else {
 		} else {
+			w.Header().Set("Content-Type", "application/json")
 			w.Write(b)
 			w.Write(b)
 		}
 		}
 	})
 	})
@@ -171,11 +178,13 @@ func ListenAndServe(addr string, srv *Server) error {
 		outs, err := srv.ImageHistory(name)
 		outs, err := srv.ImageHistory(name)
 		if err != nil {
 		if err != nil {
 			httpError(w, err)
 			httpError(w, err)
+			return
 		}
 		}
 		b, err := json.Marshal(outs)
 		b, err := json.Marshal(outs)
 		if err != nil {
 		if err != nil {
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 		} else {
 		} else {
+			w.Header().Set("Content-Type", "application/json")
 			w.Write(b)
 			w.Write(b)
 		}
 		}
 	})
 	})
@@ -187,11 +196,13 @@ func ListenAndServe(addr string, srv *Server) error {
 		changesStr, err := srv.ContainerChanges(name)
 		changesStr, err := srv.ContainerChanges(name)
 		if err != nil {
 		if err != nil {
 			httpError(w, err)
 			httpError(w, err)
+			return
 		}
 		}
 		b, err := json.Marshal(changesStr)
 		b, err := json.Marshal(changesStr)
 		if err != nil {
 		if err != nil {
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 		} else {
 		} else {
+			w.Header().Set("Content-Type", "application/json")
 			w.Write(b)
 			w.Write(b)
 		}
 		}
 	})
 	})
@@ -200,17 +211,20 @@ func ListenAndServe(addr string, srv *Server) error {
 		log.Println(r.Method, r.RequestURI)
 		log.Println(r.Method, r.RequestURI)
 		if err := r.ParseForm(); err != nil {
 		if err := r.ParseForm(); err != nil {
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
 		}
 		}
 		vars := mux.Vars(r)
 		vars := mux.Vars(r)
 		name := vars["name"]
 		name := vars["name"]
 		out, err := srv.ContainerPort(name, r.Form.Get("port"))
 		out, err := srv.ContainerPort(name, r.Form.Get("port"))
 		if err != nil {
 		if err != nil {
 			httpError(w, err)
 			httpError(w, err)
+			return
 		}
 		}
 		b, err := json.Marshal(ApiPort{out})
 		b, err := json.Marshal(ApiPort{out})
 		if err != nil {
 		if err != nil {
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 		} else {
 		} else {
+			w.Header().Set("Content-Type", "application/json")
 			w.Write(b)
 			w.Write(b)
 		}
 		}
 
 
@@ -220,6 +234,7 @@ func ListenAndServe(addr string, srv *Server) error {
 		log.Println(r.Method, r.RequestURI)
 		log.Println(r.Method, r.RequestURI)
 		if err := r.ParseForm(); err != nil {
 		if err := r.ParseForm(); err != nil {
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
 		}
 		}
 		all := r.Form.Get("all")
 		all := r.Form.Get("all")
 		notrunc := r.Form.Get("notrunc")
 		notrunc := r.Form.Get("notrunc")
@@ -234,6 +249,7 @@ func ListenAndServe(addr string, srv *Server) error {
 		if err != nil {
 		if err != nil {
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 		} else {
 		} else {
+			w.Header().Set("Content-Type", "application/json")
 			w.Write(b)
 			w.Write(b)
 		}
 		}
 	})
 	})
@@ -242,6 +258,7 @@ func ListenAndServe(addr string, srv *Server) error {
 		log.Println(r.Method, r.RequestURI)
 		log.Println(r.Method, r.RequestURI)
 		if err := r.ParseForm(); err != nil {
 		if err := r.ParseForm(); err != nil {
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
 		}
 		}
 		repo := r.Form.Get("repo")
 		repo := r.Form.Get("repo")
 		tag := r.Form.Get("tag")
 		tag := r.Form.Get("tag")
@@ -259,62 +276,68 @@ func ListenAndServe(addr string, srv *Server) error {
 		w.WriteHeader(http.StatusCreated)
 		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) {
 	r.Path("/images").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		log.Println(r.Method, r.RequestURI)
 		log.Println(r.Method, r.RequestURI)
 		if err := r.ParseForm(); err != nil {
 		if err := r.ParseForm(); err != nil {
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
 		}
 		}
 
 
 		src := r.Form.Get("fromSrc")
 		src := r.Form.Get("fromSrc")
 		image := r.Form.Get("fromImage")
 		image := r.Form.Get("fromImage")
-		container := r.Form.Get("fromContainer")
 		repo := r.Form.Get("repo")
 		repo := r.Form.Get("repo")
 		tag := r.Form.Get("tag")
 		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
-			}
-			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)
-			}
-			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
+		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())
 			}
 			}
-			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 { //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 {
 		if err != nil {
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 		} else {
 		} else {
+			w.Header().Set("Content-Type", "application/json")
 			w.Write(b)
 			w.Write(b)
 		}
 		}
 	})
 	})
@@ -372,6 +396,7 @@ func ListenAndServe(addr string, srv *Server) error {
 		log.Println(r.Method, r.RequestURI)
 		log.Println(r.Method, r.RequestURI)
 		if err := r.ParseForm(); err != nil {
 		if err := r.ParseForm(); err != nil {
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
 		}
 		}
 		t, err := strconv.Atoi(r.Form.Get("t"))
 		t, err := strconv.Atoi(r.Form.Get("t"))
 		if err != nil || t < 0 {
 		if err != nil || t < 0 {
@@ -390,6 +415,7 @@ func ListenAndServe(addr string, srv *Server) error {
 		log.Println(r.Method, r.RequestURI)
 		log.Println(r.Method, r.RequestURI)
 		if err := r.ParseForm(); err != nil {
 		if err := r.ParseForm(); err != nil {
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
 		}
 		}
 		vars := mux.Vars(r)
 		vars := mux.Vars(r)
 		name := vars["name"]
 		name := vars["name"]
@@ -430,6 +456,7 @@ func ListenAndServe(addr string, srv *Server) error {
 		log.Println(r.Method, r.RequestURI)
 		log.Println(r.Method, r.RequestURI)
 		if err := r.ParseForm(); err != nil {
 		if err := r.ParseForm(); err != nil {
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
 		}
 		}
 		t, err := strconv.Atoi(r.Form.Get("t"))
 		t, err := strconv.Atoi(r.Form.Get("t"))
 		if err != nil || t < 0 {
 		if err != nil || t < 0 {
@@ -452,11 +479,13 @@ func ListenAndServe(addr string, srv *Server) error {
 		status, err := srv.ContainerWait(name)
 		status, err := srv.ContainerWait(name)
 		if err != nil {
 		if err != nil {
 			httpError(w, err)
 			httpError(w, err)
+			return
 		}
 		}
 		b, err := json.Marshal(ApiWait{status})
 		b, err := json.Marshal(ApiWait{status})
 		if err != nil {
 		if err != nil {
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 		} else {
 		} else {
+			w.Header().Set("Content-Type", "application/json")
 			w.Write(b)
 			w.Write(b)
 		}
 		}
 	})
 	})
@@ -465,6 +494,7 @@ func ListenAndServe(addr string, srv *Server) error {
 		log.Println(r.Method, r.RequestURI)
 		log.Println(r.Method, r.RequestURI)
 		if err := r.ParseForm(); err != nil {
 		if err := r.ParseForm(); err != nil {
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
 		}
 		}
 		logs := r.Form.Get("logs")
 		logs := r.Form.Get("logs")
 		stream := r.Form.Get("stream")
 		stream := r.Form.Get("stream")
@@ -500,11 +530,13 @@ func ListenAndServe(addr string, srv *Server) error {
 		container, err := srv.ContainerInspect(name)
 		container, err := srv.ContainerInspect(name)
 		if err != nil {
 		if err != nil {
 			httpError(w, err)
 			httpError(w, err)
+			return
 		}
 		}
 		b, err := json.Marshal(container)
 		b, err := json.Marshal(container)
 		if err != nil {
 		if err != nil {
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 		} else {
 		} else {
+			w.Header().Set("Content-Type", "application/json")
 			w.Write(b)
 			w.Write(b)
 		}
 		}
 	})
 	})
@@ -517,11 +549,13 @@ func ListenAndServe(addr string, srv *Server) error {
 		image, err := srv.ImageInspect(name)
 		image, err := srv.ImageInspect(name)
 		if err != nil {
 		if err != nil {
 			httpError(w, err)
 			httpError(w, err)
+			return
 		}
 		}
 		b, err := json.Marshal(image)
 		b, err := json.Marshal(image)
 		if err != nil {
 		if err != nil {
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 		} else {
 		} else {
+			w.Header().Set("Content-Type", "application/json")
 			w.Write(b)
 			w.Write(b)
 		}
 		}
 	})
 	})

+ 4 - 4
commands.go

@@ -541,7 +541,6 @@ func CmdKill(args ...string) error {
 	return nil
 	return nil
 }
 }
 
 
-/* /!\ W.I.P /!\ */
 func CmdImport(args ...string) error {
 func CmdImport(args ...string) error {
 	cmd := Subcmd("import", "URL|- [REPOSITORY [TAG]]", "Create a new filesystem image from the contents of a tarball")
 	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)
 			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 err
 	}
 	}
 	return nil
 	return nil
@@ -764,7 +763,7 @@ func CmdCommit(args ...string) error {
 	}
 	}
 
 
 	v := url.Values{}
 	v := url.Values{}
-	v.Set("fromContainer", name)
+	v.Set("container", name)
 	v.Set("repo", repository)
 	v.Set("repo", repository)
 	v.Set("tag", tag)
 	v.Set("tag", tag)
 	v.Set("comment", *flComment)
 	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 {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -1072,6 +1071,7 @@ func call(method, path string, data interface{}) ([]byte, int, error) {
 		}
 		}
 		params = bytes.NewBuffer(buf)
 		params = bytes.NewBuffer(buf)
 	}
 	}
+
 	req, err := http.NewRequest(method, "http://0.0.0.0:4243"+path, params)
 	req, err := http.NewRequest(method, "http://0.0.0.0:4243"+path, params)
 	if err != nil {
 	if err != nil {
 		return nil, -1, err
 		return nil, -1, err

+ 1 - 1
docs/sources/conf.py

@@ -25,7 +25,7 @@ import sys, os
 
 
 # Add any Sphinx extension module names here, as strings. They can be extensions
 # Add any Sphinx extension module names here, as strings. They can be extensions
 # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
 # 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.
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['_templates']
 templates_path = ['_templates']

+ 2 - 1
docs/sources/index.rst

@@ -16,7 +16,8 @@ This documentation has the following resources:
    contributing/index
    contributing/index
    commandline/index
    commandline/index
    registry/index
    registry/index
+   remote-api/index
    faq
    faq
 
 
 
 
-.. image:: http://www.docker.io/_static/lego_docker.jpg
+.. image:: http://www.docker.io/_static/lego_docker.jpg

+ 878 - 0
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 <hannibal@a-team.com>")
+	: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.

+ 15 - 0
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