github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/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 } 99 100 func getExistingImages(t testing.TB, testEnv *Execution) []string { 101 t.Helper() 102 client := testEnv.APIClient() 103 filter := filters.NewArgs() 104 filter.Add("dangling", "false") 105 imageList, err := client.ImageList(context.Background(), types.ImageListOptions{ 106 All: true, 107 Filters: filter, 108 }) 109 assert.NilError(t, err, "failed to list images") 110 111 var images []string 112 for _, image := range imageList { 113 images = append(images, tagsFromImageSummary(image)...) 114 } 115 return images 116 } 117 118 func tagsFromImageSummary(image types.ImageSummary) []string { 119 var result []string 120 for _, tag := range image.RepoTags { 121 if tag != "<none>:<none>" { 122 result = append(result, tag) 123 } 124 } 125 for _, digest := range image.RepoDigests { 126 if digest != "<none>@<none>" { 127 result = append(result, digest) 128 } 129 } 130 return result 131 } 132 133 // ProtectNetwork adds the specified network(s) to be protected in case of 134 // clean 135 func (e *Execution) ProtectNetwork(t testing.TB, networks ...string) { 136 t.Helper() 137 for _, network := range networks { 138 e.protectedElements.networks[network] = struct{}{} 139 } 140 } 141 142 // ProtectNetworks protects existing networks from being cleaned up at the end 143 // of test runs 144 func ProtectNetworks(t testing.TB, testEnv *Execution) { 145 t.Helper() 146 networks := getExistingNetworks(t, testEnv) 147 testEnv.ProtectNetwork(t, networks...) 148 } 149 150 func getExistingNetworks(t testing.TB, testEnv *Execution) []string { 151 t.Helper() 152 client := testEnv.APIClient() 153 networkList, err := client.NetworkList(context.Background(), types.NetworkListOptions{}) 154 assert.NilError(t, err, "failed to list networks") 155 156 var networks []string 157 for _, network := range networkList { 158 networks = append(networks, network.ID) 159 } 160 return networks 161 } 162 163 // ProtectPlugin adds the specified plugin(s) to be protected in case of clean 164 func (e *Execution) ProtectPlugin(t testing.TB, plugins ...string) { 165 t.Helper() 166 for _, plugin := range plugins { 167 e.protectedElements.plugins[plugin] = struct{}{} 168 } 169 } 170 171 // ProtectPlugins protects existing plugins from being cleaned up at the end of 172 // test runs 173 func ProtectPlugins(t testing.TB, testEnv *Execution) { 174 t.Helper() 175 plugins := getExistingPlugins(t, testEnv) 176 testEnv.ProtectPlugin(t, plugins...) 177 } 178 179 func getExistingPlugins(t testing.TB, testEnv *Execution) []string { 180 t.Helper() 181 client := testEnv.APIClient() 182 pluginList, err := client.PluginList(context.Background(), filters.Args{}) 183 // Docker EE does not allow cluster-wide plugin management. 184 if errdefs.IsNotImplemented(err) { 185 return []string{} 186 } 187 assert.NilError(t, err, "failed to list plugins") 188 189 var plugins []string 190 for _, plugin := range pluginList { 191 plugins = append(plugins, plugin.Name) 192 } 193 return plugins 194 } 195 196 // ProtectVolume adds the specified volume(s) to be protected in case of clean 197 func (e *Execution) ProtectVolume(t testing.TB, volumes ...string) { 198 t.Helper() 199 for _, vol := range volumes { 200 e.protectedElements.volumes[vol] = struct{}{} 201 } 202 } 203 204 // ProtectVolumes protects existing volumes from being cleaned up at the end of 205 // test runs 206 func ProtectVolumes(t testing.TB, testEnv *Execution) { 207 t.Helper() 208 volumes := getExistingVolumes(t, testEnv) 209 testEnv.ProtectVolume(t, volumes...) 210 } 211 212 func getExistingVolumes(t testing.TB, testEnv *Execution) []string { 213 t.Helper() 214 client := testEnv.APIClient() 215 volumeList, err := client.VolumeList(context.Background(), volume.ListOptions{}) 216 assert.NilError(t, err, "failed to list volumes") 217 218 var volumes []string 219 for _, vol := range volumeList.Volumes { 220 volumes = append(volumes, vol.Name) 221 } 222 return volumes 223 }