github.com/rita33cool1/iot-system-gateway@v0.0.0-20200911033302-e65bde238cc5/docker-engine/internal/test/environment/clean.go (about)

     1  package environment // import "github.com/docker/docker/internal/test/environment"
     2  
     3  import (
     4  	"regexp"
     5  	"strings"
     6  
     7  	"github.com/docker/docker/api/types"
     8  	"github.com/docker/docker/api/types/filters"
     9  	"github.com/docker/docker/client"
    10  	"github.com/gotestyourself/gotestyourself/assert"
    11  	"golang.org/x/net/context"
    12  )
    13  
    14  type testingT interface {
    15  	assert.TestingT
    16  	logT
    17  	Fatalf(string, ...interface{})
    18  }
    19  
    20  type logT interface {
    21  	Logf(string, ...interface{})
    22  }
    23  
    24  // Clean the environment, preserving protected objects (images, containers, ...)
    25  // and removing everything else. It's meant to run after any tests so that they don't
    26  // depend on each others.
    27  func (e *Execution) Clean(t testingT) {
    28  	client := e.APIClient()
    29  
    30  	platform := e.OSType
    31  	if (platform != "windows") || (platform == "windows" && e.DaemonInfo.Isolation == "hyperv") {
    32  		unpauseAllContainers(t, client)
    33  	}
    34  	deleteAllContainers(t, client, e.protectedElements.containers)
    35  	deleteAllImages(t, client, e.protectedElements.images)
    36  	deleteAllVolumes(t, client, e.protectedElements.volumes)
    37  	deleteAllNetworks(t, client, platform, e.protectedElements.networks)
    38  	if platform == "linux" {
    39  		deleteAllPlugins(t, client, e.protectedElements.plugins)
    40  	}
    41  }
    42  
    43  func unpauseAllContainers(t assert.TestingT, client client.ContainerAPIClient) {
    44  	ctx := context.Background()
    45  	containers := getPausedContainers(ctx, t, client)
    46  	if len(containers) > 0 {
    47  		for _, container := range containers {
    48  			err := client.ContainerUnpause(ctx, container.ID)
    49  			assert.Check(t, err, "failed to unpause container %s", container.ID)
    50  		}
    51  	}
    52  }
    53  
    54  func getPausedContainers(ctx context.Context, t assert.TestingT, client client.ContainerAPIClient) []types.Container {
    55  	filter := filters.NewArgs()
    56  	filter.Add("status", "paused")
    57  	containers, err := client.ContainerList(ctx, types.ContainerListOptions{
    58  		Filters: filter,
    59  		Quiet:   true,
    60  		All:     true,
    61  	})
    62  	assert.Check(t, err, "failed to list containers")
    63  	return containers
    64  }
    65  
    66  var alreadyExists = regexp.MustCompile(`Error response from daemon: removal of container (\w+) is already in progress`)
    67  
    68  func deleteAllContainers(t assert.TestingT, apiclient client.ContainerAPIClient, protectedContainers map[string]struct{}) {
    69  	ctx := context.Background()
    70  	containers := getAllContainers(ctx, t, apiclient)
    71  	if len(containers) == 0 {
    72  		return
    73  	}
    74  
    75  	for _, container := range containers {
    76  		if _, ok := protectedContainers[container.ID]; ok {
    77  			continue
    78  		}
    79  		err := apiclient.ContainerRemove(ctx, container.ID, types.ContainerRemoveOptions{
    80  			Force:         true,
    81  			RemoveVolumes: true,
    82  		})
    83  		if err == nil || client.IsErrNotFound(err) || alreadyExists.MatchString(err.Error()) || isErrNotFoundSwarmClassic(err) {
    84  			continue
    85  		}
    86  		assert.Check(t, err, "failed to remove %s", container.ID)
    87  	}
    88  }
    89  
    90  func getAllContainers(ctx context.Context, t assert.TestingT, client client.ContainerAPIClient) []types.Container {
    91  	containers, err := client.ContainerList(ctx, types.ContainerListOptions{
    92  		Quiet: true,
    93  		All:   true,
    94  	})
    95  	assert.Check(t, err, "failed to list containers")
    96  	return containers
    97  }
    98  
    99  func deleteAllImages(t testingT, apiclient client.ImageAPIClient, protectedImages map[string]struct{}) {
   100  	images, err := apiclient.ImageList(context.Background(), types.ImageListOptions{})
   101  	assert.Check(t, err, "failed to list images")
   102  
   103  	ctx := context.Background()
   104  	for _, image := range images {
   105  		tags := tagsFromImageSummary(image)
   106  		if len(tags) == 0 {
   107  			t.Logf("Removing image %s", image.ID)
   108  			removeImage(ctx, t, apiclient, image.ID)
   109  			continue
   110  		}
   111  		for _, tag := range tags {
   112  			if _, ok := protectedImages[tag]; !ok {
   113  				t.Logf("Removing image %s", tag)
   114  				removeImage(ctx, t, apiclient, tag)
   115  				continue
   116  			}
   117  		}
   118  	}
   119  }
   120  
   121  func removeImage(ctx context.Context, t assert.TestingT, apiclient client.ImageAPIClient, ref string) {
   122  	_, err := apiclient.ImageRemove(ctx, ref, types.ImageRemoveOptions{
   123  		Force: true,
   124  	})
   125  	if client.IsErrNotFound(err) {
   126  		return
   127  	}
   128  	assert.Check(t, err, "failed to remove image %s", ref)
   129  }
   130  
   131  func deleteAllVolumes(t assert.TestingT, c client.VolumeAPIClient, protectedVolumes map[string]struct{}) {
   132  	volumes, err := c.VolumeList(context.Background(), filters.Args{})
   133  	assert.Check(t, err, "failed to list volumes")
   134  
   135  	for _, v := range volumes.Volumes {
   136  		if _, ok := protectedVolumes[v.Name]; ok {
   137  			continue
   138  		}
   139  		err := c.VolumeRemove(context.Background(), v.Name, true)
   140  		// Docker EE may list volumes that no longer exist.
   141  		if isErrNotFoundSwarmClassic(err) {
   142  			continue
   143  		}
   144  		assert.Check(t, err, "failed to remove volume %s", v.Name)
   145  	}
   146  }
   147  
   148  func deleteAllNetworks(t assert.TestingT, c client.NetworkAPIClient, daemonPlatform string, protectedNetworks map[string]struct{}) {
   149  	networks, err := c.NetworkList(context.Background(), types.NetworkListOptions{})
   150  	assert.Check(t, err, "failed to list networks")
   151  
   152  	for _, n := range networks {
   153  		if n.Name == "bridge" || n.Name == "none" || n.Name == "host" {
   154  			continue
   155  		}
   156  		if _, ok := protectedNetworks[n.ID]; ok {
   157  			continue
   158  		}
   159  		if daemonPlatform == "windows" && strings.ToLower(n.Name) == "nat" {
   160  			// nat is a pre-defined network on Windows and cannot be removed
   161  			continue
   162  		}
   163  		err := c.NetworkRemove(context.Background(), n.ID)
   164  		assert.Check(t, err, "failed to remove network %s", n.ID)
   165  	}
   166  }
   167  
   168  func deleteAllPlugins(t assert.TestingT, c client.PluginAPIClient, protectedPlugins map[string]struct{}) {
   169  	plugins, err := c.PluginList(context.Background(), filters.Args{})
   170  	// Docker EE does not allow cluster-wide plugin management.
   171  	if client.IsErrNotImplemented(err) {
   172  		return
   173  	}
   174  	assert.Check(t, err, "failed to list plugins")
   175  
   176  	for _, p := range plugins {
   177  		if _, ok := protectedPlugins[p.Name]; ok {
   178  			continue
   179  		}
   180  		err := c.PluginRemove(context.Background(), p.Name, types.PluginRemoveOptions{Force: true})
   181  		assert.Check(t, err, "failed to remove plugin %s", p.ID)
   182  	}
   183  }
   184  
   185  // Swarm classic aggregates node errors and returns a 500 so we need to check
   186  // the error string instead of just IsErrNotFound().
   187  func isErrNotFoundSwarmClassic(err error) bool {
   188  	return err != nil && strings.Contains(strings.ToLower(err.Error()), "no such")
   189  }