Browse code

Fix build image change race

The build image change controller was performing the following logic
once it determined a build was needed:

1. Bump the BuildConfig so the ResourceVersion would be updated, in
theory to prevent other image change controllers from being able to
trigger a build for the same BuildConfig revision.
2. Make an API call to instantiate a build (BuildGenerator)
3. The BuildGenerator would try to modify the BuildConfig's LastVersion
4. The BuildGenerator would try to create a Build
5. The image change controller would try to update the BuildConfig to
set the new LastTriggeredImageID value.

If another instance of an image change controller bumped the
BuildConfig's ResourceVersion before 3 above, you could get into an
infinite race loop where 1 controller would keep bumping the
ResourceVersion just before the BuildGenerator tried to update the
config's LastVersion.

This change makes it so the BuildGenerator is the only thing responsible
for both creating a Build and updating the BuildConfig. The Build is
created prior to updating the BuildConfig. If the Build creation fails,
it won't try to update the BuildConfig.

BuildRequest gains a new required field (Image) that the image change
controller sets to tell the BuildGenerator what value to set for
LastTriggeredImageID.

Andy Goldstein authored on 2015/05/29 02:42:58
Showing 10 changed files
... ...
@@ -406,6 +406,9 @@ type BuildRequest struct {
406 406
 
407 407
 	// Revision is the information from the source for a specific repo snapshot.
408 408
 	Revision *SourceRevision `json:"revision,omitempty"`
409
+
410
+	// Image is the image that triggered this build.
411
+	Image string
409 412
 }
410 413
 
411 414
 // BuildLogOptions is the REST options for a build log
... ...
@@ -390,6 +390,9 @@ type BuildRequest struct {
390 390
 
391 391
 	// Revision is the information from the source for a specific repo snapshot.
392 392
 	Revision *SourceRevision `json:"revision,omitempty"`
393
+
394
+	// Image is the image that triggered this build.
395
+	Image string `json:"image,omitempty"`
393 396
 }
394 397
 
395 398
 // BuildLogOptions is the REST options for a build log
... ...
@@ -455,6 +455,9 @@ type BuildRequest struct {
455 455
 
456 456
 	// Revision is the information from the source for a specific repo snapshot.
457 457
 	Revision *SourceRevision `json:"revision,omitempty"`
458
+
459
+	// Image is the image that triggered this build.
460
+	Image string `json:"image,omitempty"`
458 461
 }
459 462
 
460 463
 // BuildLogOptions is the REST options for a build log
... ...
@@ -390,6 +390,9 @@ type BuildRequest struct {
390 390
 
391 391
 	// Revision is the information from the source for a specific repo snapshot.
392 392
 	Revision *SourceRevision `json:"revision,omitempty"`
393
+
394
+	// Image is the image that triggered this build.
395
+	Image string `json:"image,omitempty"`
393 396
 }
394 397
 
395 398
 // BuildLogOptions is the REST options for a build log
... ...
@@ -205,7 +205,6 @@ func (factory *BuildPodControllerFactory) CreateDeleteController() controller.Ru
205 205
 type ImageChangeControllerFactory struct {
206 206
 	Client                  osclient.Interface
207 207
 	BuildConfigInstantiator buildclient.BuildConfigInstantiator
208
-	BuildConfigUpdater      buildclient.BuildConfigUpdater
209 208
 	// Stop may be set to allow controllers created by this factory to be terminated.
210 209
 	Stop <-chan struct{}
211 210
 }
... ...
@@ -221,7 +220,6 @@ func (factory *ImageChangeControllerFactory) Create() controller.RunnableControl
221 221
 
222 222
 	imageChangeController := &buildcontroller.ImageChangeController{
223 223
 		BuildConfigStore:        store,
224
-		BuildConfigUpdater:      factory.BuildConfigUpdater,
225 224
 		BuildConfigInstantiator: factory.BuildConfigInstantiator,
226 225
 		Stop: factory.Stop,
227 226
 	}
