diff --git a/components/engine/CHANGELOG.md b/components/engine/CHANGELOG.md index a9e2dab79e..4d3502d23a 100644 --- a/components/engine/CHANGELOG.md +++ b/components/engine/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 0.3.3 (2013-05-23) + - Registry: Fix push regression + - Various bugfixes + ## 0.3.2 (2013-05-09) * Runtime: Store the actual archive on commit * Registry: Improve the checksum process diff --git a/components/engine/README.md b/components/engine/README.md index c83feeae58..918fdaade2 100644 --- a/components/engine/README.md +++ b/components/engine/README.md @@ -12,7 +12,7 @@ Docker is an open-source implementation of the deployment engine which powers [d It benefits directly from the experience accumulated over several years of large-scale operation and support of hundreds of thousands of applications and databases. -![Docker L](docs/sources/static_files/lego_docker.jpg "Docker") +![Docker L](docs/sources/concepts/images/lego_docker.jpg "Docker") ## Better than VMs diff --git a/components/engine/api.go b/components/engine/api.go index a1a6949626..e004aa4a3b 100644 --- a/components/engine/api.go +++ b/components/engine/api.go @@ -13,6 +13,8 @@ import ( "strings" ) +const API_VERSION = 1.1 + func hijackServer(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) { conn, _, err := w.(http.Hijacker).Hijack() if err != nil { @@ -53,6 +55,7 @@ func writeJson(w http.ResponseWriter, b []byte) { w.Write(b) } +// FIXME: Use stvconv.ParseBool() instead? func getBoolParam(value string) (bool, error) { if value == "1" || strings.ToLower(value) == "true" { return true, nil @@ -63,8 +66,8 @@ func getBoolParam(value string) (bool, error) { return false, fmt.Errorf("Bad parameter") } -func getAuth(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { - b, err := json.Marshal(srv.registry.GetAuthConfig()) +func getAuth(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { + b, err := json.Marshal(srv.registry.GetAuthConfig(false)) if err != nil { return err } @@ -72,14 +75,14 @@ func getAuth(srv *Server, w http.ResponseWriter, r *http.Request, vars map[strin return nil } -func postAuth(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postAuth(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { config := &auth.AuthConfig{} if err := json.NewDecoder(r.Body).Decode(config); err != nil { return err } - - if config.Username == srv.registry.GetAuthConfig().Username { - config.Password = srv.registry.GetAuthConfig().Password + authConfig := srv.registry.GetAuthConfig(true) + if config.Username == authConfig.Username { + config.Password = authConfig.Password } newAuthConfig := auth.NewAuthConfig(config.Username, config.Password, config.Email, srv.runtime.root) @@ -101,7 +104,7 @@ func postAuth(srv *Server, w http.ResponseWriter, r *http.Request, vars map[stri return nil } -func getVersion(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func getVersion(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { m := srv.DockerVersion() b, err := json.Marshal(m) if err != nil { @@ -111,7 +114,7 @@ func getVersion(srv *Server, w http.ResponseWriter, r *http.Request, vars map[st return nil } -func postContainersKill(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postContainersKill(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -123,7 +126,7 @@ func postContainersKill(srv *Server, w http.ResponseWriter, r *http.Request, var return nil } -func getContainersExport(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func getContainersExport(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -136,7 +139,7 @@ func getContainersExport(srv *Server, w http.ResponseWriter, r *http.Request, va return nil } -func getImagesJson(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func getImagesJson(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -159,14 +162,14 @@ func getImagesJson(srv *Server, w http.ResponseWriter, r *http.Request, vars map return nil } -func getImagesViz(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func getImagesViz(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := srv.ImagesViz(w); err != nil { return err } return nil } -func getInfo(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func getInfo(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { out := srv.DockerInfo() b, err := json.Marshal(out) if err != nil { @@ -176,7 +179,7 @@ func getInfo(srv *Server, w http.ResponseWriter, r *http.Request, vars map[strin return nil } -func getImagesHistory(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func getImagesHistory(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -193,7 +196,7 @@ func getImagesHistory(srv *Server, w http.ResponseWriter, r *http.Request, vars return nil } -func getContainersChanges(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func getContainersChanges(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -210,7 +213,7 @@ func getContainersChanges(srv *Server, w http.ResponseWriter, r *http.Request, v return nil } -func getContainersPs(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func getContainersPs(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -234,7 +237,7 @@ func getContainersPs(srv *Server, w http.ResponseWriter, r *http.Request, vars m return nil } -func postImagesTag(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postImagesTag(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -256,7 +259,7 @@ func postImagesTag(srv *Server, w http.ResponseWriter, r *http.Request, vars map return nil } -func postCommit(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postCommit(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -283,7 +286,7 @@ func postCommit(srv *Server, w http.ResponseWriter, r *http.Request, vars map[st } // Creates an image from Pull or from Import -func postImagesCreate(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postImagesCreate(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -295,7 +298,10 @@ func postImagesCreate(srv *Server, w http.ResponseWriter, r *http.Request, vars if image != "" { //pull registry := r.Form.Get("registry") - if err := srv.ImagePull(image, tag, registry, w); err != nil { + if version > 1.0 { + w.Header().Set("Content-Type", "application/json") + } + if err := srv.ImagePull(image, tag, registry, w, version > 1.0); err != nil { return err } } else { //import @@ -306,7 +312,7 @@ func postImagesCreate(srv *Server, w http.ResponseWriter, r *http.Request, vars return nil } -func getImagesSearch(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func getImagesSearch(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -324,7 +330,7 @@ func getImagesSearch(srv *Server, w http.ResponseWriter, r *http.Request, vars m return nil } -func postImagesInsert(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postImagesInsert(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -348,7 +354,7 @@ func postImagesInsert(srv *Server, w http.ResponseWriter, r *http.Request, vars return nil } -func postImagesPush(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postImagesPush(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -365,7 +371,7 @@ func postImagesPush(srv *Server, w http.ResponseWriter, r *http.Request, vars ma return nil } -func postContainersCreate(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { config := &Config{} if err := json.NewDecoder(r.Body).Decode(config); err != nil { return err @@ -395,7 +401,7 @@ func postContainersCreate(srv *Server, w http.ResponseWriter, r *http.Request, v return nil } -func postContainersRestart(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postContainersRestart(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -414,7 +420,7 @@ func postContainersRestart(srv *Server, w http.ResponseWriter, r *http.Request, return nil } -func deleteContainers(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func deleteContainers(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -434,7 +440,7 @@ func deleteContainers(srv *Server, w http.ResponseWriter, r *http.Request, vars return nil } -func deleteImages(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func deleteImages(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -446,7 +452,7 @@ func deleteImages(srv *Server, w http.ResponseWriter, r *http.Request, vars map[ return nil } -func postContainersStart(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postContainersStart(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -458,7 +464,7 @@ func postContainersStart(srv *Server, w http.ResponseWriter, r *http.Request, va return nil } -func postContainersStop(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postContainersStop(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -479,7 +485,7 @@ func postContainersStop(srv *Server, w http.ResponseWriter, r *http.Request, var return nil } -func postContainersWait(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postContainersWait(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -496,7 +502,29 @@ func postContainersWait(srv *Server, w http.ResponseWriter, r *http.Request, var return nil } -func postContainersAttach(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postContainersResize(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { + if err := parseForm(r); err != nil { + return err + } + height, err := strconv.Atoi(r.Form.Get("h")) + if err != nil { + return err + } + width, err := strconv.Atoi(r.Form.Get("w")) + if err != nil { + return err + } + if vars == nil { + return fmt.Errorf("Missing parameter") + } + name := vars["name"] + if err := srv.ContainerResize(name, height, width); err != nil { + return err + } + return nil +} + +func postContainersAttach(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -539,7 +567,7 @@ func postContainersAttach(srv *Server, w http.ResponseWriter, r *http.Request, v return nil } -func getContainersByName(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func getContainersByName(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -557,7 +585,7 @@ func getContainersByName(srv *Server, w http.ResponseWriter, r *http.Request, va return nil } -func getImagesByName(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func getImagesByName(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -575,7 +603,7 @@ func getImagesByName(srv *Server, w http.ResponseWriter, r *http.Request, vars m return nil } -func postImagesGetCache(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func postImagesGetCache(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { apiConfig := &ApiImageConfig{} if err := json.NewDecoder(r.Body).Decode(apiConfig); err != nil { return err @@ -626,7 +654,7 @@ func ListenAndServe(addr string, srv *Server, logging bool) error { r := mux.NewRouter() log.Printf("Listening for HTTP on %s\n", addr) - m := map[string]map[string]func(*Server, http.ResponseWriter, *http.Request, map[string]string) error{ + m := map[string]map[string]func(*Server, float64, http.ResponseWriter, *http.Request, map[string]string) error{ "GET": { "/auth": getAuth, "/version": getVersion, @@ -656,6 +684,7 @@ func ListenAndServe(addr string, srv *Server, logging bool) error { "/containers/{name:.*}/start": postContainersStart, "/containers/{name:.*}/stop": postContainersStop, "/containers/{name:.*}/wait": postContainersWait, + "/containers/{name:.*}/resize": postContainersResize, "/containers/{name:.*}/attach": postContainersAttach, }, "DELETE": { @@ -671,7 +700,7 @@ func ListenAndServe(addr string, srv *Server, logging bool) error { localRoute := route localMethod := method localFct := fct - r.Path(localRoute).Methods(localMethod).HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + f := func(w http.ResponseWriter, r *http.Request) { utils.Debugf("Calling %s %s", localMethod, localRoute) if logging { log.Println(r.Method, r.RequestURI) @@ -682,12 +711,21 @@ func ListenAndServe(addr string, srv *Server, logging bool) error { utils.Debugf("Warning: client and server don't have the same version (client: %s, server: %s)", userAgent[1], VERSION) } } - if err := localFct(srv, w, r, mux.Vars(r)); err != nil { + version, err := strconv.ParseFloat(mux.Vars(r)["version"], 64) + if err != nil { + version = API_VERSION + } + if version == 0 || version > API_VERSION { + w.WriteHeader(http.StatusNotFound) + return + } + if err := localFct(srv, version, w, r, mux.Vars(r)); err != nil { httpError(w, err) } - }) + } + r.Path("/v{version:[0-9.]+}" + localRoute).Methods(localMethod).HandlerFunc(f) + r.Path(localRoute).Methods(localMethod).HandlerFunc(f) } } - return http.ListenAndServe(addr, r) } diff --git a/components/engine/api_test.go b/components/engine/api_test.go index dd685ffece..06413e1303 100644 --- a/components/engine/api_test.go +++ b/components/engine/api_test.go @@ -48,7 +48,7 @@ func TestGetAuth(t *testing.T) { t.Fatal(err) } - if err := postAuth(srv, r, req, nil); err != nil { + if err := postAuth(srv, API_VERSION, r, req, nil); err != nil { t.Fatal(err) } @@ -56,7 +56,7 @@ func TestGetAuth(t *testing.T) { t.Fatalf("%d OK or 0 expected, received %d\n", http.StatusOK, r.Code) } - newAuthConfig := srv.registry.GetAuthConfig() + newAuthConfig := srv.registry.GetAuthConfig(false) if newAuthConfig.Username != authConfig.Username || newAuthConfig.Email != authConfig.Email { t.Fatalf("The auth configuration hasn't been set correctly") @@ -74,7 +74,7 @@ func TestGetVersion(t *testing.T) { r := httptest.NewRecorder() - if err := getVersion(srv, r, nil, nil); err != nil { + if err := getVersion(srv, API_VERSION, r, nil, nil); err != nil { t.Fatal(err) } @@ -98,7 +98,7 @@ func TestGetInfo(t *testing.T) { r := httptest.NewRecorder() - if err := getInfo(srv, r, nil, nil); err != nil { + if err := getInfo(srv, API_VERSION, r, nil, nil); err != nil { t.Fatal(err) } @@ -129,7 +129,7 @@ func TestGetImagesJson(t *testing.T) { r := httptest.NewRecorder() - if err := getImagesJson(srv, r, req, nil); err != nil { + if err := getImagesJson(srv, API_VERSION, r, req, nil); err != nil { t.Fatal(err) } @@ -154,7 +154,7 @@ func TestGetImagesJson(t *testing.T) { t.Fatal(err) } - if err := getImagesJson(srv, r2, req2, nil); err != nil { + if err := getImagesJson(srv, API_VERSION, r2, req2, nil); err != nil { t.Fatal(err) } @@ -179,7 +179,7 @@ func TestGetImagesJson(t *testing.T) { t.Fatal(err) } - if err := getImagesJson(srv, r3, req3, nil); err != nil { + if err := getImagesJson(srv, API_VERSION, r3, req3, nil); err != nil { t.Fatal(err) } @@ -200,7 +200,7 @@ func TestGetImagesJson(t *testing.T) { t.Fatal(err) } - err = getImagesJson(srv, r4, req4, nil) + err = getImagesJson(srv, API_VERSION, r4, req4, nil) if err == nil { t.Fatalf("Error expected, received none") } @@ -221,7 +221,7 @@ func TestGetImagesViz(t *testing.T) { srv := &Server{runtime: runtime} r := httptest.NewRecorder() - if err := getImagesViz(srv, r, nil, nil); err != nil { + if err := getImagesViz(srv, API_VERSION, r, nil, nil); err != nil { t.Fatal(err) } @@ -258,7 +258,7 @@ func TestGetImagesSearch(t *testing.T) { t.Fatal(err) } - if err := getImagesSearch(srv, r, req, nil); err != nil { + if err := getImagesSearch(srv, API_VERSION, r, req, nil); err != nil { t.Fatal(err) } @@ -282,7 +282,7 @@ func TestGetImagesHistory(t *testing.T) { r := httptest.NewRecorder() - if err := getImagesHistory(srv, r, nil, map[string]string{"name": unitTestImageName}); err != nil { + if err := getImagesHistory(srv, API_VERSION, r, nil, map[string]string{"name": unitTestImageName}); err != nil { t.Fatal(err) } @@ -305,7 +305,7 @@ func TestGetImagesByName(t *testing.T) { srv := &Server{runtime: runtime} r := httptest.NewRecorder() - if err := getImagesByName(srv, r, nil, map[string]string{"name": unitTestImageName}); err != nil { + if err := getImagesByName(srv, API_VERSION, r, nil, map[string]string{"name": unitTestImageName}); err != nil { t.Fatal(err) } @@ -342,7 +342,7 @@ func TestGetContainersPs(t *testing.T) { } r := httptest.NewRecorder() - if err := getContainersPs(srv, r, req, nil); err != nil { + if err := getContainersPs(srv, API_VERSION, r, req, nil); err != nil { t.Fatal(err) } containers := []ApiContainers{} @@ -385,7 +385,7 @@ func TestGetContainersExport(t *testing.T) { } r := httptest.NewRecorder() - if err = getContainersExport(srv, r, nil, map[string]string{"name": container.Id}); err != nil { + if err = getContainersExport(srv, API_VERSION, r, nil, map[string]string{"name": container.Id}); err != nil { t.Fatal(err) } @@ -440,7 +440,7 @@ func TestGetContainersChanges(t *testing.T) { } r := httptest.NewRecorder() - if err := getContainersChanges(srv, r, nil, map[string]string{"name": container.Id}); err != nil { + if err := getContainersChanges(srv, API_VERSION, r, nil, map[string]string{"name": container.Id}); err != nil { t.Fatal(err) } changes := []Change{} @@ -484,7 +484,7 @@ func TestGetContainersByName(t *testing.T) { defer runtime.Destroy(container) r := httptest.NewRecorder() - if err := getContainersByName(srv, r, nil, map[string]string{"name": container.Id}); err != nil { + if err := getContainersByName(srv, API_VERSION, r, nil, map[string]string{"name": container.Id}); err != nil { t.Fatal(err) } outContainer := &Container{} @@ -515,7 +515,7 @@ func TestPostAuth(t *testing.T) { srv.registry.ResetClient(authConfigOrig) r := httptest.NewRecorder() - if err := getAuth(srv, r, nil, nil); err != nil { + if err := getAuth(srv, API_VERSION, r, nil, nil); err != nil { t.Fatal(err) } @@ -562,7 +562,7 @@ func TestPostCommit(t *testing.T) { } r := httptest.NewRecorder() - if err := postCommit(srv, r, req, nil); err != nil { + if err := postCommit(srv, API_VERSION, r, req, nil); err != nil { t.Fatal(err) } if r.Code != http.StatusCreated { @@ -840,7 +840,7 @@ func TestPostContainersCreate(t *testing.T) { } r := httptest.NewRecorder() - if err := postContainersCreate(srv, r, req, nil); err != nil { + if err := postContainersCreate(srv, API_VERSION, r, req, nil); err != nil { t.Fatal(err) } if r.Code != http.StatusCreated { @@ -903,7 +903,7 @@ func TestPostContainersKill(t *testing.T) { } r := httptest.NewRecorder() - if err := postContainersKill(srv, r, nil, map[string]string{"name": container.Id}); err != nil { + if err := postContainersKill(srv, API_VERSION, r, nil, map[string]string{"name": container.Id}); err != nil { t.Fatal(err) } if r.Code != http.StatusNoContent { @@ -951,7 +951,7 @@ func TestPostContainersRestart(t *testing.T) { t.Fatal(err) } r := httptest.NewRecorder() - if err := postContainersRestart(srv, r, req, map[string]string{"name": container.Id}); err != nil { + if err := postContainersRestart(srv, API_VERSION, r, req, map[string]string{"name": container.Id}); err != nil { t.Fatal(err) } if r.Code != http.StatusNoContent { @@ -992,7 +992,7 @@ func TestPostContainersStart(t *testing.T) { defer runtime.Destroy(container) r := httptest.NewRecorder() - if err := postContainersStart(srv, r, nil, map[string]string{"name": container.Id}); err != nil { + if err := postContainersStart(srv, API_VERSION, r, nil, map[string]string{"name": container.Id}); err != nil { t.Fatal(err) } if r.Code != http.StatusNoContent { @@ -1007,7 +1007,7 @@ func TestPostContainersStart(t *testing.T) { } r = httptest.NewRecorder() - if err = postContainersStart(srv, r, nil, map[string]string{"name": container.Id}); err == nil { + if err = postContainersStart(srv, API_VERSION, r, nil, map[string]string{"name": container.Id}); err == nil { t.Fatalf("A running containter should be able to be started") } @@ -1054,7 +1054,7 @@ func TestPostContainersStop(t *testing.T) { t.Fatal(err) } r := httptest.NewRecorder() - if err := postContainersStop(srv, r, req, map[string]string{"name": container.Id}); err != nil { + if err := postContainersStop(srv, API_VERSION, r, req, map[string]string{"name": container.Id}); err != nil { t.Fatal(err) } if r.Code != http.StatusNoContent { @@ -1092,7 +1092,7 @@ func TestPostContainersWait(t *testing.T) { setTimeout(t, "Wait timed out", 3*time.Second, func() { r := httptest.NewRecorder() - if err := postContainersWait(srv, r, nil, map[string]string{"name": container.Id}); err != nil { + if err := postContainersWait(srv, API_VERSION, r, nil, map[string]string{"name": container.Id}); err != nil { t.Fatal(err) } apiWait := &ApiWait{} @@ -1154,7 +1154,7 @@ func TestPostContainersAttach(t *testing.T) { t.Fatal(err) } - if err := postContainersAttach(srv, r, req, map[string]string{"name": container.Id}); err != nil { + if err := postContainersAttach(srv, API_VERSION, r, req, map[string]string{"name": container.Id}); err != nil { t.Fatal(err) } }() @@ -1224,7 +1224,7 @@ func TestDeleteContainers(t *testing.T) { t.Fatal(err) } r := httptest.NewRecorder() - if err := deleteContainers(srv, r, req, map[string]string{"name": container.Id}); err != nil { + if err := deleteContainers(srv, API_VERSION, r, req, map[string]string{"name": container.Id}); err != nil { t.Fatal(err) } if r.Code != http.StatusNoContent { diff --git a/components/engine/builder_client.go b/components/engine/builder_client.go index 0b511ee218..144e11b415 100644 --- a/components/engine/builder_client.go +++ b/components/engine/builder_client.go @@ -26,12 +26,6 @@ type builderClient struct { } func (b *builderClient) clearTmp(containers, images map[string]struct{}) { - for c := range containers { - if _, _, err := b.cli.call("DELETE", "/containers/"+c, nil); err != nil { - utils.Debugf("%s", err) - } - utils.Debugf("Removing container %s", c) - } for i := range images { if _, _, err := b.cli.call("DELETE", "/images/"+i, nil); err != nil { utils.Debugf("%s", err) diff --git a/components/engine/commands.go b/components/engine/commands.go index cfe6c38a41..952a2bb6cf 100644 --- a/components/engine/commands.go +++ b/components/engine/commands.go @@ -16,30 +16,36 @@ import ( "net/http/httputil" "net/url" "os" + "os/signal" "path/filepath" "reflect" "strconv" "strings" + "syscall" "text/tabwriter" "time" "unicode" ) -const VERSION = "0.3.2" +const VERSION = "0.3.3" var ( GIT_COMMIT string ) -func ParseCommands(args ...string) error { - cli := NewDockerCli("0.0.0.0", 4243) +func (cli *DockerCli) getMethod(name string) (reflect.Method, bool) { + methodName := "Cmd" + strings.ToUpper(name[:1]) + strings.ToLower(name[1:]) + return reflect.TypeOf(cli).MethodByName(methodName) +} + +func ParseCommands(addr string, port int, args ...string) error { + cli := NewDockerCli(addr, port) if len(args) > 0 { - methodName := "Cmd" + strings.ToUpper(args[0][:1]) + strings.ToLower(args[0][1:]) - method, exists := reflect.TypeOf(cli).MethodByName(methodName) + method, exists := cli.getMethod(args[0]) if !exists { fmt.Println("Error: Command not found:", args[0]) - return cli.CmdHelp(args...) + return cli.CmdHelp(args[1:]...) } ret := method.Func.CallSlice([]reflect.Value{ reflect.ValueOf(cli), @@ -54,7 +60,19 @@ func ParseCommands(args ...string) error { } func (cli *DockerCli) CmdHelp(args ...string) error { - help := "Usage: docker COMMAND [arg...]\n\nA self-sufficient runtime for linux containers.\n\nCommands:\n" + if len(args) > 0 { + method, exists := cli.getMethod(args[0]) + if !exists { + fmt.Println("Error: Command not found:", args[0]) + } else { + method.Func.CallSlice([]reflect.Value{ + reflect.ValueOf(cli), + reflect.ValueOf([]string{"--help"}), + })[0].Interface() + return nil + } + } + help := fmt.Sprintf("Usage: docker [OPTIONS] COMMAND [arg...]\n -H=\"%s:%d\": Host:port to bind/connect to\n\nA self-sufficient runtime for linux containers.\n\nCommands:\n", cli.host, cli.port) for cmd, description := range map[string]string{ "attach": "Attach to a running container", "build": "Build a container from a Dockerfile", @@ -660,39 +678,13 @@ func (cli *DockerCli) CmdPush(args ...string) error { return nil } - body, _, err := cli.call("GET", "/auth", nil) + username, err := cli.checkIfLogged(*registry == "", "push") if err != nil { return err } - var out auth.AuthConfig - err = json.Unmarshal(body, &out) - if err != nil { - return err - } - - // If the login failed AND we're using the index, abort - if *registry == "" && out.Username == "" { - if err := cli.CmdLogin(args...); err != nil { - return err - } - - body, _, err = cli.call("GET", "/auth", nil) - if err != nil { - return err - } - err = json.Unmarshal(body, &out) - if err != nil { - return err - } - - if out.Username == "" { - return fmt.Errorf("Please login prior to push. ('docker login')") - } - } - if len(strings.SplitN(name, "/", 2)) == 1 { - return fmt.Errorf("Impossible to push a \"root\" repository. Please rename your repository in / (ex: %s/%s)", out.Username, name) + return fmt.Errorf("Impossible to push a \"root\" repository. Please rename your repository in / (ex: %s/%s)", username, name) } v := url.Values{} @@ -723,6 +715,12 @@ func (cli *DockerCli) CmdPull(args ...string) error { remote = remoteParts[0] } + if strings.Contains(remote, "/") { + if _, err := cli.checkIfLogged(true, "pull"); err != nil { + return err + } + } + v := url.Values{} v.Set("fromImage", remote) v.Set("tag", *tag) @@ -1013,6 +1011,7 @@ func (cli *DockerCli) CmdAttach(args ...string) error { v.Set("stderr", "1") v.Set("stdin", "1") + cli.monitorTtySize(cmd.Arg(0)) if err := cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?"+v.Encode(), container.Config.Tty); err != nil { return err } @@ -1200,6 +1199,7 @@ func (cli *DockerCli) CmdRun(args ...string) error { } if config.AttachStdin || config.AttachStdout || config.AttachStderr { + cli.monitorTtySize(out.Id) if err := cli.hijack("POST", "/containers/"+out.Id+"/attach?"+v.Encode(), config.Tty); err != nil { return err } @@ -1210,6 +1210,40 @@ func (cli *DockerCli) CmdRun(args ...string) error { return nil } +func (cli *DockerCli) checkIfLogged(condition bool, action string) (string, error) { + body, _, err := cli.call("GET", "/auth", nil) + if err != nil { + return "", err + } + + var out auth.AuthConfig + err = json.Unmarshal(body, &out) + if err != nil { + return "", err + } + + // If condition AND the login failed + if condition && out.Username == "" { + if err := cli.CmdLogin(""); err != nil { + return "", err + } + + body, _, err = cli.call("GET", "/auth", nil) + if err != nil { + return "", err + } + err = json.Unmarshal(body, &out) + if err != nil { + return "", err + } + + if out.Username == "" { + return "", fmt.Errorf("Please login prior to %s. ('docker login')", action) + } + } + return out.Username, nil +} + func (cli *DockerCli) call(method, path string, data interface{}) ([]byte, int, error) { var params io.Reader if data != nil { @@ -1220,7 +1254,7 @@ func (cli *DockerCli) call(method, path string, data interface{}) ([]byte, int, params = bytes.NewBuffer(buf) } - req, err := http.NewRequest(method, fmt.Sprintf("http://%s:%d", cli.host, cli.port)+path, params) + req, err := http.NewRequest(method, fmt.Sprintf("http://%s:%d/v%g%s", cli.host, cli.port, API_VERSION, path), params) if err != nil { return nil, -1, err } @@ -1252,7 +1286,7 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer) e if (method == "POST" || method == "PUT") && in == nil { in = bytes.NewReader([]byte{}) } - req, err := http.NewRequest(method, fmt.Sprintf("http://%s:%d%s", cli.host, cli.port, path), in) + req, err := http.NewRequest(method, fmt.Sprintf("http://%s:%d/v%g%s", cli.host, cli.port, API_VERSION, path), in) if err != nil { return err } @@ -1276,14 +1310,35 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer) e return fmt.Errorf("error: %s", body) } - if _, err := io.Copy(out, resp.Body); err != nil { - return err + if resp.Header.Get("Content-Type") == "application/json" { + type Message struct { + Status string `json:"status,omitempty"` + Progress string `json:"progress,omitempty"` + } + dec := json.NewDecoder(resp.Body) + for { + var m Message + if err := dec.Decode(&m); err == io.EOF { + break + } else if err != nil { + return err + } + if m.Progress != "" { + fmt.Fprintf(out, "Downloading %s\r", m.Progress) + } else { + fmt.Fprintf(out, "%s\n", m.Status) + } + } + } else { + if _, err := io.Copy(out, resp.Body); err != nil { + return err + } } return nil } func (cli *DockerCli) hijack(method, path string, setRawTerminal bool) error { - req, err := http.NewRequest(method, path, nil) + req, err := http.NewRequest(method, fmt.Sprintf("/v%g%s", API_VERSION, path), nil) if err != nil { return err } @@ -1333,6 +1388,33 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool) error { } +func (cli *DockerCli) resizeTty(id string) { + ws, err := term.GetWinsize(os.Stdin.Fd()) + if err != nil { + utils.Debugf("Error getting size: %s", err) + } + v := url.Values{} + v.Set("h", strconv.Itoa(int(ws.Height))) + v.Set("w", strconv.Itoa(int(ws.Width))) + if _, _, err := cli.call("POST", "/containers/"+id+"/resize?"+v.Encode(), nil); err != nil { + utils.Debugf("Error resize: %s", err) + } +} + +func (cli *DockerCli) monitorTtySize(id string) { + cli.resizeTty(id) + + c := make(chan os.Signal, 1) + signal.Notify(c, syscall.SIGWINCH) + go func() { + for sig := range c { + if sig == syscall.SIGWINCH { + cli.resizeTty(id) + } + } + }() +} + func Subcmd(name, signature, description string) *flag.FlagSet { flags := flag.NewFlagSet(name, flag.ContinueOnError) flags.Usage = func() { @@ -1342,8 +1424,8 @@ func Subcmd(name, signature, description string) *flag.FlagSet { return flags } -func NewDockerCli(host string, port int) *DockerCli { - return &DockerCli{host, port} +func NewDockerCli(addr string, port int) *DockerCli { + return &DockerCli{addr, port} } type DockerCli struct { diff --git a/components/engine/container.go b/components/engine/container.go index a82ce0291a..c6b7c8a51c 100644 --- a/components/engine/container.go +++ b/components/engine/container.go @@ -4,6 +4,7 @@ import ( "encoding/json" "flag" "fmt" + "github.com/dotcloud/docker/term" "github.com/dotcloud/docker/utils" "github.com/kr/pty" "io" @@ -754,6 +755,14 @@ func (container *Container) Wait() int { return container.State.ExitCode } +func (container *Container) Resize(h, w int) error { + pty, ok := container.ptyMaster.(*os.File) + if !ok { + return fmt.Errorf("ptyMaster does not have Fd() method") + } + return term.SetWinsize(pty.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)}) +} + func (container *Container) ExportRw() (Archive, error) { return Tar(container.rwPath(), Uncompressed) } diff --git a/components/engine/docker/docker.go b/components/engine/docker/docker.go index c8c1a65603..7b8aa7f858 100644 --- a/components/engine/docker/docker.go +++ b/components/engine/docker/docker.go @@ -10,6 +10,7 @@ import ( "os" "os/signal" "strconv" + "strings" "syscall" ) @@ -23,18 +24,38 @@ func main() { docker.SysInit() return } + host := "127.0.0.1" + port := 4243 // FIXME: Switch d and D ? (to be more sshd like) flDaemon := flag.Bool("d", false, "Daemon mode") flDebug := flag.Bool("D", false, "Debug mode") flAutoRestart := flag.Bool("r", false, "Restart previously running containers") bridgeName := flag.String("b", "", "Attach containers to a pre-existing network bridge") pidfile := flag.String("p", "/var/run/docker.pid", "File containing process PID") + flHost := flag.String("H", fmt.Sprintf("%s:%d", host, port), "Host:port to bind/connect to") flag.Parse() if *bridgeName != "" { docker.NetworkBridgeIface = *bridgeName } else { docker.NetworkBridgeIface = docker.DefaultNetworkBridge } + + if strings.Contains(*flHost, ":") { + hostParts := strings.Split(*flHost, ":") + if len(hostParts) != 2 { + log.Fatal("Invalid bind address format.") + os.Exit(-1) + } + if hostParts[0] != "" { + host = hostParts[0] + } + if p, err := strconv.Atoi(hostParts[1]); err == nil { + port = p + } + } else { + host = *flHost + } + if *flDebug { os.Setenv("DEBUG", "1") } @@ -44,12 +65,12 @@ func main() { flag.Usage() return } - if err := daemon(*pidfile, *flAutoRestart); err != nil { + if err := daemon(*pidfile, host, port, *flAutoRestart); err != nil { log.Fatal(err) os.Exit(-1) } } else { - if err := docker.ParseCommands(flag.Args()...); err != nil { + if err := docker.ParseCommands(host, port, flag.Args()...); err != nil { log.Fatal(err) os.Exit(-1) } @@ -83,7 +104,10 @@ func removePidFile(pidfile string) { } } -func daemon(pidfile string, autoRestart bool) error { +func daemon(pidfile, addr string, port int, autoRestart bool) error { + if addr != "127.0.0.1" { + log.Println("/!\\ DON'T BIND ON ANOTHER IP ADDRESS THAN 127.0.0.1 IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\") + } if err := createPidFile(pidfile); err != nil { log.Fatal(err) } @@ -103,5 +127,5 @@ func daemon(pidfile string, autoRestart bool) error { return err } - return docker.ListenAndServe("0.0.0.0:4243", server, true) + return docker.ListenAndServe(fmt.Sprintf("%s:%d", addr, port), server, true) } diff --git a/components/engine/docs/sources/api/docker_remote_api.rst b/components/engine/docs/sources/api/docker_remote_api.rst index 2b1aad0e84..0dcf842738 100644 --- a/components/engine/docs/sources/api/docker_remote_api.rst +++ b/components/engine/docs/sources/api/docker_remote_api.rst @@ -1,3 +1,7 @@ +:title: Remote API +:description: API Documentation for Docker +:keywords: API, Docker, rcli, REST, documentation + ================= Docker Remote API ================= @@ -118,7 +122,8 @@ Create a container .. sourcecode:: http HTTP/1.1 201 OK - + Content-Type: application/json + { "Id":"e90e34656806" "Warnings":[] @@ -373,7 +378,7 @@ Attach to a container .. http:post:: /containers/(id)/attach - Stop the container ``id`` + Attach to the container ``id`` **Example request**: diff --git a/components/engine/docs/sources/api/index.rst b/components/engine/docs/sources/api/index.rst index 8c118bcbc0..4d8ff3fe67 100644 --- a/components/engine/docs/sources/api/index.rst +++ b/components/engine/docs/sources/api/index.rst @@ -1,6 +1,6 @@ -:title: docker documentation +:title: API Documentation :description: docker documentation -:keywords: +:keywords: docker, ipa, documentation API's ============= diff --git a/components/engine/docs/sources/api/registry_api.rst b/components/engine/docs/sources/api/registry_api.rst index e299584e17..7034d90e27 100644 --- a/components/engine/docs/sources/api/registry_api.rst +++ b/components/engine/docs/sources/api/registry_api.rst @@ -1,4 +1,4 @@ -:title: docker Registry documentation +:title: Registry Documentation :description: Documentation for docker Registry and Registry API :keywords: docker, registry, api, index @@ -301,7 +301,7 @@ POST /v1/users {"email": "sam@dotcloud.com", "password": "toto42", "username": "foobar"'} **Validation**: - - **username** : min 4 character, max 30 characters, all lowercase no special characters. + - **username** : min 4 character, max 30 characters, must match the regular expression [a-z0-9_]. - **password**: min 5 characters **Valid**: return HTTP 200 @@ -345,6 +345,11 @@ GET /v1/users The Registry does not know anything about users. Even though repositories are under usernames, it’s just a namespace for the registry. Allowing us to implement organizations or different namespaces per user later, without modifying the Registry’s API. +The following naming restrictions apply: + +- Namespaces must match the same regular expression as usernames (See 4.2.1.) +- Repository names must match the regular expression [a-zA-Z0-9-_.] + 4.3.1 Get all tags ^^^^^^^^^^^^^^^^^^ diff --git a/components/engine/docs/sources/commandline/cli.rst b/components/engine/docs/sources/commandline/cli.rst index 1a341d3e5d..02691b4f56 100644 --- a/components/engine/docs/sources/commandline/cli.rst +++ b/components/engine/docs/sources/commandline/cli.rst @@ -14,7 +14,8 @@ To list available commands, either run ``docker`` with no parameters or execute ``docker help``:: $ docker - Usage: docker COMMAND [arg...] + Usage: docker [OPTIONS] COMMAND [arg...] + -H="127.0.0.1:4243": Host:port to bind/connect to A self-sufficient runtime for linux containers. diff --git a/components/engine/docs/sources/commandline/command/attach.rst b/components/engine/docs/sources/commandline/command/attach.rst index ac9a84c0cf..4c4c189d8f 100644 --- a/components/engine/docs/sources/commandline/command/attach.rst +++ b/components/engine/docs/sources/commandline/command/attach.rst @@ -1,3 +1,7 @@ +:title: Attach Command +:description: Attach to a running container +:keywords: attach, container, docker, documentation + =========================================== ``attach`` -- Attach to a running container =========================================== diff --git a/components/engine/docs/sources/commandline/command/build.rst b/components/engine/docs/sources/commandline/command/build.rst index 8d07c725c2..a8d2093a5b 100644 --- a/components/engine/docs/sources/commandline/command/build.rst +++ b/components/engine/docs/sources/commandline/command/build.rst @@ -1,3 +1,7 @@ +:title: Build Command +:description: Build a new image from the Dockerfile passed via stdin +:keywords: build, docker, container, documentation + ======================================================== ``build`` -- Build a container from Dockerfile via stdin ======================================================== diff --git a/components/engine/docs/sources/commandline/command/commit.rst b/components/engine/docs/sources/commandline/command/commit.rst index 1d5c503414..92f3205662 100644 --- a/components/engine/docs/sources/commandline/command/commit.rst +++ b/components/engine/docs/sources/commandline/command/commit.rst @@ -1,3 +1,7 @@ +:title: Commit Command +:description: Create a new image from a container's changes +:keywords: commit, docker, container, documentation + =========================================================== ``commit`` -- Create a new image from a container's changes =========================================================== diff --git a/components/engine/docs/sources/commandline/command/diff.rst b/components/engine/docs/sources/commandline/command/diff.rst index 301da6c499..2901a7f215 100644 --- a/components/engine/docs/sources/commandline/command/diff.rst +++ b/components/engine/docs/sources/commandline/command/diff.rst @@ -1,3 +1,7 @@ +:title: Diff Command +:description: Inspect changes on a container's filesystem +:keywords: diff, docker, container, documentation + ======================================================= ``diff`` -- Inspect changes on a container's filesystem ======================================================= diff --git a/components/engine/docs/sources/commandline/command/export.rst b/components/engine/docs/sources/commandline/command/export.rst index 88ecd2fd53..9d7e6b369c 100644 --- a/components/engine/docs/sources/commandline/command/export.rst +++ b/components/engine/docs/sources/commandline/command/export.rst @@ -1,3 +1,7 @@ +:title: Export Command +:description: Export the contents of a filesystem as a tar archive +:keywords: export, docker, container, documentation + ================================================================= ``export`` -- Stream the contents of a container as a tar archive ================================================================= diff --git a/components/engine/docs/sources/commandline/command/history.rst b/components/engine/docs/sources/commandline/command/history.rst index 92fad3b487..2f9d3f2814 100644 --- a/components/engine/docs/sources/commandline/command/history.rst +++ b/components/engine/docs/sources/commandline/command/history.rst @@ -1,3 +1,7 @@ +:title: History Command +:description: Show the history of an image +:keywords: history, docker, container, documentation + =========================================== ``history`` -- Show the history of an image =========================================== diff --git a/components/engine/docs/sources/commandline/command/images.rst b/components/engine/docs/sources/commandline/command/images.rst index 5bcfe817f4..497bda6e16 100644 --- a/components/engine/docs/sources/commandline/command/images.rst +++ b/components/engine/docs/sources/commandline/command/images.rst @@ -1,3 +1,7 @@ +:title: Images Command +:description: List images +:keywords: images, docker, container, documentation + ========================= ``images`` -- List images ========================= diff --git a/components/engine/docs/sources/commandline/command/import.rst b/components/engine/docs/sources/commandline/command/import.rst index 5fe90764b9..34a7138e07 100644 --- a/components/engine/docs/sources/commandline/command/import.rst +++ b/components/engine/docs/sources/commandline/command/import.rst @@ -1,3 +1,7 @@ +:title: Import Command +:description: Create a new filesystem image from the contents of a tarball +:keywords: import, tarball, docker, url, documentation + ========================================================================== ``import`` -- Create a new filesystem image from the contents of a tarball ========================================================================== diff --git a/components/engine/docs/sources/commandline/command/info.rst b/components/engine/docs/sources/commandline/command/info.rst index 10697dba18..6df3486c53 100644 --- a/components/engine/docs/sources/commandline/command/info.rst +++ b/components/engine/docs/sources/commandline/command/info.rst @@ -1,3 +1,7 @@ +:title: Info Command +:description: Display system-wide information. +:keywords: info, docker, information, documentation + =========================================== ``info`` -- Display system-wide information =========================================== diff --git a/components/engine/docs/sources/commandline/command/inspect.rst b/components/engine/docs/sources/commandline/command/inspect.rst index 34365d1f26..90dbe959eb 100644 --- a/components/engine/docs/sources/commandline/command/inspect.rst +++ b/components/engine/docs/sources/commandline/command/inspect.rst @@ -1,3 +1,7 @@ +:title: Inspect Command +:description: Return low-level information on a container +:keywords: inspect, container, docker, documentation + ========================================================== ``inspect`` -- Return low-level information on a container ========================================================== diff --git a/components/engine/docs/sources/commandline/command/kill.rst b/components/engine/docs/sources/commandline/command/kill.rst index cbd019e1a9..f53d3883b0 100644 --- a/components/engine/docs/sources/commandline/command/kill.rst +++ b/components/engine/docs/sources/commandline/command/kill.rst @@ -1,3 +1,7 @@ +:title: Kill Command +:description: Kill a running container +:keywords: kill, container, docker, documentation + ==================================== ``kill`` -- Kill a running container ==================================== diff --git a/components/engine/docs/sources/commandline/command/login.rst b/components/engine/docs/sources/commandline/command/login.rst index b064b40145..bab4fa34e3 100644 --- a/components/engine/docs/sources/commandline/command/login.rst +++ b/components/engine/docs/sources/commandline/command/login.rst @@ -1,3 +1,7 @@ +:title: Login Command +:description: Register or Login to the docker registry server +:keywords: login, docker, documentation + ============================================================ ``login`` -- Register or Login to the docker registry server ============================================================ diff --git a/components/engine/docs/sources/commandline/command/logs.rst b/components/engine/docs/sources/commandline/command/logs.rst index 87f3f95b65..a3423f6e0c 100644 --- a/components/engine/docs/sources/commandline/command/logs.rst +++ b/components/engine/docs/sources/commandline/command/logs.rst @@ -1,3 +1,7 @@ +:title: Logs Command +:description: Fetch the logs of a container +:keywords: logs, container, docker, documentation + ========================================= ``logs`` -- Fetch the logs of a container ========================================= diff --git a/components/engine/docs/sources/commandline/command/port.rst b/components/engine/docs/sources/commandline/command/port.rst index 4fb6d7f812..8d59fedab6 100644 --- a/components/engine/docs/sources/commandline/command/port.rst +++ b/components/engine/docs/sources/commandline/command/port.rst @@ -1,3 +1,7 @@ +:title: Port Command +:description: Lookup the public-facing port which is NAT-ed to PRIVATE_PORT +:keywords: port, docker, container, documentation + ========================================================================= ``port`` -- Lookup the public-facing port which is NAT-ed to PRIVATE_PORT ========================================================================= diff --git a/components/engine/docs/sources/commandline/command/ps.rst b/components/engine/docs/sources/commandline/command/ps.rst index f73177918b..597dbd9ae7 100644 --- a/components/engine/docs/sources/commandline/command/ps.rst +++ b/components/engine/docs/sources/commandline/command/ps.rst @@ -1,3 +1,7 @@ +:title: Ps Command +:description: List containers +:keywords: ps, docker, documentation, container + ========================= ``ps`` -- List containers ========================= diff --git a/components/engine/docs/sources/commandline/command/pull.rst b/components/engine/docs/sources/commandline/command/pull.rst index 1c417ddcde..4348f28d0f 100644 --- a/components/engine/docs/sources/commandline/command/pull.rst +++ b/components/engine/docs/sources/commandline/command/pull.rst @@ -1,3 +1,7 @@ +:title: Pull Command +:description: Pull an image or a repository from the registry +:keywords: pull, image, repo, repository, documentation, docker + ========================================================================= ``pull`` -- Pull an image or a repository from the docker registry server ========================================================================= diff --git a/components/engine/docs/sources/commandline/command/push.rst b/components/engine/docs/sources/commandline/command/push.rst index a42296c715..9304f9acc5 100644 --- a/components/engine/docs/sources/commandline/command/push.rst +++ b/components/engine/docs/sources/commandline/command/push.rst @@ -1,3 +1,7 @@ +:title: Push Command +:description: Push an image or a repository to the registry +:keywords: push, docker, image, repository, documentation, repo + ======================================================================= ``push`` -- Push an image or a repository to the docker registry server ======================================================================= diff --git a/components/engine/docs/sources/commandline/command/restart.rst b/components/engine/docs/sources/commandline/command/restart.rst index 24bba5a5a9..dfc0dfea6e 100644 --- a/components/engine/docs/sources/commandline/command/restart.rst +++ b/components/engine/docs/sources/commandline/command/restart.rst @@ -1,3 +1,7 @@ +:title: Restart Command +:description: Restart a running container +:keywords: restart, container, docker, documentation + ========================================== ``restart`` -- Restart a running container ========================================== diff --git a/components/engine/docs/sources/commandline/command/rm.rst b/components/engine/docs/sources/commandline/command/rm.rst index f6d6893bfb..dc6d91632d 100644 --- a/components/engine/docs/sources/commandline/command/rm.rst +++ b/components/engine/docs/sources/commandline/command/rm.rst @@ -1,3 +1,7 @@ +:title: Rm Command +:description: Remove a container +:keywords: remove, container, docker, documentation, rm + ============================ ``rm`` -- Remove a container ============================ diff --git a/components/engine/docs/sources/commandline/command/rmi.rst b/components/engine/docs/sources/commandline/command/rmi.rst index 3761196f23..a0131886d6 100644 --- a/components/engine/docs/sources/commandline/command/rmi.rst +++ b/components/engine/docs/sources/commandline/command/rmi.rst @@ -1,3 +1,7 @@ +:title: Rmi Command +:description: Remove an image +:keywords: rmi, remove, image, docker, documentation + ========================== ``rmi`` -- Remove an image ========================== diff --git a/components/engine/docs/sources/commandline/command/run.rst b/components/engine/docs/sources/commandline/command/run.rst index 95fb208dd3..d6c9aef315 100644 --- a/components/engine/docs/sources/commandline/command/run.rst +++ b/components/engine/docs/sources/commandline/command/run.rst @@ -1,3 +1,7 @@ +:title: Run Command +:description: Run a command in a new container +:keywords: run, container, docker, documentation + =========================================== ``run`` -- Run a command in a new container =========================================== @@ -19,5 +23,5 @@ -t=false: Allocate a pseudo-tty -u="": Username or UID -d=[]: Set custom dns servers for the container - -v=[]: Creates a new volumes and mount it at the specified path. + -v=[]: Creates a new volume and mounts it at the specified path. -volumes-from="": Mount all volumes from the given container. diff --git a/components/engine/docs/sources/commandline/command/search.rst b/components/engine/docs/sources/commandline/command/search.rst index 0af24dfaf5..2f07e20c3a 100644 --- a/components/engine/docs/sources/commandline/command/search.rst +++ b/components/engine/docs/sources/commandline/command/search.rst @@ -1,3 +1,7 @@ +:title: Search Command +:description: Searches for the TERM parameter on the Docker index and prints out a list of repositories that match. +:keywords: search, docker, image, documentation + =================================================================== ``search`` -- Search for an image in the docker index =================================================================== diff --git a/components/engine/docs/sources/commandline/command/start.rst b/components/engine/docs/sources/commandline/command/start.rst index df415ca3d3..b70ad21cfd 100644 --- a/components/engine/docs/sources/commandline/command/start.rst +++ b/components/engine/docs/sources/commandline/command/start.rst @@ -1,3 +1,7 @@ +:title: Start Command +:description: Start a stopped container +:keywords: start, docker, container, documentation + ====================================== ``start`` -- Start a stopped container ====================================== diff --git a/components/engine/docs/sources/commandline/command/stop.rst b/components/engine/docs/sources/commandline/command/stop.rst index df6d66ccf9..3d571563ec 100644 --- a/components/engine/docs/sources/commandline/command/stop.rst +++ b/components/engine/docs/sources/commandline/command/stop.rst @@ -1,3 +1,7 @@ +:title: Stop Command +:description: Stop a running container +:keywords: stop, container, docker, documentation + ==================================== ``stop`` -- Stop a running container ==================================== diff --git a/components/engine/docs/sources/commandline/command/tag.rst b/components/engine/docs/sources/commandline/command/tag.rst index 59647355e9..a9e831aae9 100644 --- a/components/engine/docs/sources/commandline/command/tag.rst +++ b/components/engine/docs/sources/commandline/command/tag.rst @@ -1,3 +1,7 @@ +:title: Tag Command +:description: Tag an image into a repository +:keywords: tag, docker, image, repository, documentation, repo + ========================================= ``tag`` -- Tag an image into a repository ========================================= diff --git a/components/engine/docs/sources/commandline/command/version.rst b/components/engine/docs/sources/commandline/command/version.rst index eedf02f2d0..fb3d3b450e 100644 --- a/components/engine/docs/sources/commandline/command/version.rst +++ b/components/engine/docs/sources/commandline/command/version.rst @@ -1,3 +1,7 @@ +:title: Version Command +:description: +:keywords: version, docker, documentation + ================================================== ``version`` -- Show the docker version information ================================================== diff --git a/components/engine/docs/sources/commandline/command/wait.rst b/components/engine/docs/sources/commandline/command/wait.rst index 2959bf880b..23bd54513c 100644 --- a/components/engine/docs/sources/commandline/command/wait.rst +++ b/components/engine/docs/sources/commandline/command/wait.rst @@ -1,3 +1,7 @@ +:title: Wait Command +:description: Block until a container stops, then print its exit code. +:keywords: wait, docker, container, documentation + =================================================================== ``wait`` -- Block until a container stops, then print its exit code =================================================================== diff --git a/components/engine/docs/sources/commandline/index.rst b/components/engine/docs/sources/commandline/index.rst index fecf8e4885..f1a3e2da45 100644 --- a/components/engine/docs/sources/commandline/index.rst +++ b/components/engine/docs/sources/commandline/index.rst @@ -1,6 +1,6 @@ -:title: docker documentation +:title: Commands :description: -- todo: change me -:keywords: todo: change me +:keywords: todo, commands, command line, help, docker, documentation Commands diff --git a/components/engine/docs/sources/concepts/buildingblocks.rst b/components/engine/docs/sources/concepts/buildingblocks.rst index 154ef00f45..5f752ea47b 100644 --- a/components/engine/docs/sources/concepts/buildingblocks.rst +++ b/components/engine/docs/sources/concepts/buildingblocks.rst @@ -1,4 +1,4 @@ -:title: Building blocks +:title: Building Blocks :description: An introduction to docker and standard containers? :keywords: containers, lxc, concepts, explanation diff --git a/components/engine/docs/sources/concepts/containers.rst b/components/engine/docs/sources/concepts/containers.rst index 8378a7e29f..e08c3654c0 100644 --- a/components/engine/docs/sources/concepts/containers.rst +++ b/components/engine/docs/sources/concepts/containers.rst @@ -1,6 +1,6 @@ :title: Introduction :description: An introduction to docker and standard containers? -:keywords: containers, lxc, concepts, explanation +:keywords: containers, lxc, concepts, explanation, docker, documentation :note: This version of the introduction is temporary, just to make sure we don't break the links from the website when the documentation is updated diff --git a/components/engine/docs/sources/concepts/index.rst b/components/engine/docs/sources/concepts/index.rst index d8e1af5770..ba1f9f4718 100644 --- a/components/engine/docs/sources/concepts/index.rst +++ b/components/engine/docs/sources/concepts/index.rst @@ -1,6 +1,6 @@ -:title: docker documentation +:title: Concepts :description: -- todo: change me -:keywords: todo: change me +:keywords: concepts, documentation, docker, containers diff --git a/components/engine/docs/sources/contributing/contributing.rst b/components/engine/docs/sources/contributing/contributing.rst index 7b2b4da2d3..c2bd7c80fb 100644 --- a/components/engine/docs/sources/contributing/contributing.rst +++ b/components/engine/docs/sources/contributing/contributing.rst @@ -1,3 +1,7 @@ +:title: Contribution Guidelines +:description: Contribution guidelines: create issues, convetions, pull requests +:keywords: contributing, docker, documentation, help, guideline + Contributing to Docker ====================== diff --git a/components/engine/docs/sources/examples/python_web_app.rst b/components/engine/docs/sources/examples/python_web_app.rst index 992a09dc42..952ef62e33 100644 --- a/components/engine/docs/sources/examples/python_web_app.rst +++ b/components/engine/docs/sources/examples/python_web_app.rst @@ -40,7 +40,7 @@ We attach to the new container to see what is going on. Ctrl-C to disconnect .. code-block:: bash - BUILD_IMG=$(docker commit $BUILD_JOB _/builds/github.com/hykes/helloflask/master) + BUILD_IMG=$(docker commit $BUILD_JOB _/builds/github.com/shykes/helloflask/master) Save the changed we just made in the container to a new image called "_/builds/github.com/hykes/helloflask/master" and save the image id in the BUILD_IMG variable name. @@ -58,7 +58,7 @@ Use the new image we just created and create a new container with network port 5 .. code-block:: bash docker logs $WEB_WORKER - * Running on \http://0.0.0.0:5000/ + * Running on http://0.0.0.0:5000/ view the logs for the new container using the WEB_WORKER variable, and if everything worked as planned you should see the line "Running on http://0.0.0.0:5000/" in the log output. @@ -70,7 +70,8 @@ lookup the public-facing port which is NAT-ed store the private port used by the .. code-block:: bash - curl \http://`hostname`:$WEB_PORT + # install curl if necessary, then ... + curl http://127.0.0.1:$WEB_PORT Hello world! access the web app using curl. If everything worked as planned you should see the line "Hello world!" inside of your console. diff --git a/components/engine/docs/sources/faq.rst b/components/engine/docs/sources/faq.rst index b96ed06437..901e51ddbb 100644 --- a/components/engine/docs/sources/faq.rst +++ b/components/engine/docs/sources/faq.rst @@ -1,3 +1,7 @@ +:title: FAQ +:description: Most frequently asked questions. +:keywords: faq, questions, documentation, docker + FAQ === diff --git a/components/engine/docs/sources/index/variable.rst b/components/engine/docs/sources/index/variable.rst index efbcfae80c..90eac3af8a 100644 --- a/components/engine/docs/sources/index/variable.rst +++ b/components/engine/docs/sources/index/variable.rst @@ -1,3 +1,7 @@ +:title: Index Environment Variable +:description: Setting this environment variable on the docker server will change the URL docker index. +:keywords: docker, index environment variable, documentation + ================================= Docker Index Environment Variable ================================= diff --git a/components/engine/docs/sources/installation/amazon.rst b/components/engine/docs/sources/installation/amazon.rst index 64ff20f8be..59896bb63c 100644 --- a/components/engine/docs/sources/installation/amazon.rst +++ b/components/engine/docs/sources/installation/amazon.rst @@ -1,3 +1,7 @@ +:title: Installation on Amazon EC2 +:description: Docker installation on Amazon EC2 with a single vagrant command. Vagrant 1.1 or higher is required. +:keywords: amazon ec2, virtualization, cloud, docker, documentation, installation + Amazon EC2 ========== diff --git a/components/engine/docs/sources/installation/archlinux.rst b/components/engine/docs/sources/installation/archlinux.rst index db013c6cb9..9e3766eb26 100644 --- a/components/engine/docs/sources/installation/archlinux.rst +++ b/components/engine/docs/sources/installation/archlinux.rst @@ -1,3 +1,7 @@ +:title: Installation on Arch Linux +:description: Docker installation on Arch Linux. +:keywords: arch linux, virtualization, docker, documentation, installation + .. _arch_linux: Arch Linux diff --git a/components/engine/docs/sources/installation/binaries.rst b/components/engine/docs/sources/installation/binaries.rst index 25d13ab68e..e7a07b6db1 100644 --- a/components/engine/docs/sources/installation/binaries.rst +++ b/components/engine/docs/sources/installation/binaries.rst @@ -1,3 +1,7 @@ +:title: Installation from Binaries +:description: This instruction set is meant for hackers who want to try out Docker on a variety of environments. +:keywords: binaries, installation, docker, documentation, linux + .. _binaries: Binaries @@ -23,7 +27,7 @@ But we know people have had success running it under Dependencies: ------------- -* 3.8 Kernel +* 3.8 Kernel (read more about :ref:`kernel`) * AUFS filesystem support * lxc * bsdtar diff --git a/components/engine/docs/sources/installation/index.rst b/components/engine/docs/sources/installation/index.rst index 1976f30ba0..9f831091cf 100644 --- a/components/engine/docs/sources/installation/index.rst +++ b/components/engine/docs/sources/installation/index.rst @@ -1,6 +1,6 @@ -:title: docker documentation +:title: Documentation :description: -- todo: change me -:keywords: todo: change me +:keywords: todo, docker, documentation, installation, OS support diff --git a/components/engine/docs/sources/installation/kernel.rst b/components/engine/docs/sources/installation/kernel.rst index 2ec5940a7f..6f242e9e10 100644 --- a/components/engine/docs/sources/installation/kernel.rst +++ b/components/engine/docs/sources/installation/kernel.rst @@ -1,63 +1,35 @@ +:title: Kernel Requirements +:description: Kernel supports +:keywords: kernel requirements, kernel support, docker, installation, cgroups, namespaces + .. _kernel: Kernel Requirements =================== +In short, Docker has the following kernel requirements: + +- Linux version 3.8 or above. + +- `AUFS support `_. + +- Cgroups and namespaces must be enabled. + + The officially supported kernel is the one recommended by the :ref:`ubuntu_linux` installation path. It is the one that most developers will use, and the one that receives the most attention from the core contributors. If you decide to go with a different kernel and hit a bug, please try to reproduce it with the official kernels first. -If for some reason you cannot or do not want to use the "official" kernels, +If you cannot or do not want to use the "official" kernels, here is some technical background about the features (both optional and mandatory) that docker needs to run successfully. -In short, you need kernel version 3.8 (or above), compiled to include -`AUFS support `_. Of course, you need to -enable cgroups and namespaces. +Linux version 3.8 or above +-------------------------- - -Namespaces and Cgroups ----------------------- - -You need to enable namespaces and cgroups, to the extend of what is needed -to run LXC containers. Technically, while namespaces have been introduced -in the early 2.6 kernels, we do not advise to try any kernel before 2.6.32 -to run LXC containers. Note that 2.6.32 has some documented issues regarding -network namespace setup and teardown; those issues are not a risk if you -run containers in a private environment, but can lead to denial-of-service -attacks if you want to run untrusted code in your containers. For more details, -see `[LP#720095 `_. - -Kernels 2.6.38, and every version since 3.2, have been deployed successfully -to run containerized production workloads. Feature-wise, there is no huge -improvement between 2.6.38 and up to 3.6 (as far as docker is concerned!). - -Starting with version 3.7, the kernel has basic support for -`Checkpoint/Restore In Userspace `_, which is not used by -docker at this point, but allows to suspend the state of a container to -disk and resume it later. - -Version 3.8 provides improvements in stability, which are deemed necessary -for the operation of docker. Versions 3.2 to 3.5 have been shown to -exhibit a reproducible bug (for more details, see issue -`#407 `_). - -Version 3.8 also brings better support for the -`setns() syscall `_ -- but this should not -be a concern since docker does not leverage on this feature for now. - -If you want a technical overview about those concepts, you might -want to check those articles on dotCloud's blog: -`about namespaces `_ -and `about cgroups `_. - - -Important Note About Pre-3.8 Kernels ------------------------------------- - -As mentioned above, kernels before 3.8 are not stable when used with docker. +Kernel versions 3.2 to 3.5 are not stable when used with docker. In some circumstances, you will experience kernel "oopses", or even crashes. The symptoms include: @@ -77,6 +49,36 @@ detects something older than 3.8. See issue `#407 `_ for details. +AUFS support +------------ + +Docker currently relies on AUFS, an unioning filesystem. +While AUFS is included in the kernels built by the Debian and Ubuntu +distributions, is not part of the standard kernel. This means that if +you decide to roll your own kernel, you will have to patch your +kernel tree to add AUFS. The process is documented on +`AUFS webpage `_. + + +Cgroups and namespaces +---------------------- + +You need to enable namespaces and cgroups, to the extend of what is needed +to run LXC containers. Technically, while namespaces have been introduced +in the early 2.6 kernels, we do not advise to try any kernel before 2.6.32 +to run LXC containers. Note that 2.6.32 has some documented issues regarding +network namespace setup and teardown; those issues are not a risk if you +run containers in a private environment, but can lead to denial-of-service +attacks if you want to run untrusted code in your containers. For more details, +see `[LP#720095 `_. + +Kernels 2.6.38, and every version since 3.2, have been deployed successfully +to run containerized production workloads. Feature-wise, there is no huge +improvement between 2.6.38 and up to 3.6 (as far as docker is concerned!). + + + + Extra Cgroup Controllers ------------------------ @@ -111,39 +113,3 @@ And replace it by the following one:: GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount" Then run ``update-grub``, and reboot. - - -AUFS ----- - -Docker currently relies on AUFS, an unioning filesystem. -While AUFS is included in the kernels built by the Debian and Ubuntu -distributions, is not part of the standard kernel. This means that if -you decide to roll your own kernel, you will have to patch your -kernel tree to add AUFS. The process is documented on -`AUFS webpage `_. - -Note: the AUFS patch is fairly intrusive, but for the record, people have -successfully applied GRSEC and AUFS together, to obtain hardened production -kernels. - -If you want more information about that topic, there is an -`article about AUFS on dotCloud's blog -`_. - - -BTRFS, ZFS, OverlayFS... ------------------------- - -There is ongoing development on docker, to implement support for -`BTRFS `_ -(see github issue `#443 `_). - -People have also showed interest for `ZFS `_ -(using e.g. `ZFS-on-Linux `_) and OverlayFS. -The latter is functionally close to AUFS, and it might end up being included -in the stock kernel; so it's a strong candidate! - -Would you like to `contribute -`_ -support for your favorite filesystem? diff --git a/components/engine/docs/sources/installation/rackspace.rst b/components/engine/docs/sources/installation/rackspace.rst index dfb88aee84..7482404683 100644 --- a/components/engine/docs/sources/installation/rackspace.rst +++ b/components/engine/docs/sources/installation/rackspace.rst @@ -1,3 +1,7 @@ +:title: Rackspace Cloud Installation +:description: Installing Docker on Ubuntu proviced by Rackspace +:keywords: Rackspace Cloud, installation, docker, linux, ubuntu + =============== Rackspace Cloud =============== diff --git a/components/engine/docs/sources/installation/ubuntulinux.rst b/components/engine/docs/sources/installation/ubuntulinux.rst index de4a2bb9ca..ac94913ebc 100644 --- a/components/engine/docs/sources/installation/ubuntulinux.rst +++ b/components/engine/docs/sources/installation/ubuntulinux.rst @@ -1,3 +1,7 @@ +:title: Requirements and Installation on Ubuntu Linux +:description: Please note this project is currently under heavy development. It should not be used in production. +:keywords: Docker, Docker documentation, requirements, virtualbox, vagrant, git, ssh, putty, cygwin, linux + .. _ubuntu_linux: Ubuntu Linux @@ -12,7 +16,7 @@ Right now, the officially supported distribution are: Docker has the following dependencies -* Linux kernel 3.8 +* Linux kernel 3.8 (read more about :ref:`kernel`) * AUFS file system support (we are working on BTRFS support as an alternative) .. _ubuntu_precise: @@ -34,7 +38,7 @@ Due to a bug in LXC docker works best on the 3.8 kernel. Precise comes with a 3. .. code-block:: bash # install the backported kernel - sudo apt-get update && sudo apt-get install linux-image-3.8.0-19-generic + sudo apt-get update && sudo apt-get install linux-image-generic-lts-raring # reboot sudo reboot diff --git a/components/engine/docs/sources/installation/upgrading.rst b/components/engine/docs/sources/installation/upgrading.rst index 8dfde73891..9fa47904be 100644 --- a/components/engine/docs/sources/installation/upgrading.rst +++ b/components/engine/docs/sources/installation/upgrading.rst @@ -1,3 +1,7 @@ +:title: Upgrading +:description: These instructions are for upgrading Docker +:keywords: Docker, Docker documentation, upgrading docker, upgrade + .. _upgrading: Upgrading diff --git a/components/engine/docs/sources/installation/vagrant.rst b/components/engine/docs/sources/installation/vagrant.rst index d1a76b5a2b..24a1e91354 100644 --- a/components/engine/docs/sources/installation/vagrant.rst +++ b/components/engine/docs/sources/installation/vagrant.rst @@ -1,3 +1,6 @@ +:title: Using Vagrant (Mac, Linux) +:description: This guide will setup a new virtualbox virtual machine with docker installed on your computer. +:keywords: Docker, Docker documentation, virtualbox, vagrant, git, ssh, putty, cygwin .. _install_using_vagrant: diff --git a/components/engine/docs/sources/toctree.rst b/components/engine/docs/sources/toctree.rst index 09f2a7af5b..ae6d5f010c 100644 --- a/components/engine/docs/sources/toctree.rst +++ b/components/engine/docs/sources/toctree.rst @@ -1,6 +1,6 @@ -:title: docker documentation -:description: docker documentation -:keywords: +:title: Documentation +:description: -- todo: change me +:keywords: todo, docker, documentation, installation, usage, examples, contributing, faq, command line, concepts Documentation ============= diff --git a/components/engine/docs/sources/use/basics.rst b/components/engine/docs/sources/use/basics.rst index ffd2a7b96c..378028703c 100644 --- a/components/engine/docs/sources/use/basics.rst +++ b/components/engine/docs/sources/use/basics.rst @@ -1,6 +1,6 @@ -:title: Base commands +:title: Basic Commands :description: Common usage and commands -:keywords: Examples, Usage +:keywords: Examples, Usage, basic commands, docker, documentation, examples The basics @@ -33,6 +33,19 @@ Running an interactive shell # allocate a tty, attach stdin and stdout docker run -i -t base /bin/bash +Bind Docker to another host/port +-------------------------------- + +If you want Docker to listen to another port and bind to another ip +use -host and -port on both deamon and client + +.. code-block:: bash + + # Run docker in daemon mode + sudo /docker -H 0.0.0.0:5555 & + # Download a base image + docker -H :5555 pull base + Starting a long-running worker process -------------------------------------- diff --git a/components/engine/docs/sources/use/builder.rst b/components/engine/docs/sources/use/builder.rst index 84d275782e..4e53ed4a79 100644 --- a/components/engine/docs/sources/use/builder.rst +++ b/components/engine/docs/sources/use/builder.rst @@ -1,3 +1,7 @@ +:title: Docker Builder +:description: Docker Builder specifes a simple DSL which allows you to automate the steps you would normally manually take to create an image. +:keywords: builder, docker, Docker Builder, automation, image creation + ============== Docker Builder ============== diff --git a/components/engine/docs/sources/use/index.rst b/components/engine/docs/sources/use/index.rst index 9939dc7ea8..a1086c1fd2 100644 --- a/components/engine/docs/sources/use/index.rst +++ b/components/engine/docs/sources/use/index.rst @@ -1,6 +1,6 @@ -:title: docker documentation +:title: Documentation :description: -- todo: change me -:keywords: todo: change me +:keywords: todo, docker, documentation, basic, builder diff --git a/components/engine/docs/sources/use/puppet.rst b/components/engine/docs/sources/use/puppet.rst index af2d5c8d57..5606f2a863 100644 --- a/components/engine/docs/sources/use/puppet.rst +++ b/components/engine/docs/sources/use/puppet.rst @@ -1,3 +1,6 @@ +:title: Puppet Usage +:description: Installating and using Puppet +:keywords: puppet, installation, usage, docker, documentation .. _install_using_puppet: @@ -22,9 +25,9 @@ Installation The module is available on the `Puppet Forge `_ and can be installed using the built-in module tool. - .. code-block:: bash +.. code-block:: bash - puppet module install garethr/docker + puppet module install garethr/docker It can also be found on `GitHub `_ if you would rather download the source. @@ -38,9 +41,9 @@ for managing images and containers. Installation ~~~~~~~~~~~~ - .. code-block:: ruby +.. code-block:: ruby - include 'docker' + include 'docker' Images ~~~~~~ @@ -48,26 +51,26 @@ Images The next step is probably to install a docker image, for this we have a defined type which can be used like so: - .. code-block:: ruby +.. code-block:: ruby - docker::image { 'base': } + docker::image { 'base': } This is equivalent to running: - .. code-block:: bash +.. code-block:: bash - docker pull base + docker pull base Note that it will only if the image of that name does not already exist. This is downloading a large binary so on first run can take a while. For that reason this define turns off the default 5 minute timeout for exec. Note that you can also remove images you no longer need with: - .. code-block:: ruby +.. code-block:: ruby - docker::image { 'base': - ensure => 'absent', - } + docker::image { 'base': + ensure => 'absent', + } Containers ~~~~~~~~~~ @@ -75,35 +78,35 @@ Containers Now you have an image you can run commands within a container managed by docker. - .. code-block:: ruby +.. code-block:: ruby - docker::run { 'helloworld': - image => 'base', - command => '/bin/sh -c "while true; do echo hello world; sleep 1; done"', - } + docker::run { 'helloworld': + image => 'base', + command => '/bin/sh -c "while true; do echo hello world; sleep 1; done"', + } This is equivalent to running the following command, but under upstart: - .. code-block:: bash +.. code-block:: bash - docker run -d base /bin/sh -c "while true; do echo hello world; sleep 1; done" + docker run -d base /bin/sh -c "while true; do echo hello world; sleep 1; done" Run also contains a number of optional parameters: - .. code-block:: ruby +.. code-block:: ruby - docker::run { 'helloworld': - image => 'base', - command => '/bin/sh -c "while true; do echo hello world; sleep 1; done"', - ports => ['4444', '4555'], - volumes => ['/var/lib/counchdb', '/var/log'], - volumes_from => '6446ea52fbc9', - memory_limit => 10485760, # bytes - username => 'example', - hostname => 'example.com', - env => ['FOO=BAR', 'FOO2=BAR2'], - dns => ['8.8.8.8', '8.8.4.4'], - } + docker::run { 'helloworld': + image => 'base', + command => '/bin/sh -c "while true; do echo hello world; sleep 1; done"', + ports => ['4444', '4555'], + volumes => ['/var/lib/counchdb', '/var/log'], + volumes_from => '6446ea52fbc9', + memory_limit => 10485760, # bytes + username => 'example', + hostname => 'example.com', + env => ['FOO=BAR', 'FOO2=BAR2'], + dns => ['8.8.8.8', '8.8.4.4'], + } Note that ports, env, dns and volumes can be set with either a single string or as above with an array of values. diff --git a/components/engine/docs/sources/use/workingwithrepository.rst b/components/engine/docs/sources/use/workingwithrepository.rst index c1ce7f455e..9a2f96cf0d 100644 --- a/components/engine/docs/sources/use/workingwithrepository.rst +++ b/components/engine/docs/sources/use/workingwithrepository.rst @@ -1,3 +1,7 @@ +:title: Working With Repositories +:description: Generally, there are two types of repositories: Top-level repositories which are controlled by the people behind Docker, and user repositories. +:keywords: repo, repositiores, usage, pull image, push image, image, documentation + .. _working_with_the_repository: Working with the repository diff --git a/components/engine/docs/theme/docker/layout.html b/components/engine/docs/theme/docker/layout.html index aa5a24d496..d212c9ca86 100755 --- a/components/engine/docs/theme/docker/layout.html +++ b/components/engine/docs/theme/docker/layout.html @@ -8,7 +8,7 @@ - Docker - {{ meta['title'] if meta and meta['title'] else title }} + {{ meta['title'] if meta and meta['title'] else title }} - Docker Documentation diff --git a/components/engine/docs/website/index.html b/components/engine/docs/website/index.html index 2dad365ce4..d441ed8d78 100644 --- a/components/engine/docs/website/index.html +++ b/components/engine/docs/website/index.html @@ -198,6 +198,35 @@
+ +
+
+
+ + Mitchell Hashimoto‏@mitchellh: Docker launched today. It is incredible. They’re also working RIGHT NOW on a Vagrant provider. LXC is COMING!! +
+
+
+
+ + Adam Jacob‏@adamhjk: Docker is clearly the right idea. @solomonstre absolutely killed it. Containerized app deployment is the future, I think. +
+
+
+
+
+
+ + Matt Townsend‏@mtownsend: I have a serious code crush on docker.io - it's Lego for PaaS. Motherfucking awesome Lego. +
+
+
+
+ + Rob Harrop‏@robertharrop: Impressed by @getdocker - it's all kinds of magic. Serious rethink of AWS architecture happening @skillsmatter. +
+
+
diff --git a/components/engine/graph.go b/components/engine/graph.go index 5bf305fc22..c0dd869227 100644 --- a/components/engine/graph.go +++ b/components/engine/graph.go @@ -165,7 +165,7 @@ func (graph *Graph) TempLayerArchive(id string, compression Compression, output if err != nil { return nil, err } - return NewTempArchive(utils.ProgressReader(ioutil.NopCloser(archive), 0, output, "Buffering to disk %v/%v (%v)"), tmp.Root) + return NewTempArchive(utils.ProgressReader(ioutil.NopCloser(archive), 0, output, "Buffering to disk %v/%v (%v)", false), tmp.Root) } // Mktemp creates a temporary sub-directory inside the graph's filesystem. diff --git a/components/engine/packaging/ubuntu/changelog b/components/engine/packaging/ubuntu/changelog index 2e4907f200..c8a8c1689b 100644 --- a/components/engine/packaging/ubuntu/changelog +++ b/components/engine/packaging/ubuntu/changelog @@ -1,37 +1,44 @@ +lxc-docker (0.3.3-1) precise; urgency=low + - Registry: Fix push regression + - Various bugfixes + + -- dotCloud Thu, 23 May 2013 00:00:00 -0700 + + lxc-docker (0.3.2-1) precise; urgency=low - - Runtime: Store the actual archive on commit - - Registry: Improve the checksum process - - Registry: Use the size to have a good progress bar while pushing - - Registry: Use the actual archive if it exists in order to speed up the push - - Registry: Fix error 400 on push + - Runtime: Store the actual archive on commit + - Registry: Improve the checksum process + - Registry: Use the size to have a good progress bar while pushing + - Registry: Use the actual archive if it exists in order to speed up the push + - Registry: Fix error 400 on push -- dotCloud Fri, 9 May 2013 00:00:00 -0700 lxc-docker (0.3.1-1) precise; urgency=low - - Builder: Implement the autorun capability within docker builder - - Builder: Add caching to docker builder - - Builder: Add support for docker builder with native API as top level command - - Runtime: Add go version to debug infos - - Builder: Implement ENV within docker builder - - Registry: Add docker search top level command in order to search a repository - - Images: output graph of images to dot (graphviz) - - Documentation: new introduction and high-level overview - - Documentation: Add the documentation for docker builder - - Website: new high-level overview - - Makefile: Swap "go get" for "go get -d", especially to compile on go1.1rc - - Images: fix ByParent function - - Builder: Check the command existance prior create and add Unit tests for the case - - Registry: Fix pull for official images with specific tag - - Registry: Fix issue when login in with a different user and trying to push - - Documentation: CSS fix for docker documentation to make REST API docs look better. - - Documentation: Fixed CouchDB example page header mistake - - Documentation: fixed README formatting - - Registry: Improve checksum - async calculation - - Runtime: kernel version - don't show the dash if flavor is empty - - Documentation: updated www.docker.io website. - - Builder: use any whitespaces instead of tabs - - Packaging: packaging ubuntu; issue #510: Use goland-stable PPA package to build docker + - Builder: Implement the autorun capability within docker builder + - Builder: Add caching to docker builder + - Builder: Add support for docker builder with native API as top level command + - Runtime: Add go version to debug infos + - Builder: Implement ENV within docker builder + - Registry: Add docker search top level command in order to search a repository + - Images: output graph of images to dot (graphviz) + - Documentation: new introduction and high-level overview + - Documentation: Add the documentation for docker builder + - Website: new high-level overview + - Makefile: Swap "go get" for "go get -d", especially to compile on go1.1rc + - Images: fix ByParent function + - Builder: Check the command existance prior create and add Unit tests for the case + - Registry: Fix pull for official images with specific tag + - Registry: Fix issue when login in with a different user and trying to push + - Documentation: CSS fix for docker documentation to make REST API docs look better. + - Documentation: Fixed CouchDB example page header mistake + - Documentation: fixed README formatting + - Registry: Improve checksum - async calculation + - Runtime: kernel version - don't show the dash if flavor is empty + - Documentation: updated www.docker.io website. + - Builder: use any whitespaces instead of tabs + - Packaging: packaging ubuntu; issue #510: Use goland-stable PPA package to build docker -- dotCloud Fri, 8 May 2013 00:00:00 -0700 diff --git a/components/engine/registry/registry.go b/components/engine/registry/registry.go index ce9b4b4ac7..bd361b5e74 100644 --- a/components/engine/registry/registry.go +++ b/components/engine/registry/registry.go @@ -428,9 +428,14 @@ func (r *Registry) ResetClient(authConfig *auth.AuthConfig) { r.client.Jar = cookiejar.NewCookieJar() } -func (r *Registry) GetAuthConfig() *auth.AuthConfig { +func (r *Registry) GetAuthConfig(withPasswd bool) *auth.AuthConfig { + password := "" + if withPasswd { + password = r.authConfig.Password + } return &auth.AuthConfig{ Username: r.authConfig.Username, + Password: password, Email: r.authConfig.Email, } } diff --git a/components/engine/runtime_test.go b/components/engine/runtime_test.go index 9ca280495b..27db53a884 100644 --- a/components/engine/runtime_test.go +++ b/components/engine/runtime_test.go @@ -68,11 +68,13 @@ func init() { registry: registry.NewRegistry(runtime.root), } // Retrieve the Image - if err := srv.ImagePull(unitTestImageName, "", "", os.Stdout); err != nil { + if err := srv.ImagePull(unitTestImageName, "", "", os.Stdout, false); err != nil { panic(err) } } +// FIXME: test that ImagePull(json=true) send correct json output + func newTestRuntime() (*Runtime, error) { root, err := ioutil.TempDir("", "docker-test") if err != nil { diff --git a/components/engine/server.go b/components/engine/server.go index 06f947d89f..0714cba54d 100644 --- a/components/engine/server.go +++ b/components/engine/server.go @@ -91,8 +91,8 @@ func (srv *Server) ImageInsert(name, url, path string, out io.Writer) (string, e return "", err } - if err := c.Inject(utils.ProgressReader(file.Body, int(file.ContentLength), out, "Downloading %v/%v (%v)"), path); err != nil { - return "", err + if err := c.Inject(utils.ProgressReader(file.Body, int(file.ContentLength), out, "Downloading %v/%v (%v)\r", false), path); err != nil { + return err } // FIXME: Handle custom repo, tag comment, author img, err = b.Commit(c, "", "", img.Comment, img.Author, nil) @@ -291,8 +291,7 @@ func (srv *Server) ContainerTag(name, repo, tag string, force bool) error { return nil } -func (srv *Server) pullImage(out io.Writer, imgId, registry string, token []string) error { - out = utils.NewWriteFlusher(out) +func (srv *Server) pullImage(out io.Writer, imgId, registry string, token []string, json bool) error { history, err := srv.registry.GetRemoteHistory(imgId, registry, token) if err != nil { return err @@ -302,7 +301,7 @@ func (srv *Server) pullImage(out io.Writer, imgId, registry string, token []stri // FIXME: Launch the getRemoteImage() in goroutines for _, id := range history { if !srv.runtime.graph.Exists(id) { - fmt.Fprintf(out, "Pulling %s metadata\r\n", id) + fmt.Fprintf(out, utils.FormatStatus("Pulling %s metadata", json), id) imgJson, err := srv.registry.GetRemoteImageJson(id, registry, token) if err != nil { // FIXME: Keep goging in case of error? @@ -314,12 +313,12 @@ func (srv *Server) pullImage(out io.Writer, imgId, registry string, token []stri } // Get the layer - fmt.Fprintf(out, "Pulling %s fs layer\r\n", img.Id) + fmt.Fprintf(out, utils.FormatStatus("Pulling %s fs layer", json), id) layer, contentLength, err := srv.registry.GetRemoteImageLayer(img.Id, registry, token) if err != nil { return err } - if err := srv.runtime.graph.Register(utils.ProgressReader(layer, contentLength, out, "Downloading %v/%v (%v)"), false, img); err != nil { + if err := srv.runtime.graph.Register(utils.ProgressReader(layer, contentLength, out, utils.FormatProgress("%v/%v (%v)", json), json), false, img); err != nil { return err } } @@ -327,9 +326,8 @@ func (srv *Server) pullImage(out io.Writer, imgId, registry string, token []stri return nil } -func (srv *Server) pullRepository(out io.Writer, remote, askedTag string) error { - out = utils.NewWriteFlusher(out) - fmt.Fprintf(out, "Pulling repository %s from %s\r\n", remote, auth.IndexServerAddress()) +func (srv *Server) pullRepository(out io.Writer, remote, askedTag string, json bool) error { + fmt.Fprintf(out, utils.FormatStatus("Pulling repository %s from %s", json), remote, auth.IndexServerAddress()) repoData, err := srv.registry.GetRepositoryData(remote) if err != nil { return err @@ -366,11 +364,11 @@ func (srv *Server) pullRepository(out io.Writer, remote, askedTag string) error utils.Debugf("(%s) does not match %s (id: %s), skipping", img.Tag, askedTag, img.Id) continue } - fmt.Fprintf(out, "Pulling image %s (%s) from %s\n", img.Id, img.Tag, remote) + fmt.Fprintf(out, utils.FormatStatus("Pulling image %s (%s) from %s", json), img.Id, img.Tag, remote) success := false for _, ep := range repoData.Endpoints { - if err := srv.pullImage(out, img.Id, "https://"+ep+"/v1", repoData.Tokens); err != nil { - fmt.Fprintf(out, "Error while retrieving image for tag: %s (%s); checking next endpoint\n", askedTag, err) + if err := srv.pullImage(out, img.Id, "https://"+ep+"/v1", repoData.Tokens, json); err != nil { + fmt.Fprintf(out, utils.FormatStatus("Error while retrieving image for tag: %s (%s); checking next endpoint\n", json), askedTag, err) continue } success = true @@ -395,15 +393,16 @@ func (srv *Server) pullRepository(out io.Writer, remote, askedTag string) error return nil } -func (srv *Server) ImagePull(name, tag, registry string, out io.Writer) error { +func (srv *Server) ImagePull(name, tag, registry string, out io.Writer, json bool) error { + out = utils.NewWriteFlusher(out) if registry != "" { - if err := srv.pullImage(out, name, registry, nil); err != nil { + if err := srv.pullImage(out, name, registry, nil, json); err != nil { return err } return nil } - if err := srv.pullRepository(out, name, tag); err != nil { + if err := srv.pullRepository(out, name, tag, json); err != nil { return err } @@ -570,7 +569,7 @@ func (srv *Server) pushImage(out io.Writer, remote, imgId, ep string, token []st } // Send the layer - if err := srv.registry.PushImageLayerRegistry(imgData.Id, utils.ProgressReader(layerData, int(layerData.Size), out, ""), ep, token); err != nil { + if err := srv.registry.PushImageLayerRegistry(imgData.Id, utils.ProgressReader(layerData, int(layerData.Size), out, "", false), ep, token); err != nil { return err } return nil @@ -621,7 +620,7 @@ func (srv *Server) ImageImport(src, repo, tag string, in io.Reader, out io.Write if err != nil { return err } - archive = utils.ProgressReader(resp.Body, int(resp.ContentLength), out, "Importing %v/%v (%v)") + archive = utils.ProgressReader(resp.Body, int(resp.ContentLength), out, "Importing %v/%v (%v)\r", false) } img, err := srv.runtime.graph.Create(archive, nil, "Imported from "+src, "", nil) if err != nil { @@ -776,6 +775,13 @@ func (srv *Server) ContainerWait(name string) (int, error) { return 0, fmt.Errorf("No such container: %s", name) } +func (srv *Server) ContainerResize(name string, h, w int) error { + if container := srv.runtime.Get(name); container != nil { + return container.Resize(h, w) + } + return fmt.Errorf("No such container: %s", name) +} + func (srv *Server) ContainerAttach(name string, logs, stream, stdin, stdout, stderr bool, in io.ReadCloser, out io.Writer) error { container := srv.runtime.Get(name) if container == nil { diff --git a/components/engine/server_test.go b/components/engine/server_test.go index 7b90252864..b96e1dd5eb 100644 --- a/components/engine/server_test.go +++ b/components/engine/server_test.go @@ -85,6 +85,7 @@ func TestCreateStartRestartStopStartKillRm(t *testing.T) { t.Fatal(err) } + // FIXME: this failed once with a race condition ("Unable to remove filesystem for xxx: directory not empty") if err = srv.ContainerDestroy(id, true); err != nil { t.Fatal(err) } diff --git a/components/engine/term/term.go b/components/engine/term/term.go index 8c07b93356..290bf174ad 100644 --- a/components/engine/term/term.go +++ b/components/engine/term/term.go @@ -109,17 +109,35 @@ type State struct { termios Termios } +type Winsize struct { + Width uint16 + Height uint16 + x uint16 + y uint16 +} + +func GetWinsize(fd uintptr) (*Winsize, error) { + ws := &Winsize{} + _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(ws))) + return ws, err +} + +func SetWinsize(fd uintptr, ws *Winsize) error { + _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TIOCSWINSZ), uintptr(unsafe.Pointer(ws))) + return err +} + // IsTerminal returns true if the given file descriptor is a terminal. func IsTerminal(fd int) bool { var termios Termios - _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(getTermios), uintptr(unsafe.Pointer(&termios)), 0, 0, 0) + _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(getTermios), uintptr(unsafe.Pointer(&termios))) return err == 0 } // Restore restores the terminal connected to the given file descriptor to a // previous state. func Restore(fd int, state *State) error { - _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(setTermios), uintptr(unsafe.Pointer(&state.termios)), 0, 0, 0) + _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(setTermios), uintptr(unsafe.Pointer(&state.termios))) return err } diff --git a/components/engine/utils.go b/components/engine/utils.go index 27478002d3..5a9d02c490 100644 --- a/components/engine/utils.go +++ b/components/engine/utils.go @@ -49,10 +49,10 @@ func CompareConfig(a, b *Config) bool { } func MergeConfig(userConf, imageConf *Config) { - if userConf.Hostname != "" { + if userConf.Hostname == "" { userConf.Hostname = imageConf.Hostname } - if userConf.User != "" { + if userConf.User == "" { userConf.User = imageConf.User } if userConf.Memory == 0 { diff --git a/components/engine/utils/utils.go b/components/engine/utils/utils.go index 90ef30625c..ac0a142ae6 100644 --- a/components/engine/utils/utils.go +++ b/components/engine/utils/utils.go @@ -69,6 +69,7 @@ type progressReader struct { readProgress int // How much has been read so far (bytes) lastUpdate int // How many bytes read at least update template string // Template to print. Default "%v/%v (%v)" + json bool } func (r *progressReader) Read(p []byte) (n int, err error) { @@ -84,15 +85,15 @@ func (r *progressReader) Read(p []byte) (n int, err error) { } if r.readProgress-r.lastUpdate > updateEvery || err != nil { if r.readTotal > 0 { - fmt.Fprintf(r.output, r.template+"\r", r.readProgress, r.readTotal, fmt.Sprintf("%.0f%%", float64(r.readProgress)/float64(r.readTotal)*100)) + fmt.Fprintf(r.output, r.template, r.readProgress, r.readTotal, fmt.Sprintf("%.0f%%", float64(r.readProgress)/float64(r.readTotal)*100)) } else { - fmt.Fprintf(r.output, r.template+"\r", r.readProgress, "?", "n/a") + fmt.Fprintf(r.output, r.template, r.readProgress, "?", "n/a") } r.lastUpdate = r.readProgress } // Send newline when complete if err != nil { - fmt.Fprintf(r.output, "\n") + fmt.Fprintf(r.output, FormatStatus("", r.json)) } return read, err @@ -100,11 +101,11 @@ func (r *progressReader) Read(p []byte) (n int, err error) { func (r *progressReader) Close() error { return io.ReadCloser(r.reader).Close() } -func ProgressReader(r io.ReadCloser, size int, output io.Writer, template string) *progressReader { - if template == "" { - template = "%v/%v (%v)" +func ProgressReader(r io.ReadCloser, size int, output io.Writer, template string, json bool) *progressReader { + if template == "" { + template = "%v/%v (%v)\r" } - return &progressReader{r, NewWriteFlusher(output), size, 0, 0, template} + return &progressReader{r, NewWriteFlusher(output), size, 0, 0, template, json} } // HumanDuration returns a human-readable approximation of a duration @@ -562,3 +563,19 @@ func NewWriteFlusher(w io.Writer) *WriteFlusher { } return &WriteFlusher{w: w, flusher: flusher} } + +func FormatStatus(str string, json bool) string { + if json { + return "{\"status\" : \"" + str + "\"}" + } + return str + "\r\n" +} + +func FormatProgress(str string, json bool) string { + if json { + return "{\"progress\" : \"" + str + "\"}" + } + return "Downloading " + str + "\r" +} + +