mirror of https://github.com/docker/docs.git
commit
904c720ea5
|
@ -60,7 +60,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/samalba/dockerclient",
|
"ImportPath": "github.com/samalba/dockerclient",
|
||||||
"Rev": "0fdc3ca0e58365801f1212900def9c7c60bbe2c7"
|
"Rev": "0689bcd74173c6abd6394b7ad435df46b0df26f8"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/samuel/go-zookeeper/zk",
|
"ImportPath": "github.com/samuel/go-zookeeper/zk",
|
||||||
|
|
|
@ -333,10 +333,17 @@ func (client *DockerClient) ListImages() ([]*Image, error) {
|
||||||
return images, nil
|
return images, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *DockerClient) RemoveImage(name string) error {
|
func (client *DockerClient) RemoveImage(name string) ([]*ImageDelete, error) {
|
||||||
uri := fmt.Sprintf("/%s/images/%s", APIVersion, name)
|
uri := fmt.Sprintf("/%s/images/%s", APIVersion, name)
|
||||||
_, err := client.doRequest("DELETE", uri, nil, nil)
|
data, err := client.doRequest("DELETE", uri, nil, nil)
|
||||||
return err
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var imageDelete []*ImageDelete
|
||||||
|
if err := json.Unmarshal(data, &imageDelete); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return imageDelete, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *DockerClient) PauseContainer(id string) error {
|
func (client *DockerClient) PauseContainer(id string) error {
|
||||||
|
|
|
@ -23,7 +23,7 @@ type Client interface {
|
||||||
PullImage(name string, auth *AuthConfig) error
|
PullImage(name string, auth *AuthConfig) error
|
||||||
RemoveContainer(id string, force, volumes bool) error
|
RemoveContainer(id string, force, volumes bool) error
|
||||||
ListImages() ([]*Image, error)
|
ListImages() ([]*Image, error)
|
||||||
RemoveImage(name string) error
|
RemoveImage(name string) ([]*ImageDelete, error)
|
||||||
PauseContainer(name string) error
|
PauseContainer(name string) error
|
||||||
UnpauseContainer(name string) error
|
UnpauseContainer(name string) error
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,9 +88,9 @@ func (client *MockClient) ListImages() ([]*dockerclient.Image, error) {
|
||||||
return args.Get(0).([]*dockerclient.Image), args.Error(1)
|
return args.Get(0).([]*dockerclient.Image), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *MockClient) RemoveImage(name string) error {
|
func (client *MockClient) RemoveImage(name string) ([]*dockerclient.ImageDelete, error) {
|
||||||
args := client.Mock.Called(name)
|
args := client.Mock.Called(name)
|
||||||
return args.Error(0)
|
return args.Get(0).([]*dockerclient.ImageDelete), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *MockClient) PauseContainer(name string) error {
|
func (client *MockClient) PauseContainer(name string) error {
|
||||||
|
|
|
@ -166,3 +166,8 @@ type Info struct {
|
||||||
Name string
|
Name string
|
||||||
Labels []string
|
Labels []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ImageDelete struct {
|
||||||
|
Deleted string
|
||||||
|
Untagged string
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
42
api/api.go
42
api/api.go
|
@ -330,6 +330,46 @@ 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"]
|
||||||
|
|
||||||
|
matchedImages := []*cluster.Image{}
|
||||||
|
for _, image := range c.cluster.Images() {
|
||||||
|
if image.Match(name) {
|
||||||
|
matchedImages = append(matchedImages, image)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(matchedImages) == 0 {
|
||||||
|
httpError(w, fmt.Sprintf("No such image %s", name), http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
out := []*dockerclient.ImageDelete{}
|
||||||
|
errs := []string{}
|
||||||
|
for _, image := range matchedImages {
|
||||||
|
content, err := c.cluster.RemoveImage(image)
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, fmt.Sprintf("%s: %s", image.Node.Name(), err.Error()))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
out = append(out, content...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(errs) != 0 {
|
||||||
|
httpError(w, strings.Join(errs, ""), http.StatusInternalServerError)
|
||||||
|
} else {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(NewWriteFlusher(w)).Encode(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// 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 +507,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,
|
||||||
|
|
|
@ -15,6 +15,9 @@ type Cluster interface {
|
||||||
// Return one image matching `IdOrName`
|
// Return one image matching `IdOrName`
|
||||||
Image(IdOrName string) *Image
|
Image(IdOrName string) *Image
|
||||||
|
|
||||||
|
// Remove an image from the cluster
|
||||||
|
RemoveImage(image *Image) ([]*dockerclient.ImageDelete, error)
|
||||||
|
|
||||||
// Return all containers
|
// Return all containers
|
||||||
Containers() []*Container
|
Containers() []*Container
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,27 @@
|
||||||
package cluster
|
package cluster
|
||||||
|
|
||||||
import "github.com/samalba/dockerclient"
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/samalba/dockerclient"
|
||||||
|
)
|
||||||
|
|
||||||
type Image struct {
|
type Image struct {
|
||||||
dockerclient.Image
|
dockerclient.Image
|
||||||
|
|
||||||
Node Node
|
Node Node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (image *Image) Match(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
|
||||||
|
}
|
||||||
|
|
|
@ -173,7 +173,7 @@ func (c *Cluster) getNode(addr string) *node {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Containers returns all the images in the cluster.
|
// Images returns all the images in the cluster.
|
||||||
func (c *Cluster) Images() []*cluster.Image {
|
func (c *Cluster) Images() []*cluster.Image {
|
||||||
c.RLock()
|
c.RLock()
|
||||||
defer c.RUnlock()
|
defer c.RUnlock()
|
||||||
|
@ -204,6 +204,16 @@ func (c *Cluster) Image(IdOrName string) *cluster.Image {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RemoveImage removes an image from the cluster
|
||||||
|
func (c *Cluster) RemoveImage(image *cluster.Image) ([]*dockerclient.ImageDelete, error) {
|
||||||
|
c.Lock()
|
||||||
|
defer c.Unlock()
|
||||||
|
if n, ok := image.Node.(*node); ok {
|
||||||
|
return n.removeImage(image)
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Cluster) Pull(name string, callback func(what, status string)) {
|
func (c *Cluster) Pull(name string, callback func(what, status string)) {
|
||||||
size := len(c.nodes)
|
size := len(c.nodes)
|
||||||
done := make(chan bool, size)
|
done := make(chan bool, size)
|
||||||
|
|
|
@ -163,6 +163,11 @@ func (n *node) updateSpecs() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete an image from the node.
|
||||||
|
func (n *node) removeImage(image *cluster.Image) ([]*dockerclient.ImageDelete, error) {
|
||||||
|
return n.client.RemoveImage(image.Id)
|
||||||
|
}
|
||||||
|
|
||||||
// Refresh the list of images on the node.
|
// Refresh the list of images on the node.
|
||||||
func (n *node) refreshImages() error {
|
func (n *node) refreshImages() error {
|
||||||
images, err := n.client.ListImages()
|
images, err := n.client.ListImages()
|
||||||
|
@ -459,9 +464,11 @@ func (n *node) Container(IdOrName string) *cluster.Container {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Images returns all the images in the node
|
||||||
func (n *node) Images() []*cluster.Image {
|
func (n *node) Images() []*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)
|
images = append(images, image)
|
||||||
}
|
}
|
||||||
|
@ -474,16 +481,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 image.Match(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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue