github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/testutil/environment/protect.go (about)

     1  package environment
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  
     7  	"github.com/docker/docker/api/types"
     8  	"github.com/docker/docker/api/types/filters"
     9  	dclient "github.com/docker/docker/client"
    10  	"gotest.tools/v3/assert"
    11  )
    12  
    13  var frozenImages = []string{"busybox:latest", "busybox:glibc", "hello-world:frozen", "debian:jessie"}
    14  
    15  type protectedElements struct {
    16  	containers map[string]struct{}
    17  	images     map[string]struct{}
    18  	networks   map[string]struct{}
    19  	plugins    map[string]struct{}
    20  	volumes    map[string]struct{}
    21  }
    22  
    23  func newProtectedElements() protectedElements {
    24  	return protectedElements{
    25  		containers: map[string]struct{}{},
    26  		images:     map[string]struct{}{},
    27  		networks:   map[string]struct{}{},
    28  		plugins:    map[string]struct{}{},
    29  		volumes:    map[string]struct{}{},
    30  	}
    31  }
    32  
    33  // ProtectAll protects the existing environment (containers, images, networks,
    34  // volumes, and, on Linux, plugins) from being cleaned up at the end of test
    35  // runs
    36  func ProtectAll(t testing.TB, testEnv *Execution) {
    37  	t.Helper()
    38  	ProtectContainers(t, testEnv)
    39  	ProtectImages(t, testEnv)
    40  	ProtectNetworks(t, testEnv)
    41  	ProtectVolumes(t, testEnv)
    42  	if testEnv.OSType == "linux" {
    43  		ProtectPlugins(t, testEnv)
    44  	}
    45  }
    46  
    47  // ProtectContainer adds the specified container(s) to be protected in case of
    48  // clean
    49  func (e *Execution) ProtectContainer(t testing.TB, containers ...string) {
    50  	t.Helper()
    51  	for _, container := range containers {
    52  		e.protectedElements.containers[container] = struct{}{}
    53  	}
    54  }
    55  
    56  // ProtectContainers protects existing containers from being cleaned up at the
    57  // end of test runs
    58  func ProtectContainers(t testing.TB, testEnv *Execution) {
    59  	t.Helper()
    60  	containers := getExistingContainers(t, testEnv)
    61  	testEnv.ProtectContainer(t, containers...)
    62  }
    63  
    64  func getExistingContainers(t testing.TB, testEnv *Execution) []string {
    65  	t.Helper()
    66  	client := testEnv.APIClient()
    67  	containerList, err := client.ContainerList(context.Background(), types.ContainerListOptions{
    68  		All: true,
    69  	})
    70  	assert.NilError(t, err, "failed to list containers")
    71  
    72  	var containers []string
    73  	for _, container := range containerList {
    74  		containers = append(containers, container.ID)
    75  	}
    76  	return containers
    77  }
    78  
    79  // ProtectImage adds the specified image(s) to be protected in case of clean
    80  func (e *Execution) ProtectImage(t testing.TB, images ...string) {
    81  	t.Helper()
    82  	for _, image := range images {
    83  		e.protectedElements.images[image] = struct{}{}
    84  	}
    85  }
    86  
    87  // ProtectImages protects existing images and on linux frozen images from being
    88  // cleaned up at the end of test runs
    89  func ProtectImages(t testing.TB, testEnv *Execution) {
    90  	t.Helper()
    91  	images := getExistingImages(t, testEnv)
    92  
    93  	if testEnv.OSType == "linux" {
    94  		images = append(images, frozenImages...)
    95  	}
    96  	testEnv.ProtectImage(t, images...)
    97  }
    98  
    99  func getExistingImages(t testing.TB, testEnv *Execution) []string {
   100  	t.Helper()
   101  	client := testEnv.APIClient()
   102  	filter := filters.NewArgs()
   103  	filter.Add("dangling", "false")
   104  	imageList, err := client.ImageList(context.Background(), types.ImageListOptions{
   105  		All:     true,
   106  		Filters: filter,
   107  	})
   108  	assert.NilError(t, err, "failed to list images")
   109  
   110  	var images []string
   111  	for _, image := range imageList {
   112  		images = append(images, tagsFromImageSummary(image)...)
   113  	}
   114  	return images
   115  }
   116  
   117  func tagsFromImageSummary(image types.ImageSummary) []string {
   118  	var result []string
   119  	for _, tag := range image.RepoTags {
   120  		if tag != "<none>:<none>" {
   121  			result = append(result, tag)
   122  		}
   123  	}
   124  	for _, digest := range image.RepoDigests {
   125  		if digest != "<none>@<none>" {
   126  			result = append(result, digest)
   127  		}
   128  	}
   129  	return result
   130  }
   131  
   132  // ProtectNetwork adds the specified network(s) to be protected in case of
   133  // clean
   134  func (e *Execution) ProtectNetwork(t testing.TB, networks ...string) {
   135  	t.Helper()
   136  	for _, network := range networks {
   137  		e.protectedElements.networks[network] = struct{}{}
   138  	}
   139  }
   140  
   141  // ProtectNetworks protects existing networks from being cleaned up at the end
   142  // of test runs
   143  func ProtectNetworks(t testing.TB, testEnv *Execution) {
   144  	t.Helper()
   145  	networks := getExistingNetworks(t, testEnv)
   146  	testEnv.ProtectNetwork(t, networks...)
   147  }
   148  
   149  func getExistingNetworks(t testing.TB, testEnv *Execution) []string {
   150  	t.Helper()
   151  	client := testEnv.APIClient()
   152  	networkList, err := client.NetworkList(context.Background(), types.NetworkListOptions{})
   153  	assert.NilError(t, err, "failed to list networks")
   154  
   155  	var networks []string
   156  	for _, network := range networkList {
   157  		networks = append(networks, network.ID)
   158  	}
   159  	return networks
   160  }
   161  
   162  // ProtectPlugin adds the specified plugin(s) to be protected in case of clean
   163  func (e *Execution) ProtectPlugin(t testing.TB, plugins ...string) {
   164  	t.Helper()
   165  	for _, plugin := range plugins {
   166  		e.protectedElements.plugins[plugin] = struct{}{}
   167  	}
   168  }
   169  
   170  // ProtectPlugins protects existing plugins from being cleaned up at the end of
   171  // test runs
   172  func ProtectPlugins(t testing.TB, testEnv *Execution) {
   173  	t.Helper()
   174  	plugins := getExistingPlugins(t, testEnv)
   175  	testEnv.ProtectPlugin(t, plugins...)
   176  }
   177  
   178  func getExistingPlugins(t testing.TB, testEnv *Execution) []string {
   179  	t.Helper()
   180  	client := testEnv.APIClient()
   181  	pluginList, err := client.PluginList(context.Background(), filters.Args{})
   182  	// Docker EE does not allow cluster-wide plugin management.
   183  	if dclient.IsErrNotImplemented(err) {
   184  		return []string{}
   185  	}
   186  	assert.NilError(t, err, "failed to list plugins")
   187  
   188  	var plugins []string
   189  	for _, plugin := range pluginList {
   190  		plugins = append(plugins, plugin.Name)
   191  	}
   192  	return plugins
   193  }
   194  
   195  // ProtectVolume adds the specified volume(s) to be protected in case of clean
   196  func (e *Execution) ProtectVolume(t testing.TB, volumes ...string) {
   197  	t.Helper()
   198  	for _, volume := range volumes {
   199  		e.protectedElements.volumes[volume] = struct{}{}
   200  	}
   201  }
   202  
   203  // ProtectVolumes protects existing volumes from being cleaned up at the end of
   204  // test runs
   205  func ProtectVolumes(t testing.TB, testEnv *Execution) {
   206  	t.Helper()
   207  	volumes := getExistingVolumes(t, testEnv)
   208  	testEnv.ProtectVolume(t, volumes...)
   209  }
   210  
   211  func getExistingVolumes(t testing.TB, testEnv *Execution) []string {
   212  	t.Helper()
   213  	client := testEnv.APIClient()
   214  	volumeList, err := client.VolumeList(context.Background(), filters.Args{})
   215  	assert.NilError(t, err, "failed to list volumes")
   216  
   217  	var volumes []string
   218  	for _, volume := range volumeList.Volumes {
   219  		volumes = append(volumes, volume.Name)
   220  	}
   221  	return volumes
   222  }