Skip to content

Commit 38ea59d

Browse files
author
OpenShift Bot
committed
Merge pull request #2215 from csrwng/build_controller_ha
Merged by openshift-bot
2 parents 5ffd127 + d612d85 commit 38ea59d

File tree

3 files changed

+521
-3
lines changed

3 files changed

+521
-3
lines changed

pkg/build/controller/image_change_controller.go

+21
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ func (c *ImageChangeController) HandleImageRepo(repo *imageapi.ImageStream) erro
5151
// TODO: this is inefficient
5252
for _, bc := range c.BuildConfigStore.List() {
5353
config := bc.(*buildapi.BuildConfig)
54+
obj, err := kapi.Scheme.Copy(config)
55+
if err != nil {
56+
continue
57+
}
58+
originalConfig := obj.(*buildapi.BuildConfig)
59+
5460
from := buildutil.GetImageStreamForStrategy(config)
5561
if from == nil || from.Kind != "ImageStreamTag" {
5662
continue
@@ -98,6 +104,21 @@ func (c *ImageChangeController) HandleImageRepo(repo *imageapi.ImageStream) erro
98104
}
99105

100106
if shouldBuild {
107+
// The following update is meant to reduce the chance that the image change controller
108+
// will kick off multiple builds on an image change in a HA setup, where multiple controllers
109+
// of the same type may be looking at the same etcd data.
110+
// If multiple controllers read the same build config (with same ResourceVersion) above and
111+
// make a determination that a build needs to be kicked off, the update will only allow one of
112+
// those controllers to continue to launch the build, while the rest will return an error and
113+
// reset their queue. This won't eliminate the chance of multiple builds, since another controller
114+
// can read the build after this update and launch its own build.
115+
// TODO: Find a better mechanism to synchronize in a HA setup.
116+
if err := c.BuildConfigUpdater.Update(originalConfig); err != nil {
117+
// Cannot make an update to the original build config. Likely it has been changed by another process
118+
glog.V(4).Infof("Cannot update build config %s when preparing to update LastTriggeredImageID: %v", config.Name, err)
119+
return err
120+
}
121+
101122
glog.V(4).Infof("Running build for buildConfig %s in namespace %s", config.Name, config.Namespace)
102123
// instantiate new build
103124
request := &buildapi.BuildRequest{ObjectMeta: kapi.ObjectMeta{Name: config.Name}}

pkg/build/controller/image_change_controller_test.go

+13-3
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ func TestBuildConfigInstantiatorError(t *testing.T) {
240240
if actual, expected := bcInstantiator.newBuild.Parameters.Strategy.DockerStrategy.From.Name, "registry.com/namespace/imagename:newImageID123"; actual != expected {
241241
t.Errorf("Image substitutions not properly setup for new build. Expected %s, got %s |", expected, actual)
242242
}
243-
if bcUpdater.buildcfg != nil {
243+
if bcUpdater.updateCount > 1 {
244244
t.Fatal("Expected no buildConfig update on BuildCreate error!")
245245
}
246246
}
@@ -254,6 +254,7 @@ func TestBuildConfigUpdateError(t *testing.T) {
254254
bcInstantiator := controller.BuildConfigInstantiator.(*buildConfigInstantiator)
255255
bcUpdater := controller.BuildConfigUpdater.(*mockBuildConfigUpdater)
256256
bcUpdater.err = fmt.Errorf("error")
257+
bcUpdater.errUpdateCount = 2
257258

258259
err := controller.HandleImageRepo(imageStream)
259260
if len(bcInstantiator.name) == 0 {
@@ -286,12 +287,21 @@ func TestNewImageIDNoDockerRepo(t *testing.T) {
286287
}
287288

288289
type mockBuildConfigUpdater struct {
289-
buildcfg *buildapi.BuildConfig
290-
err error
290+
updateCount int
291+
buildcfg *buildapi.BuildConfig
292+
err error
293+
errUpdateCount int
291294
}
292295

293296
func (m *mockBuildConfigUpdater) Update(buildcfg *buildapi.BuildConfig) error {
294297
m.buildcfg = buildcfg
298+
m.updateCount++
299+
if m.errUpdateCount > 0 {
300+
if m.updateCount == m.errUpdateCount {
301+
return m.err
302+
}
303+
return nil
304+
}
295305
return m.err
296306
}
297307

0 commit comments

Comments
 (0)