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 }