protect.go 6.1 KB

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