From 2e968d78005fb413123b4547321a103961c8e3d4 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Thu, 22 Jan 2015 00:19:43 +0000 Subject: [PATCH] add support for history, inspect for images and improve inspect for containers Signed-off-by: Victor Vieux --- api/README.md | 2 -- api/api.go | 78 ++++++++++++++++++++++++++++------------------ api/utils.go | 2 +- cluster/cluster.go | 2 +- cluster/node.go | 16 ++++++++++ 5 files changed, 65 insertions(+), 35 deletions(-) diff --git a/api/README.md b/api/README.md index 8c4e8aaafe..a014616c1c 100644 --- a/api/README.md +++ b/api/README.md @@ -10,8 +10,6 @@ Here are the main differences: ``` GET "/images/get" GET "/images/{name:.*}/get" -GET "/images/{name:.*}/history" -GET "/images/{name:.*}/json" GET "/containers/{name:.*}/attach/ws" POST "/commit" diff --git a/api/api.go b/api/api.go index 7d2eb179f6..dabe7a1cd7 100644 --- a/api/api.go +++ b/api/api.go @@ -163,36 +163,39 @@ func getContainersJSON(c *context, w http.ResponseWriter, r *http.Request) { // GET /containers/{name:.*}/json func getContainerJSON(c *context, w http.ResponseWriter, r *http.Request) { - container := c.cluster.Container(mux.Vars(r)["name"]) - if container != nil { - client, scheme := newClientAndScheme(c.tlsConfig) - - resp, err := client.Get(scheme + "://" + container.Node.Addr + "/containers/" + container.Id + "/json") - if err != nil { - httpError(w, err.Error(), http.StatusInternalServerError) - return - } - data, err := ioutil.ReadAll(resp.Body) - if err != nil { - httpError(w, err.Error(), http.StatusInternalServerError) - return - } - - n, err := json.Marshal(container.Node) - if err != nil { - httpError(w, err.Error(), http.StatusInternalServerError) - return - } - - // insert Node field - data = bytes.Replace(data, []byte("\"Name\":\"/"), []byte(fmt.Sprintf("\"Node\":%s,\"Name\":\"/", n)), -1) - - // insert node IP - data = bytes.Replace(data, []byte("\"HostIp\":\"0.0.0.0\""), []byte(fmt.Sprintf("\"HostIp\":%q", container.Node.IP)), -1) - - w.Header().Set("Content-Type", "application/json") - w.Write(data) + name := mux.Vars(r)["name"] + container := c.cluster.Container(name) + if container == nil { + httpError(w, fmt.Sprintf("No such container %s", name), http.StatusNotFound) + return } + client, scheme := newClientAndScheme(c.tlsConfig) + + resp, err := client.Get(scheme + "://" + container.Node.Addr + "/containers/" + container.Id + "/json") + if err != nil { + httpError(w, err.Error(), http.StatusInternalServerError) + return + } + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + httpError(w, err.Error(), http.StatusInternalServerError) + return + } + + n, err := json.Marshal(container.Node) + if err != nil { + httpError(w, err.Error(), http.StatusInternalServerError) + return + } + + // insert Node field + data = bytes.Replace(data, []byte("\"Name\":\"/"), []byte(fmt.Sprintf("\"Node\":%s,\"Name\":\"/", n)), -1) + + // insert node IP + data = bytes.Replace(data, []byte("\"HostIp\":\"0.0.0.0\""), []byte(fmt.Sprintf("\"HostIp\":%q", container.Node.IP)), -1) + + w.Header().Set("Content-Type", "application/json") + w.Write(data) } // POST /containers/create @@ -292,6 +295,19 @@ func proxyContainer(c *context, w http.ResponseWriter, r *http.Request) { } } +// Proxy a request to the right node +func proxyImage(c *context, w http.ResponseWriter, r *http.Request) { + name := mux.Vars(r)["name"] + + for _, node := range c.cluster.Nodes() { + if node.Image(name) != nil { + proxy(c.tlsConfig, node.Addr, w, r) + return + } + } + httpError(w, fmt.Sprintf("No such image: %s", name), http.StatusNotFound) +} + // Proxy a request to a random node func proxyRandom(c *context, w http.ResponseWriter, r *http.Request) { candidates := c.cluster.Nodes() @@ -355,8 +371,8 @@ func createRouter(c *context, enableCors bool) *mux.Router { "/images/search": proxyRandom, "/images/get": notImplementedHandler, "/images/{name:.*}/get": notImplementedHandler, - "/images/{name:.*}/history": notImplementedHandler, - "/images/{name:.*}/json": notImplementedHandler, + "/images/{name:.*}/history": proxyImage, + "/images/{name:.*}/json": proxyImage, "/containers/ps": getContainersJSON, "/containers/json": getContainersJSON, "/containers/{name:.*}/export": proxyContainer, diff --git a/api/utils.go b/api/utils.go index 33d4687b2f..4f2ecbb31d 100644 --- a/api/utils.go +++ b/api/utils.go @@ -25,7 +25,7 @@ func getContainerFromVars(c *context, vars map[string]string) (*cluster.Containe if container := c.cluster.Container(name); container != nil { return container, nil } - return nil, fmt.Errorf("Container %s not found", name) + return nil, fmt.Errorf("No such container: %s", name) } if ID, ok := vars["execid"]; ok { diff --git a/cluster/cluster.go b/cluster/cluster.go index 44a36b4d2f..daa06ed838 100644 --- a/cluster/cluster.go +++ b/cluster/cluster.go @@ -132,7 +132,7 @@ func (c *Cluster) Containers() []*Container { return out } -// Container returns the container with ID in the cluster +// Container returns the container with IdOrName in the cluster func (c *Cluster) Container(IdOrName string) *Container { // Abort immediately if the name is empty. if len(IdOrName) == 0 { diff --git a/cluster/node.go b/cluster/node.go index e43bb1c381..ab77593f6b 100644 --- a/cluster/node.go +++ b/cluster/node.go @@ -414,6 +414,22 @@ func (n *Node) Images() []*dockerclient.Image { return images } +// Image returns the image with IdOrName in the node +func (n *Node) Image(IdOrName string) *dockerclient.Image { + size := len(IdOrName) + for _, image := range n.Images() { + if image.Id == IdOrName || (size > 2 && strings.HasPrefix(image.Id, IdOrName)) { + return image + } + for _, t := range image.RepoTags { + if t == IdOrName || (size > 2 && strings.HasPrefix(t, IdOrName)) { + return image + } + } + } + return nil +} + func (n *Node) String() string { return fmt.Sprintf("node %s addr %s", n.ID, n.Addr) }