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