Skip to content
Permalink
Browse files

Merge pull request #26108 from mlaventure/data-mngt

New Data Management commands
  • Loading branch information...
Arnaud Porterie
Arnaud Porterie committed Oct 1, 2016
2 parents 1833842 + 913e5cb commit 86de7c000f5d854051369754ad1769194e8dd5e1
Showing with 1,962 additions and 13 deletions.
  1. +6 −0 api/server/router/container/backend.go
  2. +1 −0 api/server/router/container/container.go
  3. +21 −0 api/server/router/container/container_routes.go
  4. +2 −1 api/server/router/image/backend.go
  5. +1 −0 api/server/router/image/image.go
  6. +22 −1 api/server/router/image/image_routes.go
  7. +1 −0 api/server/router/system/backend.go
  8. +1 −0 api/server/router/system/system.go
  9. +9 −0 api/server/router/system/system_routes.go
  10. +1 −0 api/server/router/volume/backend.go
  11. +1 −0 api/server/router/volume/volume.go
  12. +21 −0 api/server/router/volume/volume_routes.go
  13. +50 −0 api/types/types.go
  14. +1 −0 cli/command/container/cmd.go
  15. +74 −0 cli/command/container/prune.go
  16. +1 −2 cli/command/container/stats.go
  17. +1 −1 cli/command/{system → }/events_utils.go
  18. +14 −0 cli/command/formatter/container.go
  19. +331 −0 cli/command/formatter/disk_usage.go
  20. +32 −1 cli/command/formatter/image.go
  21. +1 −1 cli/command/formatter/image_test.go
  22. +18 −0 cli/command/formatter/volume.go
  23. +2 −0 cli/command/image/cmd.go
  24. +90 −0 cli/command/image/prune.go
  25. +39 −0 cli/command/prune/prune.go
  26. +2 −0 cli/command/system/cmd.go
  27. +55 −0 cli/command/system/df.go
  28. +90 −0 cli/command/system/prune.go
  29. +22 −0 cli/command/utils.go
  30. +1 −0 cli/command/volume/cmd.go
  31. +74 −0 cli/command/volume/prune.go
  32. +26 −0 client/container_prune.go
  33. +26 −0 client/disk_usage.go
  34. +26 −0 client/image_prune.go
  35. +4 −0 client/interface.go
  36. +26 −0 client/volume_prune.go
  37. +100 −0 daemon/disk_usage.go
  38. +68 −4 daemon/images.go
  39. +152 −0 daemon/prune.go
  40. +32 −2 daemon/volumes.go
  41. +10 −0 distribution/xfer/download_test.go
  42. +201 −0 docs/reference/api/docker_remote_api_v1.25.md
  43. +41 −0 docs/reference/commandline/container_prune.md
  44. +65 −0 docs/reference/commandline/image_prune.md
  45. +68 −0 docs/reference/commandline/system_df.md
  46. +70 −0 docs/reference/commandline/system_prune.md
  47. +48 −0 docs/reference/commandline/volume_prune.md
  48. +1 −0 layer/layer.go
  49. +13 −0 layer/layer_store.go
@@ -62,11 +62,17 @@ type attachBackend interface {
ContainerAttach(name string, c *backend.ContainerAttachConfig) error
}

// systemBackend includes functions to implement to provide system wide containers functionality
type systemBackend interface {
ContainersPrune(config *types.ContainersPruneConfig) (*types.ContainersPruneReport, error)
}

// Backend is all the methods that need to be implemented to provide container specific functionality.
type Backend interface {
execBackend
copyBackend
stateBackend
monitorBackend
attachBackend
systemBackend
}
@@ -68,6 +68,7 @@ func (r *containerRouter) initRoutes() {
router.NewPostRoute("/exec/{name:.*}/resize", r.postContainerExecResize),
router.NewPostRoute("/containers/{name:.*}/rename", r.postContainerRename),
router.NewPostRoute("/containers/{name:.*}/update", r.postContainerUpdate),
router.NewPostRoute("/containers/prune", r.postContainersPrune),
// PUT
router.NewPutRoute("/containers/{name:.*}/archive", r.putContainersArchive),
// DELETE
@@ -524,3 +524,24 @@ func (s *containerRouter) wsContainersAttach(ctx context.Context, w http.Respons
}
return err
}

func (s *containerRouter) postContainersPrune(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := httputils.ParseForm(r); err != nil {
return err
}

if err := httputils.CheckForJSON(r); err != nil {
return err
}

var cfg types.ContainersPruneConfig
if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil {
return err
}

pruneReport, err := s.backend.ContainersPrune(&cfg)
if err != nil {
return err
}
return httputils.WriteJSON(w, http.StatusOK, pruneReport)
}
@@ -25,9 +25,10 @@ type containerBackend interface {
type imageBackend interface {
ImageDelete(imageRef string, force, prune bool) ([]types.ImageDelete, error)
ImageHistory(imageName string) ([]*types.ImageHistory, error)
Images(filterArgs string, filter string, all bool) ([]*types.Image, error)
Images(filterArgs string, filter string, all bool, withExtraAttrs bool) ([]*types.Image, error)
LookupImage(name string) (*types.ImageInspect, error)
TagImage(imageName, repository, tag string) error
ImagesPrune(config *types.ImagesPruneConfig) (*types.ImagesPruneReport, error)
}

type importExportBackend interface {
@@ -43,6 +43,7 @@ func (r *imageRouter) initRoutes() {
router.Cancellable(router.NewPostRoute("/images/create", r.postImagesCreate)),
router.Cancellable(router.NewPostRoute("/images/{name:.*}/push", r.postImagesPush)),
router.NewPostRoute("/images/{name:.*}/tag", r.postImagesTag),
router.NewPostRoute("/images/prune", r.postImagesPrune),
// DELETE
router.NewDeleteRoute("/images/{name:.*}", r.deleteImages),
}
@@ -248,7 +248,7 @@ func (s *imageRouter) getImagesJSON(ctx context.Context, w http.ResponseWriter,
}

// FIXME: The filter parameter could just be a match filter
images, err := s.backend.Images(r.Form.Get("filters"), r.Form.Get("filter"), httputils.BoolValue(r, "all"))
images, err := s.backend.Images(r.Form.Get("filters"), r.Form.Get("filter"), httputils.BoolValue(r, "all"), false)
if err != nil {
return err
}
@@ -314,3 +314,24 @@ func (s *imageRouter) getImagesSearch(ctx context.Context, w http.ResponseWriter
}
return httputils.WriteJSON(w, http.StatusOK, query.Results)
}

func (s *imageRouter) postImagesPrune(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := httputils.ParseForm(r); err != nil {
return err
}

if err := httputils.CheckForJSON(r); err != nil {
return err
}

var cfg types.ImagesPruneConfig
if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil {
return err
}

pruneReport, err := s.backend.ImagesPrune(&cfg)
if err != nil {
return err
}
return httputils.WriteJSON(w, http.StatusOK, pruneReport)
}
@@ -14,6 +14,7 @@ import (
type Backend interface {
SystemInfo() (*types.Info, error)
SystemVersion() types.Version
SystemDiskUsage() (*types.DiskUsage, error)
SubscribeToEvents(since, until time.Time, ef filters.Args) ([]events.Message, chan interface{})
UnsubscribeFromEvents(chan interface{})
AuthenticateToRegistry(ctx context.Context, authConfig *types.AuthConfig) (string, string, error)
@@ -26,6 +26,7 @@ func NewRouter(b Backend, c *cluster.Cluster) router.Router {
router.Cancellable(router.NewGetRoute("/events", r.getEvents)),
router.NewGetRoute("/info", r.getInfo),
router.NewGetRoute("/version", r.getVersion),
router.NewGetRoute("/system/df", r.getDiskUsage),
router.NewPostRoute("/auth", r.postAuth),
}

@@ -56,6 +56,15 @@ func (s *systemRouter) getVersion(ctx context.Context, w http.ResponseWriter, r
return httputils.WriteJSON(w, http.StatusOK, info)
}

func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
du, err := s.backend.SystemDiskUsage()
if err != nil {
return err
}

return httputils.WriteJSON(w, http.StatusOK, du)
}

func (s *systemRouter) getEvents(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := httputils.ParseForm(r); err != nil {
return err
@@ -12,4 +12,5 @@ type Backend interface {
VolumeInspect(name string) (*types.Volume, error)
VolumeCreate(name, driverName string, opts, labels map[string]string) (*types.Volume, error)
VolumeRm(name string, force bool) error
VolumesPrune(config *types.VolumesPruneConfig) (*types.VolumesPruneReport, error)
}
@@ -29,6 +29,7 @@ func (r *volumeRouter) initRoutes() {
router.NewGetRoute("/volumes/{name:.*}", r.getVolumeByName),
// POST
router.NewPostRoute("/volumes/create", r.postVolumesCreate),
router.NewPostRoute("/volumes/prune", r.postVolumesPrune),
// DELETE
router.NewDeleteRoute("/volumes/{name:.*}", r.deleteVolumes),
}
@@ -65,3 +65,24 @@ func (v *volumeRouter) deleteVolumes(ctx context.Context, w http.ResponseWriter,
w.WriteHeader(http.StatusNoContent)
return nil
}

func (v *volumeRouter) postVolumesPrune(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := httputils.ParseForm(r); err != nil {
return err
}

if err := httputils.CheckForJSON(r); err != nil {
return err
}

var cfg types.VolumesPruneConfig
if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil {
return err
}

pruneReport, err := v.backend.VolumesPrune(&cfg)
if err != nil {
return err
}
return httputils.WriteJSON(w, http.StatusOK, pruneReport)
}
@@ -95,8 +95,10 @@ type Image struct {
RepoDigests []string
Created int64
Size int64
SharedSize int64
VirtualSize int64
Labels map[string]string
Containers int64
}

// GraphDriverData returns Image's graph driver config info
@@ -438,6 +440,8 @@ type Volume struct {
Status map[string]interface{} `json:",omitempty"` // Status provides low-level status information about the volume
Labels map[string]string // Labels is metadata specific to the volume
Scope string // Scope describes the level at which the volume exists (e.g. `global` for cluster-wide or `local` for machine level)
Size int64 // Size holds how much disk space is used by the (local driver only). Sets to -1 if not provided.
RefCount int // RefCount holds the number of containers having this volume attached to them. Sets to -1 if not provided.
}

// VolumesListResponse contains the response for the remote API:
@@ -526,3 +530,49 @@ type Runtime struct {
Path string `json:"path"`
Args []string `json:"runtimeArgs,omitempty"`
}

// DiskUsage contains response of Remote API:
// GET "/system/df"
type DiskUsage struct {
LayersSize int64
Images []*Image
Containers []*Container
Volumes []*Volume
}

// ImagesPruneConfig contains the configuration for Remote API:
// POST "/image/prune"
type ImagesPruneConfig struct {
DanglingOnly bool
}

// ContainersPruneConfig contains the configuration for Remote API:
// POST "/image/prune"
type ContainersPruneConfig struct {
}

// VolumesPruneConfig contains the configuration for Remote API:
// POST "/images/prune"
type VolumesPruneConfig struct {
}

// ContainersPruneReport contains the response for Remote API:
// POST "/containers/prune"
type ContainersPruneReport struct {
ContainersDeleted []string
SpaceReclaimed uint64
}

// VolumesPruneReport contains the response for Remote API:
// POST "/volumes/prune"
type VolumesPruneReport struct {
VolumesDeleted []string
SpaceReclaimed uint64
}

// ImagesPruneReport contains the response for Remote API:
// POST "/image/prune"
type ImagesPruneReport struct {
ImagesDeleted []ImageDelete
SpaceReclaimed uint64
}
@@ -44,6 +44,7 @@ func NewContainerCommand(dockerCli *command.DockerCli) *cobra.Command {
NewWaitCommand(dockerCli),
newListCommand(dockerCli),
newInspectCommand(dockerCli),
NewPruneCommand(dockerCli),
)
return cmd
}
@@ -0,0 +1,74 @@
package container

import (
"fmt"

"golang.org/x/net/context"

"github.com/docker/docker/api/types"
"github.com/docker/docker/cli"
"github.com/docker/docker/cli/command"
units "github.com/docker/go-units"
"github.com/spf13/cobra"
)

type pruneOptions struct {
force bool
}

// NewPruneCommand returns a new cobra prune command for containers
func NewPruneCommand(dockerCli *command.DockerCli) *cobra.Command {
var opts pruneOptions

cmd := &cobra.Command{
Use: "prune",
Short: "Remove all stopped containers",
Args: cli.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
spaceReclaimed, output, err := runPrune(dockerCli, opts)
if err != nil {
return err
}
if output != "" {
fmt.Fprintln(dockerCli.Out(), output)
}
fmt.Fprintln(dockerCli.Out(), "Total reclaimed space:", units.HumanSize(float64(spaceReclaimed)))
return nil
},
}

flags := cmd.Flags()
flags.BoolVarP(&opts.force, "force", "f", false, "Do not prompt for confirmation")

return cmd
}

const warning = `WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] `

func runPrune(dockerCli *command.DockerCli, opts pruneOptions) (spaceReclaimed uint64, output string, err error) {
if !opts.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), warning) {
return
}

report, err := dockerCli.Client().ContainersPrune(context.Background(), types.ContainersPruneConfig{})
if err != nil {
return
}

if len(report.ContainersDeleted) > 0 {
output = "Deleted Containers:"
for _, id := range report.ContainersDeleted {
output += id + "\n"
}
spaceReclaimed = report.SpaceReclaimed
}

return
}

// RunPrune call the Container Prune API
// This returns the amount of space reclaimed and a detailed output string
func RunPrune(dockerCli *command.DockerCli) (uint64, string, error) {
return runPrune(dockerCli, pruneOptions{force: true})
}
@@ -15,7 +15,6 @@ import (
"github.com/docker/docker/cli"
"github.com/docker/docker/cli/command"
"github.com/docker/docker/cli/command/formatter"
"github.com/docker/docker/cli/command/system"
"github.com/spf13/cobra"
)

@@ -110,7 +109,7 @@ func runStats(dockerCli *command.DockerCli, opts *statsOptions) error {
// retrieving the list of running containers to avoid a race where we
// would "miss" a creation.
started := make(chan struct{})
eh := system.InitEventHandler()
eh := command.InitEventHandler()
eh.Handle("create", func(e events.Message) {
if opts.all {
s := formatter.NewContainerStats(e.ID[:12], daemonOSType)
@@ -1,4 +1,4 @@
package system
package command

import (
"sync"
@@ -23,6 +23,7 @@ const (
statusHeader = "STATUS"
portsHeader = "PORTS"
mountsHeader = "MOUNTS"
localVolumes = "LOCAL VOLUMES"
)

// NewContainerFormat returns a Format for rendering using a Context
@@ -199,3 +200,16 @@ func (c *containerContext) Mounts() string {
}
return strings.Join(mounts, ",")
}

func (c *containerContext) LocalVolumes() string {
c.AddHeader(localVolumes)

count := 0
for _, m := range c.c.Mounts {
if m.Driver == "local" {
count++
}
}

return fmt.Sprintf("%d", count)
}

0 comments on commit 86de7c0

Please sign in to comment.
You can’t perform that action at this time.