add docker network prune
`docker network prune` prunes unused networks, including overlay ones. `docker system prune` also prunes unused networks. Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
This commit is contained in:
parent
f901c5ed1c
commit
7e24c16086
29 changed files with 399 additions and 3 deletions
|
@ -17,4 +17,5 @@ type Backend interface {
|
|||
ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error
|
||||
DisconnectContainerFromNetwork(containerName string, networkName string, force bool) error
|
||||
DeleteNetwork(name string) error
|
||||
NetworksPrune(config *types.NetworksPruneConfig) (*types.NetworksPruneReport, error)
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ func (r *networkRouter) initRoutes() {
|
|||
router.NewPostRoute("/networks/create", r.postNetworkCreate),
|
||||
router.NewPostRoute("/networks/{id:.*}/connect", r.postNetworkConnect),
|
||||
router.NewPostRoute("/networks/{id:.*}/disconnect", r.postNetworkDisconnect),
|
||||
router.NewPostRoute("/networks/prune", r.postNetworksPrune),
|
||||
// DELETE
|
||||
router.NewDeleteRoute("/networks/{id:.*}", r.deleteNetwork),
|
||||
}
|
||||
|
|
|
@ -274,3 +274,24 @@ func buildEndpointResource(id string, name string, info libnetwork.EndpointInfo)
|
|||
}
|
||||
return er
|
||||
}
|
||||
|
||||
func (n *networkRouter) postNetworksPrune(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.NetworksPruneConfig
|
||||
if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pruneReport, err := n.backend.NetworksPrune(&cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return httputils.WriteJSON(w, http.StatusOK, pruneReport)
|
||||
}
|
||||
|
|
|
@ -522,6 +522,11 @@ type ContainersPruneConfig struct {
|
|||
type VolumesPruneConfig struct {
|
||||
}
|
||||
|
||||
// NetworksPruneConfig contains the configuration for Remote API:
|
||||
// POST "/networks/prune"
|
||||
type NetworksPruneConfig struct {
|
||||
}
|
||||
|
||||
// ContainersPruneReport contains the response for Remote API:
|
||||
// POST "/containers/prune"
|
||||
type ContainersPruneReport struct {
|
||||
|
@ -542,3 +547,9 @@ type ImagesPruneReport struct {
|
|||
ImagesDeleted []ImageDelete
|
||||
SpaceReclaimed uint64
|
||||
}
|
||||
|
||||
// NetworksPruneReport contains the response for Remote API:
|
||||
// POST "/networks/prune"
|
||||
type NetworksPruneReport struct {
|
||||
NetworksDeleted []string
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ func NewNetworkCommand(dockerCli *command.DockerCli) *cobra.Command {
|
|||
newInspectCommand(dockerCli),
|
||||
newListCommand(dockerCli),
|
||||
newRemoveCommand(dockerCli),
|
||||
NewPruneCommand(dockerCli),
|
||||
)
|
||||
return cmd
|
||||
}
|
||||
|
|
72
cli/command/network/prune.go
Normal file
72
cli/command/network/prune.go
Normal file
|
@ -0,0 +1,72 @@
|
|||
package network
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/cli/command"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type pruneOptions struct {
|
||||
force bool
|
||||
}
|
||||
|
||||
// NewPruneCommand returns a new cobra prune command for networks
|
||||
func NewPruneCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||
var opts pruneOptions
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "prune [OPTIONS]",
|
||||
Short: "Remove all unused networks",
|
||||
Args: cli.NoArgs,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
output, err := runPrune(dockerCli, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if output != "" {
|
||||
fmt.Fprintln(dockerCli.Out(), output)
|
||||
}
|
||||
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 networks not used by at least one container.
|
||||
Are you sure you want to continue?`
|
||||
|
||||
func runPrune(dockerCli *command.DockerCli, opts pruneOptions) (output string, err error) {
|
||||
if !opts.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), warning) {
|
||||
return
|
||||
}
|
||||
|
||||
report, err := dockerCli.Client().NetworksPrune(context.Background(), types.NetworksPruneConfig{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(report.NetworksDeleted) > 0 {
|
||||
output = "Deleted Networks:\n"
|
||||
for _, id := range report.NetworksDeleted {
|
||||
output += id + "\n"
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// RunPrune calls the Network Prune API
|
||||
// This returns the amount of space reclaimed and a detailed output string
|
||||
func RunPrune(dockerCli *command.DockerCli) (uint64, string, error) {
|
||||
output, err := runPrune(dockerCli, pruneOptions{force: true})
|
||||
return 0, output, err
|
||||
}
|
|
@ -4,6 +4,7 @@ import (
|
|||
"github.com/docker/docker/cli/command"
|
||||
"github.com/docker/docker/cli/command/container"
|
||||
"github.com/docker/docker/cli/command/image"
|
||||
"github.com/docker/docker/cli/command/network"
|
||||
"github.com/docker/docker/cli/command/volume"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
@ -23,6 +24,11 @@ func NewImagePruneCommand(dockerCli *command.DockerCli) *cobra.Command {
|
|||
return image.NewPruneCommand(dockerCli)
|
||||
}
|
||||
|
||||
// NewNetworkPruneCommand returns a cobra prune command for Networks
|
||||
func NewNetworkPruneCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||
return network.NewPruneCommand(dockerCli)
|
||||
}
|
||||
|
||||
// RunContainerPrune executes a prune command for containers
|
||||
func RunContainerPrune(dockerCli *command.DockerCli) (uint64, string, error) {
|
||||
return container.RunPrune(dockerCli)
|
||||
|
@ -37,3 +43,8 @@ func RunVolumePrune(dockerCli *command.DockerCli) (uint64, string, error) {
|
|||
func RunImagePrune(dockerCli *command.DockerCli, all bool) (uint64, string, error) {
|
||||
return image.RunPrune(dockerCli, all)
|
||||
}
|
||||
|
||||
// RunNetworkPrune executes a prune command for networks
|
||||
func RunNetworkPrune(dockerCli *command.DockerCli) (uint64, string, error) {
|
||||
return network.RunPrune(dockerCli)
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ const (
|
|||
warning = `WARNING! This will remove:
|
||||
- all stopped containers
|
||||
- all volumes not used by at least one container
|
||||
- all networks not used by at least one container
|
||||
%s
|
||||
Are you sure you want to continue?`
|
||||
|
||||
|
@ -64,13 +65,14 @@ func runPrune(dockerCli *command.DockerCli, opts pruneOptions) error {
|
|||
for _, pruneFn := range []func(dockerCli *command.DockerCli) (uint64, string, error){
|
||||
prune.RunContainerPrune,
|
||||
prune.RunVolumePrune,
|
||||
prune.RunNetworkPrune,
|
||||
} {
|
||||
spc, output, err := pruneFn(dockerCli)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if spc > 0 {
|
||||
spaceReclaimed += spc
|
||||
spaceReclaimed += spc
|
||||
if output != "" {
|
||||
fmt.Fprintln(dockerCli.Out(), output)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,6 +91,7 @@ type NetworkAPIClient interface {
|
|||
NetworkInspectWithRaw(ctx context.Context, networkID string) (types.NetworkResource, []byte, error)
|
||||
NetworkList(ctx context.Context, options types.NetworkListOptions) ([]types.NetworkResource, error)
|
||||
NetworkRemove(ctx context.Context, networkID string) error
|
||||
NetworksPrune(ctx context.Context, cfg types.NetworksPruneConfig) (types.NetworksPruneReport, error)
|
||||
}
|
||||
|
||||
// NodeAPIClient defines API client methods for the nodes
|
||||
|
|
26
client/network_prune.go
Normal file
26
client/network_prune.go
Normal file
|
@ -0,0 +1,26 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// NetworksPrune requests the daemon to delete unused networks
|
||||
func (cli *Client) NetworksPrune(ctx context.Context, cfg types.NetworksPruneConfig) (types.NetworksPruneReport, error) {
|
||||
var report types.NetworksPruneReport
|
||||
|
||||
serverResp, err := cli.post(ctx, "/networks/prune", nil, cfg, nil)
|
||||
if err != nil {
|
||||
return report, err
|
||||
}
|
||||
defer ensureReaderClosed(serverResp)
|
||||
|
||||
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
|
||||
return report, fmt.Errorf("Error retrieving network prune report: %v", err)
|
||||
}
|
||||
|
||||
return report, nil
|
||||
}
|
|
@ -279,6 +279,7 @@ func (cli *DaemonCli) start(opts daemonOptions) (err error) {
|
|||
|
||||
// initMiddlewares needs cli.d to be populated. Dont change this init order.
|
||||
cli.initMiddlewares(api, serverConfig)
|
||||
d.SetCluster(c)
|
||||
initRouter(api, d, c)
|
||||
|
||||
cli.setupConfigReloadTrap()
|
||||
|
|
12
daemon/cluster.go
Normal file
12
daemon/cluster.go
Normal file
|
@ -0,0 +1,12 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
apitypes "github.com/docker/docker/api/types"
|
||||
)
|
||||
|
||||
// Cluster is the interface for github.com/docker/docker/daemon/cluster.(*Cluster).
|
||||
type Cluster interface {
|
||||
GetNetwork(input string) (apitypes.NetworkResource, error)
|
||||
GetNetworks() ([]apitypes.NetworkResource, error)
|
||||
RemoveNetwork(input string) error
|
||||
}
|
|
@ -102,6 +102,7 @@ type Daemon struct {
|
|||
containerdRemote libcontainerd.Remote
|
||||
defaultIsolation containertypes.Isolation // Default isolation mode on Windows
|
||||
clusterProvider cluster.Provider
|
||||
cluster Cluster
|
||||
}
|
||||
|
||||
// HasExperimental returns whether the experimental features of the daemon are enabled or not
|
||||
|
@ -1234,3 +1235,13 @@ func copyBlkioEntry(entries []*containerd.BlkioStatsEntry) []types.BlkioStatEntr
|
|||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// GetCluster returns the cluster
|
||||
func (daemon *Daemon) GetCluster() Cluster {
|
||||
return daemon.cluster
|
||||
}
|
||||
|
||||
// SetCluster sets the cluster
|
||||
func (daemon *Daemon) SetCluster(cluster Cluster) {
|
||||
daemon.cluster = cluster
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/docker/api/types"
|
||||
|
@ -8,7 +10,9 @@ import (
|
|||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/directory"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/runconfig"
|
||||
"github.com/docker/docker/volume"
|
||||
"github.com/docker/libnetwork"
|
||||
)
|
||||
|
||||
// ContainersPrune removes unused containers
|
||||
|
@ -150,3 +154,72 @@ func (daemon *Daemon) ImagesPrune(config *types.ImagesPruneConfig) (*types.Image
|
|||
|
||||
return rep, nil
|
||||
}
|
||||
|
||||
// localNetworksPrune removes unused local networks
|
||||
func (daemon *Daemon) localNetworksPrune(config *types.NetworksPruneConfig) (*types.NetworksPruneReport, error) {
|
||||
rep := &types.NetworksPruneReport{}
|
||||
var err error
|
||||
// When the function returns true, the walk will stop.
|
||||
l := func(nw libnetwork.Network) bool {
|
||||
nwName := nw.Name()
|
||||
predefined := runconfig.IsPreDefinedNetwork(nwName)
|
||||
if !predefined && len(nw.Endpoints()) == 0 {
|
||||
if err = daemon.DeleteNetwork(nw.ID()); err != nil {
|
||||
logrus.Warnf("could not remove network %s: %v", nwName, err)
|
||||
return false
|
||||
}
|
||||
rep.NetworksDeleted = append(rep.NetworksDeleted, nwName)
|
||||
}
|
||||
return false
|
||||
}
|
||||
daemon.netController.WalkNetworks(l)
|
||||
return rep, err
|
||||
}
|
||||
|
||||
// clusterNetworksPrune removes unused cluster networks
|
||||
func (daemon *Daemon) clusterNetworksPrune(config *types.NetworksPruneConfig) (*types.NetworksPruneReport, error) {
|
||||
rep := &types.NetworksPruneReport{}
|
||||
cluster := daemon.GetCluster()
|
||||
networks, err := cluster.GetNetworks()
|
||||
if err != nil {
|
||||
return rep, err
|
||||
}
|
||||
networkIsInUse := regexp.MustCompile(`network ([[:alnum:]]+) is in use`)
|
||||
for _, nw := range networks {
|
||||
if nw.Name == "ingress" {
|
||||
continue
|
||||
}
|
||||
// https://github.com/docker/docker/issues/24186
|
||||
// `docker network inspect` unfortunately displays ONLY those containers that are local to that node.
|
||||
// So we try to remove it anyway and check the error
|
||||
err = cluster.RemoveNetwork(nw.ID)
|
||||
if err != nil {
|
||||
// we can safely ignore the "network .. is in use" error
|
||||
match := networkIsInUse.FindStringSubmatch(err.Error())
|
||||
if len(match) != 2 || match[1] != nw.ID {
|
||||
logrus.Warnf("could not remove network %s: %v", nw.Name, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
rep.NetworksDeleted = append(rep.NetworksDeleted, nw.Name)
|
||||
}
|
||||
return rep, nil
|
||||
}
|
||||
|
||||
// NetworksPrune removes unused networks
|
||||
func (daemon *Daemon) NetworksPrune(config *types.NetworksPruneConfig) (*types.NetworksPruneReport, error) {
|
||||
rep := &types.NetworksPruneReport{}
|
||||
clusterRep, err := daemon.clusterNetworksPrune(config)
|
||||
if err != nil {
|
||||
logrus.Warnf("could not remove cluster networks: %v", err)
|
||||
} else {
|
||||
rep.NetworksDeleted = append(rep.NetworksDeleted, clusterRep.NetworksDeleted...)
|
||||
}
|
||||
localRep, err := daemon.localNetworksPrune(config)
|
||||
if err != nil {
|
||||
logrus.Warnf("could not remove local networks: %v", err)
|
||||
} else {
|
||||
rep.NetworksDeleted = append(rep.NetworksDeleted, localRep.NetworksDeleted...)
|
||||
}
|
||||
return rep, err
|
||||
}
|
||||
|
|
|
@ -157,8 +157,10 @@ This section lists each version from latest to oldest. Each listing includes a
|
|||
* `POST /containers/prune` prunes stopped containers.
|
||||
* `POST /images/prune` prunes unused images.
|
||||
* `POST /volumes/prune` prunes unused volumes.
|
||||
* `POST /networks/prune` prunes unused networks.
|
||||
* Every API response now includes a `Docker-Experimental` header specifying if experimental features are enabled (value can be `true` or `false`).
|
||||
|
||||
|
||||
### v1.24 API changes
|
||||
|
||||
[Docker Remote API v1.24](docker_remote_api_v1.24.md) documentation
|
||||
|
|
|
@ -3881,6 +3881,36 @@ Instruct the driver to remove the network (`id`).
|
|||
- **404** - no such network
|
||||
- **500** - server error
|
||||
|
||||
### Prune unused networks
|
||||
|
||||
`POST /networks/prune`
|
||||
|
||||
Delete unused networks
|
||||
|
||||
**Example request**:
|
||||
|
||||
POST /networks/prune HTTP/1.1
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"NetworksDeleted": [
|
||||
"n1"
|
||||
],
|
||||
}
|
||||
|
||||
**Status codes**:
|
||||
|
||||
- **200** – no error
|
||||
- **500** – server error
|
||||
|
||||
## 3.6 Plugins
|
||||
|
||||
### List plugins
|
||||
|
|
|
@ -43,4 +43,5 @@ Total reclaimed space: 212 B
|
|||
* [system df](system_df.md)
|
||||
* [volume prune](volume_prune.md)
|
||||
* [image prune](image_prune.md)
|
||||
* [network prune](network_prune.md)
|
||||
* [system prune](system_prune.md)
|
||||
|
|
|
@ -67,4 +67,5 @@ Total reclaimed space: 16.43 MB
|
|||
* [system df](system_df.md)
|
||||
* [container prune](container_prune.md)
|
||||
* [volume prune](volume_prune.md)
|
||||
* [network prune](network_prune.md)
|
||||
* [system prune](system_prune.md)
|
||||
|
|
|
@ -98,5 +98,6 @@ You can connect a container to one or more networks. The networks need not be th
|
|||
* [network disconnect](network_disconnect.md)
|
||||
* [network ls](network_ls.md)
|
||||
* [network rm](network_rm.md)
|
||||
* [network prune](network_prune.md)
|
||||
* [Understand Docker container networks](https://docs.docker.com/engine/userguide/networking/)
|
||||
* [Work with networks](https://docs.docker.com/engine/userguide/networking/work-with-networks/)
|
||||
|
|
|
@ -197,4 +197,5 @@ to create an externally isolated `overlay` network, you can specify the
|
|||
* [network disconnect](network_disconnect.md)
|
||||
* [network ls](network_ls.md)
|
||||
* [network rm](network_rm.md)
|
||||
* [network prune](network_prune.md)
|
||||
* [Understand Docker container networks](https://docs.docker.com/engine/userguide/networking/)
|
||||
|
|
|
@ -39,4 +39,5 @@ Disconnects a container from a network. The container must be running to disconn
|
|||
* [network create](network_create.md)
|
||||
* [network ls](network_ls.md)
|
||||
* [network rm](network_rm.md)
|
||||
* [network prune](network_prune.md)
|
||||
* [Understand Docker container networks](https://docs.docker.com/engine/userguide/networking/)
|
||||
|
|
|
@ -128,4 +128,5 @@ $ docker network inspect simple-network
|
|||
* [network create](network_create.md)
|
||||
* [network ls](network_ls.md)
|
||||
* [network rm](network_rm.md)
|
||||
* [network prune](network_prune.md)
|
||||
* [Understand Docker container networks](https://docs.docker.com/engine/userguide/networking/)
|
||||
|
|
|
@ -214,4 +214,5 @@ d1584f8dc718: host
|
|||
* [network create](network_create.md)
|
||||
* [network inspect](network_inspect.md)
|
||||
* [network rm](network_rm.md)
|
||||
* [network prune](network_prune.md)
|
||||
* [Understand Docker container networks](https://docs.docker.com/engine/userguide/networking/)
|
||||
|
|
45
docs/reference/commandline/network_prune.md
Normal file
45
docs/reference/commandline/network_prune.md
Normal file
|
@ -0,0 +1,45 @@
|
|||
---
|
||||
title: "network prune"
|
||||
description: "Remove unused networks"
|
||||
keywords: [network, prune, delete]
|
||||
---
|
||||
|
||||
# network prune
|
||||
|
||||
```markdown
|
||||
Usage: docker network prune [OPTIONS]
|
||||
|
||||
Remove all unused networks
|
||||
|
||||
Options:
|
||||
-f, --force Do not prompt for confirmation
|
||||
--help Print usage
|
||||
```
|
||||
|
||||
Remove all unused networks. Unused networks are those which are not referenced by any containers.
|
||||
|
||||
Example output:
|
||||
|
||||
```bash
|
||||
$ docker network prune
|
||||
WARNING! This will remove all networks not used by at least one container.
|
||||
Are you sure you want to continue? [y/N] y
|
||||
Deleted Networks:
|
||||
n1
|
||||
n2
|
||||
```
|
||||
|
||||
## Related information
|
||||
|
||||
* [network disconnect ](network_disconnect.md)
|
||||
* [network connect](network_connect.md)
|
||||
* [network create](network_create.md)
|
||||
* [network ls](network_ls.md)
|
||||
* [network inspect](network_inspect.md)
|
||||
* [network rm](network_rm.md)
|
||||
* [Understand Docker container networks](../../userguide/networking/index.md)
|
||||
* [system df](system_df.md)
|
||||
* [container prune](container_prune.md)
|
||||
* [image prune](image_prune.md)
|
||||
* [volume prune](volume_prune.md)
|
||||
* [system prune](system_prune.md)
|
|
@ -55,4 +55,5 @@ deletion.
|
|||
* [network create](network_create.md)
|
||||
* [network ls](network_ls.md)
|
||||
* [network inspect](network_inspect.md)
|
||||
* [network prune](network_prune.md)
|
||||
* [Understand Docker container networks](https://docs.docker.com/engine/userguide/networking/)
|
||||
|
|
|
@ -66,8 +66,11 @@ my-named-vol 0
|
|||
* `UNIQUE SIZE` is the amount of space that is only used by a given image
|
||||
* `SIZE` is the virtual size of the image, it is the sum of `SHARED SIZE` and `UNIQUE SIZE`
|
||||
|
||||
Note that network information is not shown because it doesn't consume the disk space.
|
||||
|
||||
## Related Information
|
||||
* [system prune](system_prune.md)
|
||||
* [container prune](container_prune.md)
|
||||
* [volume prune](volume_prune.md)
|
||||
* [image prune](image_prune.md)
|
||||
* [network prune](network_prune.md)
|
||||
|
|
|
@ -26,7 +26,7 @@ Options:
|
|||
--help Print usage
|
||||
```
|
||||
|
||||
Remove all unused containers, volumes and images (both dangling and unreferenced).
|
||||
Remove all unused containers, volumes, networks and images (both dangling and unreferenced).
|
||||
|
||||
Example output:
|
||||
|
||||
|
@ -35,6 +35,7 @@ $ docker system prune -a
|
|||
WARNING! This will remove:
|
||||
- all stopped containers
|
||||
- all volumes not used by at least one container
|
||||
- all networks not used by at least one container
|
||||
- all images without at least one container associated to them
|
||||
Are you sure you want to continue? [y/N] y
|
||||
Deleted Containers:
|
||||
|
@ -74,4 +75,5 @@ Total reclaimed space: 13.5 MB
|
|||
* [system df](system_df.md)
|
||||
* [container prune](container_prune.md)
|
||||
* [image prune](image_prune.md)
|
||||
* [network prune](network_prune.md)
|
||||
* [system prune](system_prune.md)
|
||||
|
|
|
@ -50,4 +50,5 @@ Total reclaimed space: 36 B
|
|||
* [system df](system_df.md)
|
||||
* [container prune](container_prune.md)
|
||||
* [image prune](image_prune.md)
|
||||
* [network prune](network_prune.md)
|
||||
* [system prune](system_prune.md)
|
||||
|
|
61
integration-cli/docker_cli_prune_unix_test.go
Normal file
61
integration-cli/docker_cli_prune_unix_test.go
Normal file
|
@ -0,0 +1,61 @@
|
|||
// +build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/pkg/integration/checker"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func pruneNetworkAndVerify(c *check.C, d *SwarmDaemon, kept, pruned []string) {
|
||||
_, err := d.Cmd("network", "prune", "--force")
|
||||
c.Assert(err, checker.IsNil)
|
||||
out, err := d.Cmd("network", "ls", "--format", "{{.Name}}")
|
||||
c.Assert(err, checker.IsNil)
|
||||
for _, s := range kept {
|
||||
c.Assert(out, checker.Contains, s)
|
||||
}
|
||||
for _, s := range pruned {
|
||||
c.Assert(out, checker.Not(checker.Contains), s)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestPruneNetwork(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
_, err := d.Cmd("network", "create", "n1") // used by container (testprune)
|
||||
c.Assert(err, checker.IsNil)
|
||||
_, err = d.Cmd("network", "create", "n2")
|
||||
c.Assert(err, checker.IsNil)
|
||||
_, err = d.Cmd("network", "create", "n3", "--driver", "overlay") // used by service (testprunesvc)
|
||||
c.Assert(err, checker.IsNil)
|
||||
_, err = d.Cmd("network", "create", "n4", "--driver", "overlay")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
cName := "testprune"
|
||||
_, err = d.Cmd("run", "-d", "--name", cName, "--net", "n1", "busybox", "top")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
serviceName := "testprunesvc"
|
||||
replicas := 1
|
||||
out, err := d.Cmd("service", "create", "--name", serviceName,
|
||||
"--replicas", strconv.Itoa(replicas),
|
||||
"--network", "n3",
|
||||
"busybox", "top")
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, replicas+1)
|
||||
|
||||
// prune and verify
|
||||
pruneNetworkAndVerify(c, d, []string{"n1", "n3"}, []string{"n2", "n4"})
|
||||
|
||||
// remove containers, then prune and verify again
|
||||
_, err = d.Cmd("rm", "-f", cName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
_, err = d.Cmd("service", "rm", serviceName)
|
||||
c.Assert(err, checker.IsNil)
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 0)
|
||||
pruneNetworkAndVerify(c, d, []string{}, []string{"n1", "n3"})
|
||||
}
|
Loading…
Reference in a new issue