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