Merge pull request #271 from vieux/history_inspect

add support for history, inspect for images and improve inspect for containers
This commit is contained in:
Andrea Luzzardi 2015-01-21 17:26:50 -08:00
commit 7dd2d2440b
5 changed files with 65 additions and 35 deletions

View File

@ -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"

View File

@ -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,

View File

@ -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 {

View File

@ -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 {

View File

@ -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)
}