... ...
@@ -4,6 +4,7 @@ import (
4 4
 	"fmt"
5 5
 	"strings"
6 6
 
7
+	kerrors "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
7 8
 	"github.com/golang/glog"
8 9
 
9 10
 	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
... ...
@@ -32,7 +33,6 @@ func (e ImageChangeControllerFatalError) Error() string {
32 32
 type ImageChangeController struct {
33 33
 	BuildConfigStore        cache.Store
34 34
 	BuildConfigInstantiator buildclient.BuildConfigInstantiator
35
-	BuildConfigUpdater      buildclient.BuildConfigUpdater
36 35
 	// Stop is an optional channel that controls when the controller exits
37 36
 	Stop <-chan struct{}
38 37
 }
... ...
@@ -51,11 +51,6 @@ func (c *ImageChangeController) HandleImageRepo(repo *imageapi.ImageStream) erro
51 51
 	// TODO: this is inefficient
52 52
 	for _, bc := range c.BuildConfigStore.List() {
53 53
 		config := bc.(*buildapi.BuildConfig)
54
-		obj, err := kapi.Scheme.Copy(config)
55
-		if err != nil {
56
-			continue
57
-		}
58
-		originalConfig := obj.(*buildapi.BuildConfig)
59 54
 
60 55
 		from := buildutil.GetImageStreamForStrategy(config.Parameters.Strategy)
61 56
 		if from == nil || from.Kind != "ImageStreamTag" {
... ...
@@ -63,6 +58,7 @@ func (c *ImageChangeController) HandleImageRepo(repo *imageapi.ImageStream) erro
63 63
 		}
64 64
 
65 65
 		shouldBuild := false
66
+		triggeredImage := ""
66 67
 		// For every ImageChange trigger find the latest tagged image from the image repository and replace that value
67 68
 		// throughout the build strategies. A new build is triggered only if the latest tagged image id or pull spec
68 69
 		// differs from the last triggered build recorded on the build config.
... ...
@@ -99,68 +95,37 @@ func (c *ImageChangeController) HandleImageRepo(repo *imageapi.ImageStream) erro
99 99
 			next := latest.DockerImageReference
100 100
 
101 101
 			if len(last) == 0 || (len(next) > 0 && next != last) {
102
-				trigger.ImageChange.LastTriggeredImageID = next
102
+				triggeredImage = next
103 103
 				shouldBuild = true
104
+				// it doesn't really make sense to have multiple image change triggers any more,
105
+				// so just exit the loop now
106
+				break
104 107
 			}
105 108
 		}
106 109
 
107 110
 		if shouldBuild {
108
-			// The following update is meant to reduce the chance that the image change controller
109
-			// will kick off multiple builds on an image change in a HA setup, where multiple controllers
110
-			// of the same type may be looking at the same etcd data.
111
-			// If multiple controllers read the same build config (with same ResourceVersion) above and
112
-			// make a determination that a build needs to be kicked off, the update will only allow one of
113
-			// those controllers to continue to launch the build, while the rest will return an error and
114
-			// reset their queue. This won't eliminate the chance of multiple builds, since another controller
115
-			// can read the build after this update and launch its own build.
116
-			// TODO: Find a better mechanism to synchronize in a HA setup.
117
-			if err := c.BuildConfigUpdater.Update(originalConfig); err != nil {
118
-				// Cannot make an update to the original build config. Likely it has been changed by another process
119
-				glog.V(4).Infof("Cannot update BuildConfig %s/%s when preparing to update LastTriggeredImageID: %v", config.Namespace, config.Name, err)
120
-				return err
121
-			}
122
-
123 111
 			glog.V(4).Infof("Running build for BuildConfig %s/%s", config.Namespace, config.Name)
124 112
 			// instantiate new build
125
-			request := &buildapi.BuildRequest{ObjectMeta: kapi.ObjectMeta{Name: config.Name}}
126
-			if _, err := c.BuildConfigInstantiator.Instantiate(config.Namespace, request); err != nil {
127
-				return fmt.Errorf("error instantiating Build from BuildConfig %s/%s: %v", config.Namespace, config.Name, err)
113
+			request := &buildapi.BuildRequest{
114
+				ObjectMeta: kapi.ObjectMeta{
115
+					Name: config.Name,
116
+				},
117
+				Image: triggeredImage,
128 118
 			}
129
-			// and update the config
130
-			if err := c.updateConfig(config); err != nil {
131
-				// This is not a retryable error. The worst case outcome of not updating the buildconfig
132
-				// is that we might rerun a build for the same "new" imageid change in the future,
133
-				// which is better than guaranteeing we run the build 2+ times by retrying it here.
134
-				return ImageChangeControllerFatalError{
135
-					Reason: fmt.Sprintf("error updating BuildConfig %s/%s with new LastTriggeredImageID", config.Namespace, config.Name),
136
-					Err:    err,
119
+			if _, err := c.BuildConfigInstantiator.Instantiate(config.Namespace, request); err != nil {
120
+				if kerrors.IsConflict(err) {
121
+					// This is not a retryable error. The worst case outcome of not updating the buildconfig
122
+					// is that we might rerun a build for the same "new" imageid change in the future,
123
+					// which is better than guaranteeing we run the build 2+ times by retrying it here.
124
+					return ImageChangeControllerFatalError{
125
+						Reason: fmt.Sprintf("unable to instantiate Build for BuildConfig %s/%s due to a conflicting update: %v", config.Namespace, config.Name, err),
126
+						Err:    err,
127
+					}
137 128
 				}
129
+
130
+				return fmt.Errorf("error instantiating Build from BuildConfig %s/%s: %v", config.Namespace, config.Name, err)
138 131
 			}
139 132
 		}
140 133
 	}
141 134
 	return nil
142 135
 }
143
-
144
-// updateConfig is responsible for updating current BuildConfig object which was changed
145
-// during instantiate call, it basically copies LastTriggeredImageID to fresh copy
146
-// of the BuildConfig object
147
-func (c *ImageChangeController) updateConfig(config *buildapi.BuildConfig) error {
148
-	item, _, err := c.BuildConfigStore.Get(config)
149
-	if err != nil {
150
-		return err
151
-	}
152
-	if item == nil {
153
-		return fmt.Errorf("unable to retrieve BuildConfig %s/%s for updating", config.Namespace, config.Name)
154
-	}
155
-	newConfig := item.(*buildapi.BuildConfig)
156
-	for i, trigger := range newConfig.Triggers {
157
-		if trigger.Type != buildapi.ImageChangeBuildTriggerType {
158
-			continue
159
-		}
160
-		change := trigger.ImageChange
161
-		change.LastTriggeredImageID = config.Triggers[i].ImageChange.LastTriggeredImageID
162
-	}
163
-	glog.V(4).Infof("BuildConfig %s/%s is about to be updated", config.Namespace, config.Name)
164
-
165
-	return c.BuildConfigUpdater.Update(newConfig)
166
-}
... ...
@@ -1,11 +1,13 @@
1 1
 package controller
2 2
 
3 3
 import (
4
+	"errors"
4 5
 	"fmt"
5 6
 	"strings"
6 7
 	"testing"
7 8
 
8 9
 	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
10
+	kerrors "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
9 11
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/testclient"
10 12
 
11 13
 	buildapi "github.com/openshift/origin/pkg/build/api"
... ...
@@ -22,7 +24,7 @@ func TestNewImageID(t *testing.T) {
22 22
 	image := mockImage("testImage@id", "registry.com/namespace/imagename:newImageID123")
23 23
 	controller := mockImageChangeController(buildcfg, imageStream, image)
24 24
 	bcInstantiator := controller.BuildConfigInstantiator.(*buildConfigInstantiator)
25
-	bcUpdater := controller.BuildConfigUpdater.(*mockBuildConfigUpdater)
25
+	bcUpdater := bcInstantiator.buildConfigUpdater
26 26
 
27 27
 	err := controller.HandleImageRepo(imageStream)
28 28
 	if err != nil {
... ...
@@ -50,7 +52,7 @@ func TestNewImageIDDefaultTag(t *testing.T) {
50 50
 	image := mockImage("testImage@id", "registry.com/namespace/imagename:newImageID123")
51 51
 	controller := mockImageChangeController(buildcfg, imageStream, image)
52 52
 	bcInstantiator := controller.BuildConfigInstantiator.(*buildConfigInstantiator)
53
-	bcUpdater := controller.BuildConfigUpdater.(*mockBuildConfigUpdater)
53
+	bcUpdater := bcInstantiator.buildConfigUpdater
54 54
 
55 55
 	err := controller.HandleImageRepo(imageStream)
56 56
 	if err != nil {
... ...
@@ -78,7 +80,7 @@ func TestNonExistentImageStream(t *testing.T) {
78 78
 	image := mockImage("testImage@id", "registry.com/namespace/imagename@id")
79 79
 	controller := mockImageChangeController(buildcfg, imageStream, image)
80 80
 	bcInstantiator := controller.BuildConfigInstantiator.(*buildConfigInstantiator)
81
-	bcUpdater := controller.BuildConfigUpdater.(*mockBuildConfigUpdater)
81
+	bcUpdater := bcInstantiator.buildConfigUpdater
82 82
 
83 83
 	err := controller.HandleImageRepo(imageStream)
84 84
 	if err != nil {
... ...
@@ -99,7 +101,7 @@ func TestNewImageDifferentTagUpdate(t *testing.T) {
99 99
 	image := mockImage("testImage@id", "registry.com/namespace/imagename@id")
100 100
 	controller := mockImageChangeController(buildcfg, imageStream, image)
101 101
 	bcInstantiator := controller.BuildConfigInstantiator.(*buildConfigInstantiator)
102
-	bcUpdater := controller.BuildConfigUpdater.(*mockBuildConfigUpdater)
102
+	bcUpdater := bcInstantiator.buildConfigUpdater
103 103
 
104 104
 	err := controller.HandleImageRepo(imageStream)
105 105
 	if err != nil {
... ...
@@ -122,7 +124,7 @@ func TestNewImageDifferentTagUpdate2(t *testing.T) {
122 122
 	image := mockImage("testImage@id", "registry.com/namespace/imagename@id")
123 123
 	controller := mockImageChangeController(buildcfg, imageStream, image)
124 124
 	bcInstantiator := controller.BuildConfigInstantiator.(*buildConfigInstantiator)
125
-	bcUpdater := controller.BuildConfigUpdater.(*mockBuildConfigUpdater)
125
+	bcUpdater := bcInstantiator.buildConfigUpdater
126 126
 
127 127
 	err := controller.HandleImageRepo(imageStream)
128 128
 	if err != nil {
... ...
@@ -143,7 +145,7 @@ func TestNewDifferentImageUpdate(t *testing.T) {
143 143
 	image := mockImage("testImage@id", "registry.com/namespace/imagename@id")
144 144
 	controller := mockImageChangeController(buildcfg, imageStream, image)
145 145
 	bcInstantiator := controller.BuildConfigInstantiator.(*buildConfigInstantiator)
146
-	bcUpdater := controller.BuildConfigUpdater.(*mockBuildConfigUpdater)
146
+	bcUpdater := bcInstantiator.buildConfigUpdater
147 147
 
148 148
 	err := controller.HandleImageRepo(imageStream)
149 149
 	if err != nil {
... ...
@@ -166,7 +168,7 @@ func TestSameStreamNameDifferentNamespaces(t *testing.T) {
166 166
 	image := mockImage("testImage@id", "registry.com/namespace/imagename@id")
167 167
 	controller := mockImageChangeController(buildcfg, imageStream, image)
168 168
 	bcInstantiator := controller.BuildConfigInstantiator.(*buildConfigInstantiator)
169
-	bcUpdater := controller.BuildConfigUpdater.(*mockBuildConfigUpdater)
169
+	bcUpdater := bcInstantiator.buildConfigUpdater
170 170
 
171 171
 	err := controller.HandleImageRepo(imageStream)
172 172
 	if err != nil {
... ...
@@ -188,7 +190,7 @@ func TestBuildConfigWithDifferentTriggerType(t *testing.T) {
188 188
 	image := mockImage("testImage@id", "registry.com/namespace/imagename@id")
189 189
 	controller := mockImageChangeController(buildcfg, imageStream, image)
190 190
 	bcInstantiator := controller.BuildConfigInstantiator.(*buildConfigInstantiator)
191
-	bcUpdater := controller.BuildConfigUpdater.(*mockBuildConfigUpdater)
191
+	bcUpdater := bcInstantiator.buildConfigUpdater
192 192
 
193 193
 	err := controller.HandleImageRepo(imageStream)
194 194
 	if err != nil {
... ...
@@ -211,7 +213,7 @@ func TestNoImageIDChange(t *testing.T) {
211 211
 	image := mockImage("testImage@id", "registry.com/namespace/imagename@id")
212 212
 	controller := mockImageChangeController(buildcfg, imageStream, image)
213 213
 	bcInstantiator := controller.BuildConfigInstantiator.(*buildConfigInstantiator)
214
-	bcUpdater := controller.BuildConfigUpdater.(*mockBuildConfigUpdater)
214
+	bcUpdater := bcInstantiator.buildConfigUpdater
215 215
 
216 216
 	err := controller.HandleImageRepo(imageStream)
217 217
 	if err != nil {
... ...
@@ -233,7 +235,7 @@ func TestBuildConfigInstantiatorError(t *testing.T) {
233 233
 	controller := mockImageChangeController(buildcfg, imageStream, image)
234 234
 	bcInstantiator := controller.BuildConfigInstantiator.(*buildConfigInstantiator)
235 235
 	bcInstantiator.err = fmt.Errorf("instantiating error")
236
-	bcUpdater := controller.BuildConfigUpdater.(*mockBuildConfigUpdater)
236
+	bcUpdater := bcInstantiator.buildConfigUpdater
237 237
 
238 238
 	err := controller.HandleImageRepo(imageStream)
239 239
 	if err == nil || !strings.Contains(err.Error(), "instantiating error") {
... ...
@@ -254,9 +256,8 @@ func TestBuildConfigUpdateError(t *testing.T) {
254 254
 	image := mockImage("testImage@id", "registry.com/namespace/imagename@id")
255 255
 	controller := mockImageChangeController(buildcfg, imageStream, image)
256 256
 	bcInstantiator := controller.BuildConfigInstantiator.(*buildConfigInstantiator)
257
-	bcUpdater := controller.BuildConfigUpdater.(*mockBuildConfigUpdater)
258
-	bcUpdater.err = fmt.Errorf("error")
259
-	bcUpdater.errUpdateCount = 2
257
+	bcUpdater := bcInstantiator.buildConfigUpdater
258
+	bcUpdater.err = kerrors.NewConflict("BuildConfig", buildcfg.Name, errors.New("foo"))
260 259
 
261 260
 	err := controller.HandleImageRepo(imageStream)
262 261
 	if len(bcInstantiator.name) == 0 {
... ...
@@ -274,7 +275,7 @@ func TestNewImageIDNoDockerRepo(t *testing.T) {
274 274
 	image := mockImage("testImage@id", "registry.com/namespace/imagename@id")
275 275
 	controller := mockImageChangeController(buildcfg, imageStream, image)
276 276
 	bcInstantiator := controller.BuildConfigInstantiator.(*buildConfigInstantiator)
277
-	bcUpdater := controller.BuildConfigUpdater.(*mockBuildConfigUpdater)
277
+	bcUpdater := bcInstantiator.buildConfigUpdater
278 278
 
279 279
 	err := controller.HandleImageRepo(imageStream)
280 280
 	if err != nil {
... ...
@@ -289,21 +290,14 @@ func TestNewImageIDNoDockerRepo(t *testing.T) {
289 289
 }
290 290
 
291 291
 type mockBuildConfigUpdater struct {
292
-	updateCount    int
293
-	buildcfg       *buildapi.BuildConfig
294
-	err            error
295
-	errUpdateCount int
292
+	updateCount int
293
+	buildcfg    *buildapi.BuildConfig
294
+	err         error
296 295
 }
297 296
 
298 297
 func (m *mockBuildConfigUpdater) Update(buildcfg *buildapi.BuildConfig) error {
299 298
 	m.buildcfg = buildcfg
300 299
 	m.updateCount++
301
-	if m.errUpdateCount > 0 {
302
-		if m.updateCount == m.errUpdateCount {
303
-			return m.err
304
-		}
305
-		return nil
306
-	}
307 300
 	return m.err
308 301
 }
309 302
 
... ...
@@ -366,10 +360,11 @@ func mockImage(name, dockerSpec string) *imageapi.Image {
366 366
 }
367 367
 
368 368
 type buildConfigInstantiator struct {
369
-	generator buildgenerator.BuildGenerator
370
-	name      string
371
-	newBuild  *buildapi.Build
372
-	err       error
369
+	generator          buildgenerator.BuildGenerator
370
+	buildConfigUpdater *mockBuildConfigUpdater
371
+	name               string
372
+	newBuild           *buildapi.Build
373
+	err                error
373 374
 }
374 375
 
375 376
 func (i *buildConfigInstantiator) Instantiate(namespace string, request *buildapi.BuildRequest) (*buildapi.Build, error) {
... ...
@@ -383,6 +378,7 @@ func mockBuildConfigInstantiator(buildcfg *buildapi.BuildConfig, imageStream *im
383 383
 		Secrets:    []kapi.ObjectReference{},
384 384
 	}
385 385
 	instantiator := &buildConfigInstantiator{}
386
+	instantiator.buildConfigUpdater = &mockBuildConfigUpdater{}
386 387
 	generator := buildgenerator.BuildGenerator{
387 388
 		Secrets:         testclient.NewSimpleFake(),
388 389
 		ServiceAccounts: testclient.NewSimpleFake(&builderAccount),
... ...
@@ -391,7 +387,7 @@ func mockBuildConfigInstantiator(buildcfg *buildapi.BuildConfig, imageStream *im
391 391
 				return buildcfg, nil
392 392
 			},
393 393
 			UpdateBuildConfigFunc: func(ctx kapi.Context, buildConfig *buildapi.BuildConfig) error {
394
-				return nil
394
+				return instantiator.buildConfigUpdater.Update(buildConfig)
395 395
 			},
396 396
 			CreateBuildFunc: func(ctx kapi.Context, build *buildapi.Build) error {
397 397
 				instantiator.newBuild = build
... ...
@@ -418,6 +414,5 @@ func mockImageChangeController(buildcfg *buildapi.BuildConfig, imageStream *imag
418 418
 	return &ImageChangeController{
419 419
 		BuildConfigStore:        buildtest.NewFakeBuildConfigStore(buildcfg),
420 420
 		BuildConfigInstantiator: mockBuildConfigInstantiator(buildcfg, imageStream, image),
421
-		BuildConfigUpdater:      &mockBuildConfigUpdater{},
422 421
 	}
423 422
 }
... ...
@@ -127,8 +127,29 @@ func (g *BuildGenerator) Instantiate(ctx kapi.Context, request *buildapi.BuildRe
127 127
 	if err != nil {
128 128
 		return nil, err
129 129
 	}
130
+
130 131
 	glog.V(4).Infof("Build %s/%s has been generated from %s/%s BuildConfig", newBuild.Namespace, newBuild.ObjectMeta.Name, bc.Namespace, bc.ObjectMeta.Name)
131
-	return g.createBuild(ctx, newBuild)
132
+	updatedBuild, err := g.createBuild(ctx, newBuild)
133
+	if err != nil {
134
+		return nil, err
135
+	}
136
+
137
+	if len(request.Image) > 0 {
138
+		for _, trigger := range bc.Triggers {
139
+			if trigger.Type != buildapi.ImageChangeBuildTriggerType {
140
+				continue
141
+			}
142
+
143
+			trigger.ImageChange.LastTriggeredImageID = request.Image
144
+		}
145
+	}
146
+
147
+	// need to update the BuildConfig because LastVersion and possibly LastTriggeredImageID changed
148
+	if err := g.Client.UpdateBuildConfig(ctx, bc); err != nil {
149
+		return nil, err
150
+	}
151
+
152
+	return updatedBuild, nil
132 153
 }
133 154
 
134 155
 // Clone returns clone of a Build
... ...
@@ -162,10 +183,6 @@ func (g *BuildGenerator) createBuild(ctx kapi.Context, build *buildapi.Build) (*
162 162
 // the Strategy, or uses the Image field of the Strategy.
163 163
 // Takes a BuildConfig to base the build on, and an optional SourceRevision to build.
164 164
 func (g *BuildGenerator) generateBuildFromConfig(ctx kapi.Context, bc *buildapi.BuildConfig, revision *buildapi.SourceRevision) (*buildapi.Build, error) {
165
-	builderSecrets, err := g.FetchServiceAccountSecrets(bc.Namespace)
166
-	if err != nil {
167
-		return nil, err
168
-	}
169 165
 	// Need to copy the buildConfig here so that it doesn't share pointers with
170 166
 	// the build object which could be (will be) modified later.
171 167
 	obj, _ := kapi.Scheme.Copy(bc)
... ...
@@ -187,14 +204,15 @@ func (g *BuildGenerator) generateBuildFromConfig(ctx kapi.Context, bc *buildapi.
187 187
 
188 188
 	build.Config = &kapi.ObjectReference{Kind: "BuildConfig", Name: bc.Name, Namespace: bc.Namespace}
189 189
 	build.Name = getNextBuildName(bc)
190
-	if err := g.Client.UpdateBuildConfig(ctx, bc); err != nil {
191
-		return nil, err
192
-	}
193 190
 	if build.Labels == nil {
194 191
 		build.Labels = make(map[string]string)
195 192
 	}
196 193
 	build.Labels[buildapi.BuildConfigLabel] = bcCopy.Name
197 194
 
195
+	builderSecrets, err := g.FetchServiceAccountSecrets(bc.Namespace)
196
+	if err != nil {
197
+		return nil, err
198
+	}
198 199
 	if build.Parameters.Output.PushSecret == nil {
199 200
 		build.Parameters.Output.PushSecret = g.resolveImageSecret(ctx, builderSecrets, build.Parameters.Output.To, bc.Namespace)
200 201
 	}
... ...
@@ -57,6 +57,14 @@ func TestInstantiate(t *testing.T) {
57 57
 	}
58 58
 }
59 59
 
60
+// agoldste: I'm not sure the intent of this test. Using the previous logic for
61
+// the generator, which would try to update the build config before creating
62
+// the build, I can see why the UpdateBuildConfigFunc is set up to return an
63
+// error, but nothing is checking the value of instantiationCalls. We could
64
+// update this test to fail sooner, when the build is created, but that's
65
+// already handled by TestCreateBuildCreateError. We may just want to delete
66
+// this test.
67
+/*
60 68
 func TestInstantiateRetry(t *testing.T) {
61 69
 	instantiationCalls := 0
62 70
 	fakeSecrets := []runtime.Object{}
... ...
@@ -80,8 +88,8 @@ func TestInstantiateRetry(t *testing.T) {
80 80
 	if err == nil || !strings.Contains(err.Error(), "update-error") {
81 81
 		t.Errorf("Expected update-error, got different %v", err)
82 82
 	}
83
-
84 83
 }
84
+*/
85 85
 
86 86
 func TestInstantiateGetBuildConfigError(t *testing.T) {
87 87
 	generator := BuildGenerator{Client: Client{
... ...
@@ -859,9 +859,8 @@ func (c *MasterConfig) RunBuildPodController() {
859 859
 // RunBuildImageChangeTriggerController starts the build image change trigger controller process.
860 860
 func (c *MasterConfig) RunBuildImageChangeTriggerController() {
861 861
 	bcClient, _ := c.BuildControllerClients()
862
-	bcUpdater := buildclient.NewOSClientBuildConfigClient(bcClient)
863 862
 	bcInstantiator := buildclient.NewOSClientBuildConfigInstantiatorClient(bcClient)
864
-	factory := buildcontrollerfactory.ImageChangeControllerFactory{Client: bcClient, BuildConfigInstantiator: bcInstantiator, BuildConfigUpdater: bcUpdater}
863
+	factory := buildcontrollerfactory.ImageChangeControllerFactory{Client: bcClient, BuildConfigInstantiator: bcInstantiator}
865 864
 	factory.Create().Run()
866 865
 }
867 866