Browse code

Merge pull request #9096 from kargakis/bug-1340735

Merged by openshift-bot

OpenShift Bot authored on 2016/06/03 05:45:25
Showing 3 changed files
... ...
@@ -50,11 +50,11 @@ func (c *ImageChangeController) Handle(stream *imageapi.ImageStream) error {
50 50
 				continue
51 51
 			}
52 52
 
53
-			// All initial deployments (latestVersion == 0) should have their images resolved in order
54
-			// to be able to work and not try to pull non-existent images from DockerHub.
55
-			// Deployments with automatic set to false that have been deployed at least once (latestVersion > 0)
56
-			// shouldn't have their images updated.
57
-			if !params.Automatic && config.Status.LatestVersion != 0 {
53
+			// All initial deployments should have their images resolved in order to
54
+			// be able to work and not try to pull non-existent images from DockerHub.
55
+			// Deployments with automatic set to false that have been deployed at least
56
+			// once shouldn't have their images updated.
57
+			if !params.Automatic && len(params.LastTriggeredImage) > 0 {
58 58
 				continue
59 59
 			}
60 60
 
... ...
@@ -52,6 +52,8 @@ func TestHandle_changeForNonAutomaticTag(t *testing.T) {
52 52
 			config := testapi.OkDeploymentConfig(1)
53 53
 			config.Namespace = kapi.NamespaceDefault
54 54
 			config.Spec.Triggers[0].ImageChangeParams.Automatic = false
55
+			// The image has been resolved at least once before.
56
+			config.Spec.Triggers[0].ImageChangeParams.LastTriggeredImage = testapi.DockerImageReference
55 57
 
56 58
 			return []*deployapi.DeploymentConfig{config}, nil
57 59
 		},
... ...
@@ -137,11 +139,14 @@ func TestHandle_changeForUnregisteredTag(t *testing.T) {
137 137
 // match) properly.
138 138
 func TestHandle_matchScenarios(t *testing.T) {
139 139
 	tests := []struct {
140
+		name string
141
+
140 142
 		param   *deployapi.DeploymentTriggerImageChangeParams
141 143
 		matches bool
142 144
 	}{
143
-		// Update from empty last image ID to a new one with explicit namespaces
144 145
 		{
146
+			name: "automatic=true, initial trigger, explicit namespace",
147
+
145 148
 			param: &deployapi.DeploymentTriggerImageChangeParams{
146 149
 				Automatic:          true,
147 150
 				ContainerNames:     []string{"container1"},
... ...
@@ -150,8 +155,9 @@ func TestHandle_matchScenarios(t *testing.T) {
150 150
 			},
151 151
 			matches: true,
152 152
 		},
153
-		// Update from empty last image ID to a new one with implicit namespaces
154 153
 		{
154
+			name: "automatic=true, initial trigger, implicit namespace",
155
+
155 156
 			param: &deployapi.DeploymentTriggerImageChangeParams{
156 157
 				Automatic:          true,
157 158
 				ContainerNames:     []string{"container1"},
... ...
@@ -160,18 +166,31 @@ func TestHandle_matchScenarios(t *testing.T) {
160 160
 			},
161 161
 			matches: true,
162 162
 		},
163
-		// Update from empty last image ID to a new one, but not marked automatic
164 163
 		{
164
+			name: "automatic=false, initial trigger",
165
+
165 166
 			param: &deployapi.DeploymentTriggerImageChangeParams{
166 167
 				Automatic:          false,
167 168
 				ContainerNames:     []string{"container1"},
168 169
 				From:               kapi.ObjectReference{Namespace: kapi.NamespaceDefault, Name: imageapi.JoinImageStreamTag(testapi.ImageStreamName, imageapi.DefaultImageTag)},
169 170
 				LastTriggeredImage: "",
170 171
 			},
172
+			matches: true,
173
+		},
174
+		{
175
+			name: "(no-op) automatic=false, already triggered",
176
+
177
+			param: &deployapi.DeploymentTriggerImageChangeParams{
178
+				Automatic:          false,
179
+				ContainerNames:     []string{"container1"},
180
+				From:               kapi.ObjectReference{Namespace: kapi.NamespaceDefault, Name: imageapi.JoinImageStreamTag(testapi.ImageStreamName, imageapi.DefaultImageTag)},
181
+				LastTriggeredImage: testapi.DockerImageReference,
182
+			},
171 183
 			matches: false,
172 184
 		},
173
-		// Updated image ID is equal to the last triggered ID
174 185
 		{
186
+			name: "(no-op) automatic=true, image is already deployed",
187
+
175 188
 			param: &deployapi.DeploymentTriggerImageChangeParams{
176 189
 				Automatic:          true,
177 190
 				ContainerNames:     []string{"container1"},
... ...
@@ -180,8 +199,9 @@ func TestHandle_matchScenarios(t *testing.T) {
180 180
 			},
181 181
 			matches: false,
182 182
 		},
183
-		// Trigger stream reference doesn't match
184 183
 		{
184
+			name: "(no-op) trigger doesn't match the stream",
185
+
185 186
 			param: &deployapi.DeploymentTriggerImageChangeParams{
186 187
 				Automatic:          true,
187 188
 				ContainerNames:     []string{"container1"},
... ...
@@ -192,13 +212,13 @@ func TestHandle_matchScenarios(t *testing.T) {
192 192
 		},
193 193
 	}
194 194
 
195
-	for i, test := range tests {
195
+	for _, test := range tests {
196 196
 		updated := false
197 197
 
198 198
 		fake := &testclient.Fake{}
199 199
 		fake.AddReactor("update", "deploymentconfigs", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
200 200
 			if !test.matches {
201
-				t.Fatalf("unexpected deploymentconfig update for scenario %d", i)
201
+				t.Fatal("unexpected deploymentconfig update")
202 202
 			}
203 203
 			updated = true
204 204
 			return true, nil, nil
... ...
@@ -220,15 +240,15 @@ func TestHandle_matchScenarios(t *testing.T) {
220 220
 			client: fake,
221 221
 		}
222 222
 
223
-		t.Logf("running scenario: %d", i)
223
+		t.Logf("running test %q", test.name)
224 224
 		stream := makeStream(testapi.ImageStreamName, imageapi.DefaultImageTag, testapi.DockerImageReference, testapi.ImageID)
225 225
 		if err := controller.Handle(stream); err != nil {
226
-			t.Fatalf("unexpected error for scenario %v: %v", i, err)
226
+			t.Fatalf("unexpected error: %v", err)
227 227
 		}
228 228
 
229 229
 		// assert updates occurred
230 230
 		if test.matches && !updated {
231
-			t.Fatalf("expected update for scenario: %v", test)
231
+			t.Fatal("expected an update")
232 232
 		}
233 233
 	}
234 234
 }
... ...
@@ -5,6 +5,7 @@ package integration
5 5
 import (
6 6
 	"fmt"
7 7
 	"testing"
8
+	"time"
8 9
 
9 10
 	kapi "k8s.io/kubernetes/pkg/api"
10 11
 	kclient "k8s.io/kubernetes/pkg/client/unversioned"
... ...
@@ -114,17 +115,17 @@ func TestTriggers_imageChange(t *testing.T) {
114 114
 
115 115
 	configWatch, err := openshiftProjectAdminClient.DeploymentConfigs(testutil.Namespace()).Watch(kapi.ListOptions{})
116 116
 	if err != nil {
117
-		t.Fatalf("Couldn't subscribe to Deployments %v", err)
117
+		t.Fatalf("Couldn't subscribe to deploymentconfigs %v", err)
118 118
 	}
119 119
 	defer configWatch.Stop()
120 120
 
121 121
 	if imageStream, err = openshiftProjectAdminClient.ImageStreams(testutil.Namespace()).Create(imageStream); err != nil {
122
-		t.Fatalf("Couldn't create ImageStream: %v", err)
122
+		t.Fatalf("Couldn't create imagestream: %v", err)
123 123
 	}
124 124
 
125 125
 	imageWatch, err := openshiftProjectAdminClient.ImageStreams(testutil.Namespace()).Watch(kapi.ListOptions{})
126 126
 	if err != nil {
127
-		t.Fatalf("Couldn't subscribe to ImageStreams: %s", err)
127
+		t.Fatalf("Couldn't subscribe to imagestreams: %v", err)
128 128
 	}
129 129
 	defer imageWatch.Stop()
130 130
 
... ...
@@ -147,29 +148,29 @@ func TestTriggers_imageChange(t *testing.T) {
147 147
 			t.Fatalf("unexpected error: %v", err)
148 148
 		}
149 149
 
150
-		t.Log("Waiting for image stream mapping to be reflected in the IS status...")
150
+		t.Log("Waiting for image stream mapping to be reflected in the image stream status...")
151 151
 	statusLoop:
152 152
 		for {
153 153
 			select {
154 154
 			case event := <-imageWatch.ResultChan():
155 155
 				stream := event.Object.(*imageapi.ImageStream)
156 156
 				if _, ok := stream.Status.Tags[imageapi.DefaultImageTag]; ok {
157
-					t.Logf("ImageStream %s now has Status with tags: %#v", stream.Name, stream.Status.Tags)
157
+					t.Logf("imagestream %q now has status with tags: %#v", stream.Name, stream.Status.Tags)
158 158
 					break statusLoop
159 159
 				}
160
-				t.Logf("Still waiting for latest tag status on ImageStream %s", stream.Name)
160
+				t.Logf("Still waiting for latest tag status on imagestream %q", stream.Name)
161 161
 			}
162 162
 		}
163 163
 	}
164 164
 
165 165
 	if config, err = openshiftProjectAdminClient.DeploymentConfigs(testutil.Namespace()).Create(config); err != nil {
166
-		t.Fatalf("Couldn't create DeploymentConfig: %v", err)
166
+		t.Fatalf("Couldn't create deploymentconfig: %v", err)
167 167
 	}
168 168
 
169 169
 	createTagEvent()
170 170
 
171 171
 	var newConfig *deployapi.DeploymentConfig
172
-	t.Log("Waiting for a new deployment config in response to ImageStream update")
172
+	t.Log("Waiting for a new deployment config in response to imagestream update")
173 173
 waitForNewConfig:
174 174
 	for {
175 175
 		select {
... ...
@@ -184,12 +185,155 @@ waitForNewConfig:
184 184
 					}
185 185
 					break waitForNewConfig
186 186
 				}
187
-				t.Log("Still waiting for a new deployment config in response to ImageStream update")
187
+				t.Log("Still waiting for a new deployment config in response to imagestream update")
188 188
 			}
189 189
 		}
190 190
 	}
191 191
 }
192 192
 
193
+func TestTriggers_imageChange_nonAutomatic(t *testing.T) {
194
+	testutil.RequireEtcd(t)
195
+	_, clusterAdminKubeConfig, err := testserver.StartTestMaster()
196
+	if err != nil {
197
+		t.Fatalf("error starting master: %v", err)
198
+	}
199
+	openshiftClusterAdminClient, err := testutil.GetClusterAdminClient(clusterAdminKubeConfig)
200
+	if err != nil {
201
+		t.Fatalf("error getting cluster admin client: %v", err)
202
+	}
203
+	openshiftClusterAdminClientConfig, err := testutil.GetClusterAdminClientConfig(clusterAdminKubeConfig)
204
+	if err != nil {
205
+		t.Fatalf("error getting cluster admin client config: %v", err)
206
+	}
207
+	openshiftProjectAdminClient, err := testserver.CreateNewProject(openshiftClusterAdminClient, *openshiftClusterAdminClientConfig, testutil.Namespace(), "bob")
208
+	if err != nil {
209
+		t.Fatalf("error creating project: %v", err)
210
+	}
211
+
212
+	imageStream := &imageapi.ImageStream{ObjectMeta: kapi.ObjectMeta{Name: deploytest.ImageStreamName}}
213
+
214
+	if imageStream, err = openshiftProjectAdminClient.ImageStreams(testutil.Namespace()).Create(imageStream); err != nil {
215
+		t.Fatalf("Couldn't create imagestream: %v", err)
216
+	}
217
+
218
+	imageWatch, err := openshiftProjectAdminClient.ImageStreams(testutil.Namespace()).Watch(kapi.ListOptions{})
219
+	if err != nil {
220
+		t.Fatalf("Couldn't subscribe to imagestreams: %v", err)
221
+	}
222
+	defer imageWatch.Stop()
223
+
224
+	image := fmt.Sprintf("sha256:%s", deploytest.ImageID)
225
+	pullSpec := fmt.Sprintf("registry:8080/%s/%s@%s", testutil.Namespace(), deploytest.ImageStreamName, image)
226
+	// Make a function which can create a new tag event for the image stream and
227
+	// then wait for the stream status to be asynchronously updated.
228
+	mapping := &imageapi.ImageStreamMapping{
229
+		ObjectMeta: kapi.ObjectMeta{Name: imageStream.Name},
230
+		Tag:        imageapi.DefaultImageTag,
231
+		Image: imageapi.Image{
232
+			ObjectMeta: kapi.ObjectMeta{
233
+				Name: image,
234
+			},
235
+			DockerImageReference: pullSpec,
236
+		},
237
+	}
238
+	updated := ""
239
+
240
+	createTagEvent := func(mapping *imageapi.ImageStreamMapping) {
241
+		if err := openshiftProjectAdminClient.ImageStreamMappings(testutil.Namespace()).Create(mapping); err != nil {
242
+			t.Fatalf("unexpected error: %v", err)
243
+		}
244
+
245
+		t.Log("Waiting for image stream mapping to be reflected in the image stream status...")
246
+
247
+		for {
248
+			select {
249
+			case event := <-imageWatch.ResultChan():
250
+				stream := event.Object.(*imageapi.ImageStream)
251
+				tagEventList, ok := stream.Status.Tags[imageapi.DefaultImageTag]
252
+				if ok {
253
+					if updated != tagEventList.Items[0].DockerImageReference {
254
+						updated = tagEventList.Items[0].DockerImageReference
255
+						return
256
+					}
257
+				}
258
+				t.Logf("Still waiting for latest tag status update on imagestream %q", stream.Name)
259
+			}
260
+		}
261
+	}
262
+
263
+	configWatch, err := openshiftProjectAdminClient.DeploymentConfigs(testutil.Namespace()).Watch(kapi.ListOptions{})
264
+	if err != nil {
265
+		t.Fatalf("Couldn't subscribe to deploymentconfigs: %v", err)
266
+	}
267
+	defer configWatch.Stop()
268
+
269
+	config := deploytest.OkDeploymentConfig(0)
270
+	config.Namespace = testutil.Namespace()
271
+	config.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{deploytest.OkImageChangeTrigger()}
272
+	config.Spec.Triggers[0].ImageChangeParams.Automatic = false
273
+	if config, err = openshiftProjectAdminClient.DeploymentConfigs(testutil.Namespace()).Create(config); err != nil {
274
+		t.Fatalf("Couldn't create deploymentconfig: %v", err)
275
+	}
276
+
277
+	createTagEvent(mapping)
278
+
279
+	var newConfig *deployapi.DeploymentConfig
280
+	t.Log("Waiting for the initial deploymentconfig update in response to the imagestream update")
281
+
282
+	timeout := time.After(30 * time.Second)
283
+
284
+	// This is the initial deployment with automatic=false in its ICT - it should be updated to pullSpec
285
+out:
286
+	for {
287
+		select {
288
+		case event := <-configWatch.ResultChan():
289
+			if event.Type != watchapi.Modified {
290
+				continue
291
+			}
292
+
293
+			newConfig = event.Object.(*deployapi.DeploymentConfig)
294
+
295
+			if newConfig.Status.LatestVersion > 0 {
296
+				t.Fatalf("unexpected latestVersion update - the config has no config change trigger")
297
+			}
298
+
299
+			if e, a := updated, newConfig.Spec.Template.Spec.Containers[0].Image; e == a {
300
+				break out
301
+			}
302
+		case <-timeout:
303
+			t.Fatalf("timed out waiting for the image update to happen")
304
+		}
305
+	}
306
+
307
+	t.Log("Waiting for the second imagestream update - it shouldn't update the deploymentconfig")
308
+
309
+	// Subsequent updates to the image shouldn't update the pod template image
310
+	mapping.Image.Name = "sha256:thisupdatedimageshouldneverlandinthepodtemplate"
311
+	mapping.Image.DockerImageReference = fmt.Sprintf("registry:8080/%s/%s@%s", testutil.Namespace(), deploytest.ImageStreamName, mapping.Image.Name)
312
+	createTagEvent(mapping)
313
+
314
+	for {
315
+		select {
316
+		case event := <-configWatch.ResultChan():
317
+			if event.Type != watchapi.Modified {
318
+				continue
319
+			}
320
+
321
+			newConfig = event.Object.(*deployapi.DeploymentConfig)
322
+
323
+			if newConfig.Status.LatestVersion > 0 {
324
+				t.Fatalf("unexpected latestVersion update - the config has no config change trigger")
325
+			}
326
+
327
+			if e, a := updated, newConfig.Spec.Template.Spec.Containers[0].Image; e == a {
328
+				t.Fatalf("unexpected image update, expected initial image to be the same")
329
+			}
330
+		case <-timeout:
331
+			return
332
+		}
333
+	}
334
+}
335
+
193 336
 func TestTriggers_configChange(t *testing.T) {
194 337
 	const namespace = "test-triggers-configchange"
195 338