'docker rm': remove layers. Layers currently in use can't removed.

This commit is contained in:
Solomon Hykes 2013-01-21 18:12:56 -08:00
parent be3563cebb
commit 559e3200fa
1 changed files with 73 additions and 19 deletions

View File

@ -33,6 +33,7 @@ func (docker *Docker) CmdHelp(stdin io.ReadCloser, stdout io.Writer, args ...str
{"list", "Display a list of containers"}, {"list", "Display a list of containers"},
{"layers", "Display a list of layers"}, {"layers", "Display a list of layers"},
{"get", "Download a layer from a remote location"}, {"get", "Download a layer from a remote location"},
{"rm", "Remove layers"},
{"wait", "Wait for the state of a container to change"}, {"wait", "Wait for the state of a container to change"},
{"stop", "Stop a running container"}, {"stop", "Stop a running container"},
{"logs", "Fetch the logs of a container"}, {"logs", "Fetch the logs of a container"},
@ -96,6 +97,43 @@ func (docker *Docker) CmdLayers(stdin io.ReadCloser, stdout io.Writer, args ...s
return nil return nil
} }
func (docker *Docker) findLayer(name string) (*Layer, bool) {
// 1: look for layer by ID
if layer, exists := docker.layers[name]; exists {
return layer, true
}
// 2: look for a layer by name (and pick the most recent)
if layers, exists := docker.layersByName[name]; exists {
return (*layers)[0], true
}
return nil, false
}
func (docker *Docker) usingLayer(layer *Layer) []*Container {
var containers []*Container
for _, container := range docker.containers {
for _, l := range container.Layers {
if l.Id == layer.Id {
containers = append(containers, &container)
}
}
}
return containers
}
func (docker *Docker) CmdRm(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
flags := Subcmd(stdout, "rm", "[OPTIONS LAYER", "Remove a layer")
if err := flags.Parse(args); err != nil {
return nil
}
for _, name := range flags.Args() {
if _, err := docker.rmLayer(name); err != nil {
fmt.Fprintln(stdout, "Error: " + err.Error())
}
}
return nil
}
func (docker *Docker) CmdGet(stdin io.ReadCloser, stdout io.Writer, args ...string) error { func (docker *Docker) CmdGet(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
if len(args) < 1 { if len(args) < 1 {
return errors.New("Not enough arguments") return errors.New("Not enough arguments")
@ -209,20 +247,43 @@ func (l *ByDate) Add(layer *Layer) {
sort.Sort(l) sort.Sort(l)
} }
func (l *ByDate) Del(id string) {
for idx, layer := range *l {
if layer.Id == id {
*l = append((*l)[:idx], (*l)[idx + 1:]...)
}
}
}
func (docker *Docker) addLayer(name string, source string, size uint) Layer {
func (docker *Docker) addLayer(name string, source string, size uint) *Layer {
if size == 0 { if size == 0 {
size = uint(rand.Int31n(142 * 1024 * 1024)) size = uint(rand.Int31n(142 * 1024 * 1024))
} }
layer := Layer{Id: randomId(), Name: name, Source: source, Added: time.Now(), Size: size} layer := &Layer{Id: randomId(), Name: name, Source: source, Added: time.Now(), Size: size}
docker.layers[layer.Id] = layer docker.layers[layer.Id] = layer
if _, exists := docker.layersByName[layer.Name]; !exists { if _, exists := docker.layersByName[layer.Name]; !exists {
docker.layersByName[layer.Name] = new(ByDate) docker.layersByName[layer.Name] = new(ByDate)
} }
docker.layersByName[layer.Name].Add(&layer) docker.layersByName[layer.Name].Add(layer)
return layer return layer
} }
func (docker *Docker) rmLayer(id string) (*Layer, error) {
if layer, exists := docker.layers[id]; exists {
if containers := docker.usingLayer(layer); len(containers) > 0 {
return nil, errors.New(fmt.Sprintf("Layer is in use: %s", id))
} else {
// Remove from name lookup
docker.layersByName[layer.Name].Del(layer.Id)
// Remove from id lookup
delete(docker.layers, layer.Id)
return layer, nil
}
}
return nil, errors.New(fmt.Sprintf("No such layer: %s", id))
}
type ArgList []string type ArgList []string
func (l *ArgList) Set(value string) error { func (l *ArgList) Set(value string) error {
@ -262,21 +323,14 @@ func (docker *Docker) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...stri
BytesChanged: uint(rand.Int31n(24 * 1024 * 1024)), BytesChanged: uint(rand.Int31n(24 * 1024 * 1024)),
} }
for _, name := range *fl_layers { for _, name := range *fl_layers {
// 1: look for layer by ID if layer, exists := docker.findLayer(name); exists {
if layer, exists := docker.layers[name]; !exists { container.Layers = append(container.Layers, layer)
// 2: look for a layer by name (and pick the most recent) } else if srcContainer, exists := docker.containers[name]; exists {
if layers, exists := docker.layersByName[name]; exists { for _, layer := range srcContainer.Layers {
container.Layers = append(container.Layers, *(*layers)[0]) container.Layers = append(container.Layers, layer)
// 3: look for container by name (and copy its layers)
} else if srcContainer, exists := docker.containers[name]; exists {
for _, layer := range srcContainer.Layers {
container.Layers = append(container.Layers, layer)
}
} else {
return errors.New("No such layer or container: " + name)
} }
} else { } else {
container.Layers = append(container.Layers, layer) return errors.New("No such layer or container: " + name)
} }
} }
docker.containers[container.Id] = container docker.containers[container.Id] = container
@ -376,7 +430,7 @@ func main() {
func New() *Docker { func New() *Docker {
return &Docker{ return &Docker{
layers: make(map[string]Layer), layers: make(map[string]*Layer),
layersByName: make(map[string]*ByDate), layersByName: make(map[string]*ByDate),
containers: make(map[string]Container), containers: make(map[string]Container),
} }
@ -468,7 +522,7 @@ func Go(f func() error) chan error {
} }
type Docker struct { type Docker struct {
layers map[string]Layer layers map[string]*Layer
layersByName map[string]*ByDate layersByName map[string]*ByDate
containers map[string]Container containers map[string]Container
} }
@ -485,7 +539,7 @@ type Container struct {
Id string Id string
Cmd string Cmd string
Args []string Args []string
Layers []Layer Layers []*Layer
Created time.Time Created time.Time
FilesChanged uint FilesChanged uint
BytesChanged uint BytesChanged uint