Skip to content

Commit 545fd50

Browse files
author
OpenShift Bot
committed
Merge pull request #9096 from kargakis/bug-1340735
Merged by openshift-bot
2 parents b50c855 + 91ec89c commit 545fd50

File tree

3 files changed

+188
-24
lines changed

3 files changed

+188
-24
lines changed

pkg/deploy/controller/imagechange/controller.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,11 @@ func (c *ImageChangeController) Handle(stream *imageapi.ImageStream) error {
5050
continue
5151
}
5252

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 {
5858
continue
5959
}
6060

pkg/deploy/controller/imagechange/controller_test.go

+30-10
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ func TestHandle_changeForNonAutomaticTag(t *testing.T) {
5252
config := testapi.OkDeploymentConfig(1)
5353
config.Namespace = kapi.NamespaceDefault
5454
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
5557

5658
return []*deployapi.DeploymentConfig{config}, nil
5759
},
@@ -137,11 +139,14 @@ func TestHandle_changeForUnregisteredTag(t *testing.T) {
137139
// match) properly.
138140
func TestHandle_matchScenarios(t *testing.T) {
139141
tests := []struct {
142+
name string
143+
140144
param *deployapi.DeploymentTriggerImageChangeParams
141145
matches bool
142146
}{
143-
// Update from empty last image ID to a new one with explicit namespaces
144147
{
148+
name: "automatic=true, initial trigger, explicit namespace",
149+
145150
param: &deployapi.DeploymentTriggerImageChangeParams{
146151
Automatic: true,
147152
ContainerNames: []string{"container1"},
@@ -150,8 +155,9 @@ func TestHandle_matchScenarios(t *testing.T) {
150155
},
151156
matches: true,
152157
},
153-
// Update from empty last image ID to a new one with implicit namespaces
154158
{
159+
name: "automatic=true, initial trigger, implicit namespace",
160+
155161
param: &deployapi.DeploymentTriggerImageChangeParams{
156162
Automatic: true,
157163
ContainerNames: []string{"container1"},
@@ -160,18 +166,31 @@ func TestHandle_matchScenarios(t *testing.T) {
160166
},
161167
matches: true,
162168
},
163-
// Update from empty last image ID to a new one, but not marked automatic
164169
{
170+
name: "automatic=false, initial trigger",
171+
165172
param: &deployapi.DeploymentTriggerImageChangeParams{
166173
Automatic: false,
167174
ContainerNames: []string{"container1"},
168175
From: kapi.ObjectReference{Namespace: kapi.NamespaceDefault, Name: imageapi.JoinImageStreamTag(testapi.ImageStreamName, imageapi.DefaultImageTag)},
169176
LastTriggeredImage: "",
170177
},
178+
matches: true,
179+
},
180+
{
181+
name: "(no-op) automatic=false, already triggered",
182+
183+
param: &deployapi.DeploymentTriggerImageChangeParams{
184+
Automatic: false,
185+
ContainerNames: []string{"container1"},
186+
From: kapi.ObjectReference{Namespace: kapi.NamespaceDefault, Name: imageapi.JoinImageStreamTag(testapi.ImageStreamName, imageapi.DefaultImageTag)},
187+
LastTriggeredImage: testapi.DockerImageReference,
188+
},
171189
matches: false,
172190
},
173-
// Updated image ID is equal to the last triggered ID
174191
{
192+
name: "(no-op) automatic=true, image is already deployed",
193+
175194
param: &deployapi.DeploymentTriggerImageChangeParams{
176195
Automatic: true,
177196
ContainerNames: []string{"container1"},
@@ -180,8 +199,9 @@ func TestHandle_matchScenarios(t *testing.T) {
180199
},
181200
matches: false,
182201
},
183-
// Trigger stream reference doesn't match
184202
{
203+
name: "(no-op) trigger doesn't match the stream",
204+
185205
param: &deployapi.DeploymentTriggerImageChangeParams{
186206
Automatic: true,
187207
ContainerNames: []string{"container1"},
@@ -192,13 +212,13 @@ func TestHandle_matchScenarios(t *testing.T) {
192212
},
193213
}
194214

195-
for i, test := range tests {
215+
for _, test := range tests {
196216
updated := false
197217

198218
fake := &testclient.Fake{}
199219
fake.AddReactor("update", "deploymentconfigs", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
200220
if !test.matches {
201-
t.Fatalf("unexpected deploymentconfig update for scenario %d", i)
221+
t.Fatal("unexpected deploymentconfig update")
202222
}
203223
updated = true
204224
return true, nil, nil
@@ -220,15 +240,15 @@ func TestHandle_matchScenarios(t *testing.T) {
220240
client: fake,
221241
}
222242

223-
t.Logf("running scenario: %d", i)
243+
t.Logf("running test %q", test.name)
224244
stream := makeStream(testapi.ImageStreamName, imageapi.DefaultImageTag, testapi.DockerImageReference, testapi.ImageID)
225245
if err := controller.Handle(stream); err != nil {
226-
t.Fatalf("unexpected error for scenario %v: %v", i, err)
246+
t.Fatalf("unexpected error: %v", err)
227247
}
228248

229249
// assert updates occurred
230250
if test.matches && !updated {
231-
t.Fatalf("expected update for scenario: %v", test)
251+
t.Fatal("expected an update")
232252
}
233253
}
234254
}

test/integration/deploy_trigger_test.go

+153-9
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package integration
55
import (
66
"fmt"
77
"testing"
8+
"time"
89

910
kapi "k8s.io/kubernetes/pkg/api"
1011
kclient "k8s.io/kubernetes/pkg/client/unversioned"
@@ -114,17 +115,17 @@ func TestTriggers_imageChange(t *testing.T) {
114115

115116
configWatch, err := openshiftProjectAdminClient.DeploymentConfigs(testutil.Namespace()).Watch(kapi.ListOptions{})
116117
if err != nil {
117-
t.Fatalf("Couldn't subscribe to Deployments %v", err)
118+
t.Fatalf("Couldn't subscribe to deploymentconfigs %v", err)
118119
}
119120
defer configWatch.Stop()
120121

121122
if imageStream, err = openshiftProjectAdminClient.ImageStreams(testutil.Namespace()).Create(imageStream); err != nil {
122-
t.Fatalf("Couldn't create ImageStream: %v", err)
123+
t.Fatalf("Couldn't create imagestream: %v", err)
123124
}
124125

125126
imageWatch, err := openshiftProjectAdminClient.ImageStreams(testutil.Namespace()).Watch(kapi.ListOptions{})
126127
if err != nil {
127-
t.Fatalf("Couldn't subscribe to ImageStreams: %s", err)
128+
t.Fatalf("Couldn't subscribe to imagestreams: %v", err)
128129
}
129130
defer imageWatch.Stop()
130131

@@ -147,29 +148,29 @@ func TestTriggers_imageChange(t *testing.T) {
147148
t.Fatalf("unexpected error: %v", err)
148149
}
149150

150-
t.Log("Waiting for image stream mapping to be reflected in the IS status...")
151+
t.Log("Waiting for image stream mapping to be reflected in the image stream status...")
151152
statusLoop:
152153
for {
153154
select {
154155
case event := <-imageWatch.ResultChan():
155156
stream := event.Object.(*imageapi.ImageStream)
156157
if _, ok := stream.Status.Tags[imageapi.DefaultImageTag]; ok {
157-
t.Logf("ImageStream %s now has Status with tags: %#v", stream.Name, stream.Status.Tags)
158+
t.Logf("imagestream %q now has status with tags: %#v", stream.Name, stream.Status.Tags)
158159
break statusLoop
159160
}
160-
t.Logf("Still waiting for latest tag status on ImageStream %s", stream.Name)
161+
t.Logf("Still waiting for latest tag status on imagestream %q", stream.Name)
161162
}
162163
}
163164
}
164165

165166
if config, err = openshiftProjectAdminClient.DeploymentConfigs(testutil.Namespace()).Create(config); err != nil {
166-
t.Fatalf("Couldn't create DeploymentConfig: %v", err)
167+
t.Fatalf("Couldn't create deploymentconfig: %v", err)
167168
}
168169

169170
createTagEvent()
170171

171172
var newConfig *deployapi.DeploymentConfig
172-
t.Log("Waiting for a new deployment config in response to ImageStream update")
173+
t.Log("Waiting for a new deployment config in response to imagestream update")
173174
waitForNewConfig:
174175
for {
175176
select {
@@ -184,12 +185,155 @@ waitForNewConfig:
184185
}
185186
break waitForNewConfig
186187
}
187-
t.Log("Still waiting for a new deployment config in response to ImageStream update")
188+
t.Log("Still waiting for a new deployment config in response to imagestream update")
188189
}
189190
}
190191
}
191192
}
192193

194+
func TestTriggers_imageChange_nonAutomatic(t *testing.T) {
195+
testutil.RequireEtcd(t)
196+
_, clusterAdminKubeConfig, err := testserver.StartTestMaster()
197+
if err != nil {
198+
t.Fatalf("error starting master: %v", err)
199+
}
200+
openshiftClusterAdminClient, err := testutil.GetClusterAdminClient(clusterAdminKubeConfig)
201+
if err != nil {
202+
t.Fatalf("error getting cluster admin client: %v", err)
203+
}
204+
openshiftClusterAdminClientConfig, err := testutil.GetClusterAdminClientConfig(clusterAdminKubeConfig)
205+
if err != nil {
206+
t.Fatalf("error getting cluster admin client config: %v", err)
207+
}
208+
openshiftProjectAdminClient, err := testserver.CreateNewProject(openshiftClusterAdminClient, *openshiftClusterAdminClientConfig, testutil.Namespace(), "bob")
209+
if err != nil {
210+
t.Fatalf("error creating project: %v", err)
211+
}
212+
213+
imageStream := &imageapi.ImageStream{ObjectMeta: kapi.ObjectMeta{Name: deploytest.ImageStreamName}}
214+
215+
if imageStream, err = openshiftProjectAdminClient.ImageStreams(testutil.Namespace()).Create(imageStream); err != nil {
216+
t.Fatalf("Couldn't create imagestream: %v", err)
217+
}
218+
219+
imageWatch, err := openshiftProjectAdminClient.ImageStreams(testutil.Namespace()).Watch(kapi.ListOptions{})
220+
if err != nil {
221+
t.Fatalf("Couldn't subscribe to imagestreams: %v", err)
222+
}
223+
defer imageWatch.Stop()
224+
225+
image := fmt.Sprintf("sha256:%s", deploytest.ImageID)
226+
pullSpec := fmt.Sprintf("registry:8080/%s/%s@%s", testutil.Namespace(), deploytest.ImageStreamName, image)
227+
// Make a function which can create a new tag event for the image stream and
228+
// then wait for the stream status to be asynchronously updated.
229+
mapping := &imageapi.ImageStreamMapping{
230+
ObjectMeta: kapi.ObjectMeta{Name: imageStream.Name},
231+
Tag: imageapi.DefaultImageTag,
232+
Image: imageapi.Image{
233+
ObjectMeta: kapi.ObjectMeta{
234+
Name: image,
235+
},
236+
DockerImageReference: pullSpec,
237+
},
238+
}
239+
updated := ""
240+
241+
createTagEvent := func(mapping *imageapi.ImageStreamMapping) {
242+
if err := openshiftProjectAdminClient.ImageStreamMappings(testutil.Namespace()).Create(mapping); err != nil {
243+
t.Fatalf("unexpected error: %v", err)
244+
}
245+
246+
t.Log("Waiting for image stream mapping to be reflected in the image stream status...")
247+
248+
for {
249+
select {
250+
case event := <-imageWatch.ResultChan():
251+
stream := event.Object.(*imageapi.ImageStream)
252+
tagEventList, ok := stream.Status.Tags[imageapi.DefaultImageTag]
253+
if ok {
254+
if updated != tagEventList.Items[0].DockerImageReference {
255+
updated = tagEventList.Items[0].DockerImageReference
256+
return
257+
}
258+
}
259+
t.Logf("Still waiting for latest tag status update on imagestream %q", stream.Name)
260+
}
261+
}
262+
}
263+
264+
configWatch, err := openshiftProjectAdminClient.DeploymentConfigs(testutil.Namespace()).Watch(kapi.ListOptions{})
265+
if err != nil {
266+
t.Fatalf("Couldn't subscribe to deploymentconfigs: %v", err)
267+
}
268+
defer configWatch.Stop()
269+
270+
config := deploytest.OkDeploymentConfig(0)
271+
config.Namespace = testutil.Namespace()
272+
config.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{deploytest.OkImageChangeTrigger()}
273+
config.Spec.Triggers[0].ImageChangeParams.Automatic = false
274+
if config, err = openshiftProjectAdminClient.DeploymentConfigs(testutil.Namespace()).Create(config); err != nil {
275+
t.Fatalf("Couldn't create deploymentconfig: %v", err)
276+
}
277+
278+
createTagEvent(mapping)
279+
280+
var newConfig *deployapi.DeploymentConfig
281+
t.Log("Waiting for the initial deploymentconfig update in response to the imagestream update")
282+
283+
timeout := time.After(30 * time.Second)
284+
285+
// This is the initial deployment with automatic=false in its ICT - it should be updated to pullSpec
286+
out:
287+
for {
288+
select {
289+
case event := <-configWatch.ResultChan():
290+
if event.Type != watchapi.Modified {
291+
continue
292+
}
293+
294+
newConfig = event.Object.(*deployapi.DeploymentConfig)
295+
296+
if newConfig.Status.LatestVersion > 0 {
297+
t.Fatalf("unexpected latestVersion update - the config has no config change trigger")
298+
}
299+
300+
if e, a := updated, newConfig.Spec.Template.Spec.Containers[0].Image; e == a {
301+
break out
302+
}
303+
case <-timeout:
304+
t.Fatalf("timed out waiting for the image update to happen")
305+
}
306+
}
307+
308+
t.Log("Waiting for the second imagestream update - it shouldn't update the deploymentconfig")
309+
310+
// Subsequent updates to the image shouldn't update the pod template image
311+
mapping.Image.Name = "sha256:thisupdatedimageshouldneverlandinthepodtemplate"
312+
mapping.Image.DockerImageReference = fmt.Sprintf("registry:8080/%s/%s@%s", testutil.Namespace(), deploytest.ImageStreamName, mapping.Image.Name)
313+
createTagEvent(mapping)
314+
315+
for {
316+
select {
317+
case event := <-configWatch.ResultChan():
318+
if event.Type != watchapi.Modified {
319+
continue
320+
}
321+
322+
newConfig = event.Object.(*deployapi.DeploymentConfig)
323+
324+
if newConfig.Status.LatestVersion > 0 {
325+
t.Fatalf("unexpected latestVersion update - the config has no config change trigger")
326+
}
327+
328+
if e, a := updated, newConfig.Spec.Template.Spec.Containers[0].Image; e == a {
329+
t.Fatalf("unexpected image update, expected initial image to be the same")
330+
}
331+
case <-timeout:
332+
return
333+
}
334+
}
335+
}
336+
193337
func TestTriggers_configChange(t *testing.T) {
194338
const namespace = "test-triggers-configchange"
195339

0 commit comments

Comments
 (0)