github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/testutil/environment/protect.go (about)

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