mirror of https://github.com/docker/docs.git
add docker rmi
Signed-off-by: Victor Vieux <vieux@docker.com>
This commit is contained in:
parent
3dfa0816c5
commit
649b6cf577
|
@ -22,8 +22,6 @@ POST "/images/create" (pull implemented)
|
||||||
POST "/images/load"
|
POST "/images/load"
|
||||||
POST "/images/{name:.*}/push"
|
POST "/images/{name:.*}/push"
|
||||||
POST "/images/{name:.*}/tag"
|
POST "/images/{name:.*}/tag"
|
||||||
|
|
||||||
DELETE "/images/{name:.*}"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Endpoints which behave differently
|
## Endpoints which behave differently
|
||||||
|
|
68
api/api.go
68
api/api.go
|
@ -5,6 +5,7 @@ import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -89,7 +90,7 @@ func getImagesJSON(c *context, w http.ResponseWriter, r *http.Request) {
|
||||||
accepteds, _ := filters["node"]
|
accepteds, _ := filters["node"]
|
||||||
images := []*cluster.Image{}
|
images := []*cluster.Image{}
|
||||||
|
|
||||||
for _, image := range c.cluster.Images() {
|
for _, image := range c.cluster.Images("") {
|
||||||
if len(accepteds) != 0 {
|
if len(accepteds) != 0 {
|
||||||
found := false
|
found := false
|
||||||
for _, accepted := range accepteds {
|
for _, accepted := range accepteds {
|
||||||
|
@ -330,6 +331,69 @@ func postContainersExec(c *context, w http.ResponseWriter, r *http.Request) {
|
||||||
w.Write(data)
|
w.Write(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DELETE /images/{name:.*}
|
||||||
|
func deleteImages(c *context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
if err := r.ParseForm(); err != nil {
|
||||||
|
httpError(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var name = mux.Vars(r)["name"]
|
||||||
|
|
||||||
|
client, scheme := newClientAndScheme(c.tlsConfig)
|
||||||
|
defer closeIdleConnections(client)
|
||||||
|
|
||||||
|
images := c.cluster.Images(name)
|
||||||
|
size := len(images)
|
||||||
|
if size == 0 {
|
||||||
|
httpError(w, fmt.Sprintf("No such image %s", name), http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, image := range images {
|
||||||
|
req, err := http.NewRequest("DELETE", scheme+"://"+image.Node.Addr()+"/images/"+name, nil)
|
||||||
|
if err != nil {
|
||||||
|
if size == 1 {
|
||||||
|
httpError(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
if size == 1 {
|
||||||
|
httpError(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := ioutil.ReadAll(resp.Body)
|
||||||
|
resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
if size == 1 {
|
||||||
|
httpError(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
|
if size == 1 {
|
||||||
|
w.WriteHeader(resp.StatusCode)
|
||||||
|
io.Copy(NewWriteFlusher(w), resp.Body)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
sdata := bytes.NewBuffer(data).String()
|
||||||
|
if i != 0 {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
sdata = strings.Replace(sdata, "[", ",", -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if i != len(images)-1 {
|
||||||
|
sdata = strings.Replace(sdata, "]", "", -1)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, sdata)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GET /_ping
|
// GET /_ping
|
||||||
func ping(c *context, w http.ResponseWriter, r *http.Request) {
|
func ping(c *context, w http.ResponseWriter, r *http.Request) {
|
||||||
w.Write([]byte{'O', 'K'})
|
w.Write([]byte{'O', 'K'})
|
||||||
|
@ -467,7 +531,7 @@ func createRouter(c *context, enableCors bool) *mux.Router {
|
||||||
},
|
},
|
||||||
"DELETE": {
|
"DELETE": {
|
||||||
"/containers/{name:.*}": deleteContainers,
|
"/containers/{name:.*}": deleteContainers,
|
||||||
"/images/{name:.*}": notImplementedHandler,
|
"/images/{name:.*}": deleteImages,
|
||||||
},
|
},
|
||||||
"OPTIONS": {
|
"OPTIONS": {
|
||||||
"": optionsHandler,
|
"": optionsHandler,
|
||||||
|
|
|
@ -23,7 +23,7 @@ func (fn *FakeNode) ID() string { return "node_id" }
|
||||||
func (fn *FakeNode) Name() string { return "node_name" }
|
func (fn *FakeNode) Name() string { return "node_name" }
|
||||||
func (fn *FakeNode) IP() string { return "node_ip" }
|
func (fn *FakeNode) IP() string { return "node_ip" }
|
||||||
func (fn *FakeNode) Addr() string { return "node_addr" }
|
func (fn *FakeNode) Addr() string { return "node_addr" }
|
||||||
func (fn *FakeNode) Images() []*cluster.Image { return nil }
|
func (fn *FakeNode) Images(_ string) []*cluster.Image { return nil }
|
||||||
func (fn *FakeNode) Image(_ string) *cluster.Image { return nil }
|
func (fn *FakeNode) Image(_ string) *cluster.Image { return nil }
|
||||||
func (fn *FakeNode) Containers() []*cluster.Container { return nil }
|
func (fn *FakeNode) Containers() []*cluster.Container { return nil }
|
||||||
func (fn *FakeNode) Container(_ string) *cluster.Container { return nil }
|
func (fn *FakeNode) Container(_ string) *cluster.Container { return nil }
|
||||||
|
|
|
@ -9,8 +9,9 @@ type Cluster interface {
|
||||||
// Remove a container
|
// Remove a container
|
||||||
RemoveContainer(container *Container, force bool) error
|
RemoveContainer(container *Container, force bool) error
|
||||||
|
|
||||||
// Return all images
|
// Return all images matching `name`
|
||||||
Images() []*Image
|
// if `name` == "" return all images in the cluster
|
||||||
|
Images(name string) []*Image
|
||||||
|
|
||||||
// Return one image matching `IdOrName`
|
// Return one image matching `IdOrName`
|
||||||
Image(IdOrName string) *Image
|
Image(IdOrName string) *Image
|
||||||
|
|
|
@ -9,7 +9,7 @@ type Node interface {
|
||||||
IP() string //to inject the actual IP of the machine in docker ps (hostname:port or ip:port)
|
IP() string //to inject the actual IP of the machine in docker ps (hostname:port or ip:port)
|
||||||
Addr() string //to know where to connect with the proxy
|
Addr() string //to know where to connect with the proxy
|
||||||
|
|
||||||
Images() []*Image //used by the API
|
Images(name string) []*Image //used by the API
|
||||||
Image(IdOrName string) *Image //used by the filters
|
Image(IdOrName string) *Image //used by the filters
|
||||||
Containers() []*Container //used by the filters
|
Containers() []*Container //used by the filters
|
||||||
Container(IdOrName string) *Container //used by the filters
|
Container(IdOrName string) *Container //used by the filters
|
||||||
|
|
|
@ -156,13 +156,14 @@ func (c *Cluster) getNode(addr string) *node {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Containers returns all the images in the cluster.
|
// Containers returns all the images in the cluster.
|
||||||
func (c *Cluster) Images() []*cluster.Image {
|
// If `name` is empty, return all the images
|
||||||
|
func (c *Cluster) Images(name string) []*cluster.Image {
|
||||||
c.RLock()
|
c.RLock()
|
||||||
defer c.RUnlock()
|
defer c.RUnlock()
|
||||||
|
|
||||||
out := []*cluster.Image{}
|
out := []*cluster.Image{}
|
||||||
for _, n := range c.nodes {
|
for _, n := range c.nodes {
|
||||||
out = append(out, n.Images()...)
|
out = append(out, n.Images(name)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return out
|
return out
|
||||||
|
|
|
@ -459,11 +459,30 @@ func (n *node) Container(IdOrName string) *cluster.Container {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *node) Images() []*cluster.Image {
|
func matchImage(image *cluster.Image, IdOrName string) bool {
|
||||||
|
size := len(IdOrName)
|
||||||
|
|
||||||
|
if image.Id == IdOrName || (size > 2 && strings.HasPrefix(image.Id, IdOrName)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
for _, repoTag := range image.RepoTags {
|
||||||
|
if repoTag == IdOrName || (size > 2 && strings.HasPrefix(repoTag, IdOrName)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Images returns a list for images matching name in the node
|
||||||
|
// If `name` is empty, returns all the images
|
||||||
|
func (n *node) Images(name string) []*cluster.Image {
|
||||||
images := []*cluster.Image{}
|
images := []*cluster.Image{}
|
||||||
n.RLock()
|
n.RLock()
|
||||||
|
|
||||||
for _, image := range n.images {
|
for _, image := range n.images {
|
||||||
images = append(images, image)
|
if name == "" || matchImage(image, name) {
|
||||||
|
images = append(images, image)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
n.RUnlock()
|
n.RUnlock()
|
||||||
return images
|
return images
|
||||||
|
@ -474,16 +493,10 @@ func (n *node) Image(IdOrName string) *cluster.Image {
|
||||||
n.RLock()
|
n.RLock()
|
||||||
defer n.RUnlock()
|
defer n.RUnlock()
|
||||||
|
|
||||||
size := len(IdOrName)
|
for _, image := range n.images {
|
||||||
for _, image := range n.Images() {
|
if matchImage(image, IdOrName) {
|
||||||
if image.Id == IdOrName || (size > 2 && strings.HasPrefix(image.Id, IdOrName)) {
|
|
||||||
return image
|
return image
|
||||||
}
|
}
|
||||||
for _, t := range image.RepoTags {
|
|
||||||
if t == IdOrName || (size > 2 && strings.HasPrefix(t, IdOrName)) {
|
|
||||||
return image
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ func (f *AffinityFilter) Filter(config *dockerclient.ContainerConfig, nodes []cl
|
||||||
}
|
}
|
||||||
case "image":
|
case "image":
|
||||||
images := []string{}
|
images := []string{}
|
||||||
for _, image := range node.Images() {
|
for _, image := range node.Images("") {
|
||||||
images = append(images, image.Id)
|
images = append(images, image.Id)
|
||||||
images = append(images, image.RepoTags...)
|
images = append(images, image.RepoTags...)
|
||||||
for _, tag := range image.RepoTags {
|
for _, tag := range image.RepoTags {
|
||||||
|
|
|
@ -11,11 +11,11 @@ type FakeNode struct {
|
||||||
labels map[string]string
|
labels map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fn *FakeNode) ID() string { return fn.id }
|
func (fn *FakeNode) ID() string { return fn.id }
|
||||||
func (fn *FakeNode) Name() string { return fn.name }
|
func (fn *FakeNode) Name() string { return fn.name }
|
||||||
func (fn *FakeNode) IP() string { return "" }
|
func (fn *FakeNode) IP() string { return "" }
|
||||||
func (fn *FakeNode) Addr() string { return fn.addr }
|
func (fn *FakeNode) Addr() string { return fn.addr }
|
||||||
func (fn *FakeNode) Images() []*cluster.Image { return fn.images }
|
func (fn *FakeNode) Images(_ string) []*cluster.Image { return fn.images }
|
||||||
func (fn *FakeNode) Image(id string) *cluster.Image {
|
func (fn *FakeNode) Image(id string) *cluster.Image {
|
||||||
for _, image := range fn.images {
|
for _, image := range fn.images {
|
||||||
if image.Id == id {
|
if image.Id == id {
|
||||||
|
|
|
@ -21,7 +21,7 @@ func (fn *FakeNode) ID() string { return fn.id }
|
||||||
func (fn *FakeNode) Name() string { return fn.name }
|
func (fn *FakeNode) Name() string { return fn.name }
|
||||||
func (fn *FakeNode) IP() string { return "" }
|
func (fn *FakeNode) IP() string { return "" }
|
||||||
func (fn *FakeNode) Addr() string { return fn.addr }
|
func (fn *FakeNode) Addr() string { return fn.addr }
|
||||||
func (fn *FakeNode) Images() []*cluster.Image { return nil }
|
func (fn *FakeNode) Images(_ string) []*cluster.Image { return nil }
|
||||||
func (fn *FakeNode) Image(_ string) *cluster.Image { return nil }
|
func (fn *FakeNode) Image(_ string) *cluster.Image { return nil }
|
||||||
func (fn *FakeNode) Containers() []*cluster.Container { return fn.containers }
|
func (fn *FakeNode) Containers() []*cluster.Container { return fn.containers }
|
||||||
func (fn *FakeNode) Container(_ string) *cluster.Container { return nil }
|
func (fn *FakeNode) Container(_ string) *cluster.Container { return nil }
|
||||||
|
|
Loading…
Reference in New Issue