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