Browse code

Allow protection of entire environment during tests

Signed-off-by: Christopher Crone <christopher.crone@docker.com>

Christopher Crone authored on 2017/09/08 23:41:02
Showing 2 changed files
... ...
@@ -32,12 +32,12 @@ func (e *Execution) Clean(t testingT) {
32 32
 	if (platform != "windows") || (platform == "windows" && e.DaemonInfo.Isolation == "hyperv") {
33 33
 		unpauseAllContainers(t, client)
34 34
 	}
35
-	deleteAllContainers(t, client)
35
+	deleteAllContainers(t, client, e.protectedElements.containers)
36 36
 	deleteAllImages(t, client, e.protectedElements.images)
37
-	deleteAllVolumes(t, client)
38
-	deleteAllNetworks(t, client, platform)
37
+	deleteAllVolumes(t, client, e.protectedElements.volumes)
38
+	deleteAllNetworks(t, client, platform, e.protectedElements.networks)
39 39
 	if platform == "linux" {
40
-		deleteAllPlugins(t, client)
40
+		deleteAllPlugins(t, client, e.protectedElements.plugins)
41 41
 	}
42 42
 }
43 43
 
... ...
@@ -66,7 +66,7 @@ func getPausedContainers(ctx context.Context, t assert.TestingT, client client.C
66 66
 
67 67
 var alreadyExists = regexp.MustCompile(`Error response from daemon: removal of container (\w+) is already in progress`)
68 68
 
69
-func deleteAllContainers(t assert.TestingT, apiclient client.ContainerAPIClient) {
69
+func deleteAllContainers(t assert.TestingT, apiclient client.ContainerAPIClient, protectedContainers map[string]struct{}) {
70 70
 	ctx := context.Background()
71 71
 	containers := getAllContainers(ctx, t, apiclient)
72 72
 	if len(containers) == 0 {
... ...
@@ -74,6 +74,9 @@ func deleteAllContainers(t assert.TestingT, apiclient client.ContainerAPIClient)
74 74
 	}
75 75
 
76 76
 	for _, container := range containers {
77
+		if _, ok := protectedContainers[container.ID]; ok {
78
+			continue
79
+		}
77 80
 		err := apiclient.ContainerRemove(ctx, container.ID, types.ContainerRemoveOptions{
78 81
 			Force:         true,
79 82
 			RemoveVolumes: true,
... ...
@@ -126,17 +129,20 @@ func removeImage(ctx context.Context, t assert.TestingT, apiclient client.ImageA
126 126
 	assert.NoError(t, err, "failed to remove image %s", ref)
127 127
 }
128 128
 
129
-func deleteAllVolumes(t assert.TestingT, c client.VolumeAPIClient) {
129
+func deleteAllVolumes(t assert.TestingT, c client.VolumeAPIClient, protectedVolumes map[string]struct{}) {
130 130
 	volumes, err := c.VolumeList(context.Background(), filters.Args{})
131 131
 	assert.NoError(t, err, "failed to list volumes")
132 132
 
133 133
 	for _, v := range volumes.Volumes {
134
+		if _, ok := protectedVolumes[v.Name]; ok {
135
+			continue
136
+		}
134 137
 		err := c.VolumeRemove(context.Background(), v.Name, true)
135 138
 		assert.NoError(t, err, "failed to remove volume %s", v.Name)
136 139
 	}
137 140
 }
138 141
 
139
-func deleteAllNetworks(t assert.TestingT, c client.NetworkAPIClient, daemonPlatform string) {
142
+func deleteAllNetworks(t assert.TestingT, c client.NetworkAPIClient, daemonPlatform string, protectedNetworks map[string]struct{}) {
140 143
 	networks, err := c.NetworkList(context.Background(), types.NetworkListOptions{})
141 144
 	assert.NoError(t, err, "failed to list networks")
142 145
 
... ...
@@ -144,6 +150,9 @@ func deleteAllNetworks(t assert.TestingT, c client.NetworkAPIClient, daemonPlatf
144 144
 		if n.Name == "bridge" || n.Name == "none" || n.Name == "host" {
145 145
 			continue
146 146
 		}
147
+		if _, ok := protectedNetworks[n.ID]; ok {
148
+			continue
149
+		}
147 150
 		if daemonPlatform == "windows" && strings.ToLower(n.Name) == "nat" {
148 151
 			// nat is a pre-defined network on Windows and cannot be removed
149 152
 			continue
... ...
@@ -153,11 +162,14 @@ func deleteAllNetworks(t assert.TestingT, c client.NetworkAPIClient, daemonPlatf
153 153
 	}
154 154
 }
155 155
 
156
-func deleteAllPlugins(t assert.TestingT, c client.PluginAPIClient) {
156
+func deleteAllPlugins(t assert.TestingT, c client.PluginAPIClient, protectedPlugins map[string]struct{}) {
157 157
 	plugins, err := c.PluginList(context.Background(), filters.Args{})
158 158
 	assert.NoError(t, err, "failed to list plugins")
159 159
 
160 160
 	for _, p := range plugins {
161
+		if _, ok := protectedPlugins[p.Name]; ok {
162
+			continue
163
+		}
161 164
 		err := c.PluginRemove(context.Background(), p.Name, types.PluginRemoveOptions{Force: true})
162 165
 		assert.NoError(t, err, "failed to remove plugin %s", p.ID)
163 166
 	}
... ...
@@ -10,7 +10,63 @@ import (
10 10
 )
11 11
 
12 12
 type protectedElements struct {
13
-	images map[string]struct{}
13
+	containers map[string]struct{}
14
+	images     map[string]struct{}
15
+	networks   map[string]struct{}
16
+	plugins    map[string]struct{}
17
+	volumes    map[string]struct{}
18
+}
19
+
20
+func newProtectedElements() protectedElements {
21
+	return protectedElements{
22
+		containers: map[string]struct{}{},
23
+		images:     map[string]struct{}{},
24
+		networks:   map[string]struct{}{},
25
+		plugins:    map[string]struct{}{},
26
+		volumes:    map[string]struct{}{},
27
+	}
28
+}
29
+
30
+// ProtectAll protects the existing environment (containers, images, networks,
31
+// volumes, and, on Linux, plugins) from being cleaned up at the end of test
32
+// runs
33
+func ProtectAll(t testingT, testEnv *Execution) {
34
+	ProtectContainers(t, testEnv)
35
+	ProtectImages(t, testEnv)
36
+	ProtectNetworks(t, testEnv)
37
+	ProtectVolumes(t, testEnv)
38
+	if testEnv.DaemonInfo.OSType == "linux" {
39
+		ProtectPlugins(t, testEnv)
40
+	}
41
+}
42
+
43
+// ProtectContainer adds the specified container(s) to be protected in case of
44
+// clean
45
+func (e *Execution) ProtectContainer(t testingT, containers ...string) {
46
+	for _, container := range containers {
47
+		e.protectedElements.containers[container] = struct{}{}
48
+	}
49
+}
50
+
51
+// ProtectContainers protects existing containers from being cleaned up at the
52
+// end of test runs
53
+func ProtectContainers(t testingT, testEnv *Execution) {
54
+	containers := getExistingContainers(t, testEnv)
55
+	testEnv.ProtectContainer(t, containers...)
56
+}
57
+
58
+func getExistingContainers(t require.TestingT, testEnv *Execution) []string {
59
+	client := testEnv.APIClient()
60
+	containerList, err := client.ContainerList(context.Background(), types.ContainerListOptions{
61
+		All: true,
62
+	})
63
+	require.NoError(t, err, "failed to list containers")
64
+
65
+	containers := []string{}
66
+	for _, container := range containerList {
67
+		containers = append(containers, container.ID)
68
+	}
69
+	return containers
14 70
 }
15 71
 
16 72
 // ProtectImage adds the specified image(s) to be protected in case of clean
... ...
@@ -20,12 +76,6 @@ func (e *Execution) ProtectImage(t testingT, images ...string) {
20 20
 	}
21 21
 }
22 22
 
23
-func newProtectedElements() protectedElements {
24
-	return protectedElements{
25
-		images: map[string]struct{}{},
26
-	}
27
-}
28
-
29 23
 // ProtectImages protects existing images and on linux frozen images from being
30 24
 // cleaned up at the end of test runs
31 25
 func ProtectImages(t testingT, testEnv *Execution) {
... ...
@@ -42,6 +92,7 @@ func getExistingImages(t require.TestingT, testEnv *Execution) []string {
42 42
 	filter := filters.NewArgs()
43 43
 	filter.Add("dangling", "false")
44 44
 	imageList, err := client.ImageList(context.Background(), types.ImageListOptions{
45
+		All:     true,
45 46
 		Filters: filter,
46 47
 	})
47 48
 	require.NoError(t, err, "failed to list images")
... ...
@@ -76,3 +127,82 @@ func ensureFrozenImagesLinux(t testingT, testEnv *Execution) []string {
76 76
 	}
77 77
 	return images
78 78
 }
79
+
80
+// ProtectNetwork adds the specified network(s) to be protected in case of
81
+// clean
82
+func (e *Execution) ProtectNetwork(t testingT, networks ...string) {
83
+	for _, network := range networks {
84
+		e.protectedElements.networks[network] = struct{}{}
85
+	}
86
+}
87
+
88
+// ProtectNetworks protects existing networks from being cleaned up at the end
89
+// of test runs
90
+func ProtectNetworks(t testingT, testEnv *Execution) {
91
+	networks := getExistingNetworks(t, testEnv)
92
+	testEnv.ProtectNetwork(t, networks...)
93
+}
94
+
95
+func getExistingNetworks(t require.TestingT, testEnv *Execution) []string {
96
+	client := testEnv.APIClient()
97
+	networkList, err := client.NetworkList(context.Background(), types.NetworkListOptions{})
98
+	require.NoError(t, err, "failed to list networks")
99
+
100
+	networks := []string{}
101
+	for _, network := range networkList {
102
+		networks = append(networks, network.ID)
103
+	}
104
+	return networks
105
+}
106
+
107
+// ProtectPlugin adds the specified plugin(s) to be protected in case of clean
108
+func (e *Execution) ProtectPlugin(t testingT, plugins ...string) {
109
+	for _, plugin := range plugins {
110
+		e.protectedElements.plugins[plugin] = struct{}{}
111
+	}
112
+}
113
+
114
+// ProtectPlugins protects existing plugins from being cleaned up at the end of
115
+// test runs
116
+func ProtectPlugins(t testingT, testEnv *Execution) {
117
+	plugins := getExistingPlugins(t, testEnv)
118
+	testEnv.ProtectPlugin(t, plugins...)
119
+}
120
+
121
+func getExistingPlugins(t require.TestingT, testEnv *Execution) []string {
122
+	client := testEnv.APIClient()
123
+	pluginList, err := client.PluginList(context.Background(), filters.Args{})
124
+	require.NoError(t, err, "failed to list plugins")
125
+
126
+	plugins := []string{}
127
+	for _, plugin := range pluginList {
128
+		plugins = append(plugins, plugin.Name)
129
+	}
130
+	return plugins
131
+}
132
+
133
+// ProtectVolume adds the specified volume(s) to be protected in case of clean
134
+func (e *Execution) ProtectVolume(t testingT, volumes ...string) {
135
+	for _, volume := range volumes {
136
+		e.protectedElements.volumes[volume] = struct{}{}
137
+	}
138
+}
139
+
140
+// ProtectVolumes protects existing volumes from being cleaned up at the end of
141
+// test runs
142
+func ProtectVolumes(t testingT, testEnv *Execution) {
143
+	volumes := getExistingVolumes(t, testEnv)
144
+	testEnv.ProtectVolume(t, volumes...)
145
+}
146
+
147
+func getExistingVolumes(t require.TestingT, testEnv *Execution) []string {
148
+	client := testEnv.APIClient()
149
+	volumeList, err := client.VolumeList(context.Background(), filters.Args{})
150
+	require.NoError(t, err, "failed to list volumes")
151
+
152
+	volumes := []string{}
153
+	for _, volume := range volumeList.Volumes {
154
+		volumes = append(volumes, volume.Name)
155
+	}
156
+	return volumes
157
+}