clean.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. package environment
  2. import (
  3. "regexp"
  4. "strings"
  5. "github.com/docker/docker/api/types"
  6. "github.com/docker/docker/api/types/filters"
  7. "github.com/docker/docker/client"
  8. "github.com/stretchr/testify/assert"
  9. "github.com/stretchr/testify/require"
  10. "golang.org/x/net/context"
  11. )
  12. type testingT interface {
  13. require.TestingT
  14. logT
  15. Fatalf(string, ...interface{})
  16. }
  17. type logT interface {
  18. Logf(string, ...interface{})
  19. }
  20. // Clean the environment, preserving protected objects (images, containers, ...)
  21. // and removing everything else. It's meant to run after any tests so that they don't
  22. // depend on each others.
  23. func (e *Execution) Clean(t testingT) {
  24. client := e.APIClient()
  25. platform := e.OSType
  26. if (platform != "windows") || (platform == "windows" && e.DaemonInfo.Isolation == "hyperv") {
  27. unpauseAllContainers(t, client)
  28. }
  29. deleteAllContainers(t, client, e.protectedElements.containers)
  30. deleteAllImages(t, client, e.protectedElements.images)
  31. deleteAllVolumes(t, client, e.protectedElements.volumes)
  32. deleteAllNetworks(t, client, platform, e.protectedElements.networks)
  33. if platform == "linux" {
  34. deleteAllPlugins(t, client, e.protectedElements.plugins)
  35. }
  36. }
  37. func unpauseAllContainers(t assert.TestingT, client client.ContainerAPIClient) {
  38. ctx := context.Background()
  39. containers := getPausedContainers(ctx, t, client)
  40. if len(containers) > 0 {
  41. for _, container := range containers {
  42. err := client.ContainerUnpause(ctx, container.ID)
  43. assert.NoError(t, err, "failed to unpause container %s", container.ID)
  44. }
  45. }
  46. }
  47. func getPausedContainers(ctx context.Context, t assert.TestingT, client client.ContainerAPIClient) []types.Container {
  48. filter := filters.NewArgs()
  49. filter.Add("status", "paused")
  50. containers, err := client.ContainerList(ctx, types.ContainerListOptions{
  51. Filters: filter,
  52. Quiet: true,
  53. All: true,
  54. })
  55. assert.NoError(t, err, "failed to list containers")
  56. return containers
  57. }
  58. var alreadyExists = regexp.MustCompile(`Error response from daemon: removal of container (\w+) is already in progress`)
  59. func deleteAllContainers(t assert.TestingT, apiclient client.ContainerAPIClient, protectedContainers map[string]struct{}) {
  60. ctx := context.Background()
  61. containers := getAllContainers(ctx, t, apiclient)
  62. if len(containers) == 0 {
  63. return
  64. }
  65. for _, container := range containers {
  66. if _, ok := protectedContainers[container.ID]; ok {
  67. continue
  68. }
  69. err := apiclient.ContainerRemove(ctx, container.ID, types.ContainerRemoveOptions{
  70. Force: true,
  71. RemoveVolumes: true,
  72. })
  73. if err == nil || client.IsErrNotFound(err) || alreadyExists.MatchString(err.Error()) {
  74. continue
  75. }
  76. assert.NoError(t, err, "failed to remove %s", container.ID)
  77. }
  78. }
  79. func getAllContainers(ctx context.Context, t assert.TestingT, client client.ContainerAPIClient) []types.Container {
  80. containers, err := client.ContainerList(ctx, types.ContainerListOptions{
  81. Quiet: true,
  82. All: true,
  83. })
  84. assert.NoError(t, err, "failed to list containers")
  85. return containers
  86. }
  87. func deleteAllImages(t testingT, apiclient client.ImageAPIClient, protectedImages map[string]struct{}) {
  88. images, err := apiclient.ImageList(context.Background(), types.ImageListOptions{})
  89. assert.NoError(t, err, "failed to list images")
  90. ctx := context.Background()
  91. for _, image := range images {
  92. tags := tagsFromImageSummary(image)
  93. if len(tags) == 0 {
  94. t.Logf("Removing image %s", image.ID)
  95. removeImage(ctx, t, apiclient, image.ID)
  96. continue
  97. }
  98. for _, tag := range tags {
  99. if _, ok := protectedImages[tag]; !ok {
  100. t.Logf("Removing image %s", tag)
  101. removeImage(ctx, t, apiclient, tag)
  102. continue
  103. }
  104. }
  105. }
  106. }
  107. func removeImage(ctx context.Context, t assert.TestingT, apiclient client.ImageAPIClient, ref string) {
  108. _, err := apiclient.ImageRemove(ctx, ref, types.ImageRemoveOptions{
  109. Force: true,
  110. })
  111. if client.IsErrNotFound(err) {
  112. return
  113. }
  114. assert.NoError(t, err, "failed to remove image %s", ref)
  115. }
  116. func deleteAllVolumes(t assert.TestingT, c client.VolumeAPIClient, protectedVolumes map[string]struct{}) {
  117. volumes, err := c.VolumeList(context.Background(), filters.Args{})
  118. assert.NoError(t, err, "failed to list volumes")
  119. for _, v := range volumes.Volumes {
  120. if _, ok := protectedVolumes[v.Name]; ok {
  121. continue
  122. }
  123. err := c.VolumeRemove(context.Background(), v.Name, true)
  124. assert.NoError(t, err, "failed to remove volume %s", v.Name)
  125. }
  126. }
  127. func deleteAllNetworks(t assert.TestingT, c client.NetworkAPIClient, daemonPlatform string, protectedNetworks map[string]struct{}) {
  128. networks, err := c.NetworkList(context.Background(), types.NetworkListOptions{})
  129. assert.NoError(t, err, "failed to list networks")
  130. for _, n := range networks {
  131. if n.Name == "bridge" || n.Name == "none" || n.Name == "host" {
  132. continue
  133. }
  134. if _, ok := protectedNetworks[n.ID]; ok {
  135. continue
  136. }
  137. if daemonPlatform == "windows" && strings.ToLower(n.Name) == "nat" {
  138. // nat is a pre-defined network on Windows and cannot be removed
  139. continue
  140. }
  141. err := c.NetworkRemove(context.Background(), n.ID)
  142. assert.NoError(t, err, "failed to remove network %s", n.ID)
  143. }
  144. }
  145. func deleteAllPlugins(t assert.TestingT, c client.PluginAPIClient, protectedPlugins map[string]struct{}) {
  146. plugins, err := c.PluginList(context.Background(), filters.Args{})
  147. assert.NoError(t, err, "failed to list plugins")
  148. for _, p := range plugins {
  149. if _, ok := protectedPlugins[p.Name]; ok {
  150. continue
  151. }
  152. err := c.PluginRemove(context.Background(), p.Name, types.PluginRemoveOptions{Force: true})
  153. assert.NoError(t, err, "failed to remove plugin %s", p.ID)
  154. }
  155. }