Skip to content

Commit e30d636

Browse files
committed
lookup buildconfigs in shared indexed cache instead of listing
1 parent 7bb3e69 commit e30d636

File tree

10 files changed

+303
-119
lines changed

10 files changed

+303
-119
lines changed

pkg/build/controller/factory/factory.go

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,18 @@ import (
2525
strategy "github.com/openshift/origin/pkg/build/controller/strategy"
2626
buildutil "github.com/openshift/origin/pkg/build/util"
2727
osclient "github.com/openshift/origin/pkg/client"
28+
oscache "github.com/openshift/origin/pkg/client/cache"
2829
controller "github.com/openshift/origin/pkg/controller"
2930
imageapi "github.com/openshift/origin/pkg/image/api"
3031
errors "github.com/openshift/origin/pkg/util/errors"
3132
)
3233

33-
const maxRetries = 60
34+
const (
35+
// We must avoid creating processing imagestream changes until the build config store has synced.
36+
// If it hasn't synced, to avoid a hot loop, we'll wait this long between checks.
37+
StoreSyncedPollPeriod = 100 * time.Millisecond
38+
maxRetries = 60
39+
)
3440

3541
// limitedLogAndRetry stops retrying after maxTimeout, failing the build.
3642
func limitedLogAndRetry(buildupdater buildclient.BuildUpdater, maxTimeout time.Duration) controller.RetryFunc {
@@ -274,6 +280,8 @@ func (factory *BuildPodControllerFactory) CreateDeleteController() controller.Ru
274280
type ImageChangeControllerFactory struct {
275281
Client osclient.Interface
276282
BuildConfigInstantiator buildclient.BuildConfigInstantiator
283+
BuildConfigIndex oscache.StoreToBuildConfigLister
284+
BuildConfigIndexSynced func() bool
277285
// Stop may be set to allow controllers created by this factory to be terminated.
278286
Stop <-chan struct{}
279287
}
@@ -284,14 +292,14 @@ func (factory *ImageChangeControllerFactory) Create() controller.RunnableControl
284292
queue := cache.NewResyncableFIFO(cache.MetaNamespaceKeyFunc)
285293
cache.NewReflector(&imageStreamLW{factory.Client}, &imageapi.ImageStream{}, queue, 2*time.Minute).RunUntil(factory.Stop)
286294

287-
store := cache.NewStore(cache.MetaNamespaceKeyFunc)
288-
cache.NewReflector(&buildConfigLW{client: factory.Client}, &buildapi.BuildConfig{}, store, 2*time.Minute).RunUntil(factory.Stop)
289-
290295
imageChangeController := &buildcontroller.ImageChangeController{
291-
BuildConfigStore: store,
296+
BuildConfigIndex: factory.BuildConfigIndex,
292297
BuildConfigInstantiator: factory.BuildConfigInstantiator,
293298
}
294299

300+
// Wait for the bc store to sync before starting any work in this controller.
301+
factory.waitForSyncedStores()
302+
295303
return &controller.RetryController{
296304
Queue: queue,
297305
RetryManager: controller.NewQueueRetryManager(
@@ -305,11 +313,18 @@ func (factory *ImageChangeControllerFactory) Create() controller.RunnableControl
305313
),
306314
Handle: func(obj interface{}) error {
307315
imageRepo := obj.(*imageapi.ImageStream)
308-
return imageChangeController.HandleImageRepo(imageRepo)
316+
return imageChangeController.HandleImageStream(imageRepo)
309317
},
310318
}
311319
}
312320

321+
func (factory *ImageChangeControllerFactory) waitForSyncedStores() {
322+
for !factory.BuildConfigIndexSynced() {
323+
glog.V(4).Infof("Waiting for the bc caches to sync before starting the imagechange buildconfig controller worker")
324+
<-time.After(StoreSyncedPollPeriod)
325+
}
326+
}
327+
313328
type BuildConfigControllerFactory struct {
314329
Client osclient.Interface
315330
KubeClient kclient.Interface

pkg/build/controller/image_change_controller.go

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ import (
88
kerrors "k8s.io/kubernetes/pkg/api/errors"
99

1010
kapi "k8s.io/kubernetes/pkg/api"
11-
"k8s.io/kubernetes/pkg/client/cache"
1211
utilruntime "k8s.io/kubernetes/pkg/util/runtime"
1312

1413
buildapi "github.com/openshift/origin/pkg/build/api"
1514
buildclient "github.com/openshift/origin/pkg/build/client"
1615
buildutil "github.com/openshift/origin/pkg/build/util"
16+
oscache "github.com/openshift/origin/pkg/client/cache"
1717
imageapi "github.com/openshift/origin/pkg/image/api"
1818
)
1919

@@ -31,7 +31,7 @@ func (e ImageChangeControllerFatalError) Error() string {
3131
// builds when a new version of a tag referenced by a BuildConfig
3232
// is available.
3333
type ImageChangeController struct {
34-
BuildConfigStore cache.Store
34+
BuildConfigIndex oscache.StoreToBuildConfigLister
3535
BuildConfigInstantiator buildclient.BuildConfigInstantiator
3636
}
3737

@@ -42,9 +42,9 @@ func getImageStreamNameFromReference(ref *kapi.ObjectReference) string {
4242
return strings.Split(name, "@")[0]
4343
}
4444

45-
// HandleImageRepo processes the next ImageStream event.
46-
func (c *ImageChangeController) HandleImageRepo(repo *imageapi.ImageStream) error {
47-
glog.V(4).Infof("Build image change controller detected ImageStream change %s", repo.Status.DockerImageRepository)
45+
// HandleImageStream processes the next ImageStream event.
46+
func (c *ImageChangeController) HandleImageStream(stream *imageapi.ImageStream) error {
47+
glog.V(4).Infof("Build image change controller detected ImageStream change %s", stream.Status.DockerImageRepository)
4848

4949
// Loop through all build configurations and record if there was an error
5050
// instead of breaking the loop. The error will be returned in the end, so the
@@ -53,17 +53,18 @@ func (c *ImageChangeController) HandleImageRepo(repo *imageapi.ImageStream) erro
5353
// in a no-op for them.
5454
hasError := false
5555

56-
// TODO: this is inefficient
57-
for _, bc := range c.BuildConfigStore.List() {
58-
config := bc.(*buildapi.BuildConfig)
59-
56+
bcs, err := c.BuildConfigIndex.GetConfigsForImageStreamTrigger(stream)
57+
if err != nil {
58+
return err
59+
}
60+
for _, config := range bcs {
6061
var (
6162
from *kapi.ObjectReference
6263
shouldBuild = false
6364
triggeredImage = ""
6465
latest *imageapi.TagEvent
6566
)
66-
// For every ImageChange trigger find the latest tagged image from the image repository and
67+
// For every ImageChange trigger find the latest tagged image from the image stream and
6768
// invoke a build using that image id. A new build is triggered only if the latest tagged image id or pull spec
6869
// differs from the last triggered build recorded on the build config for that trigger
6970
for _, trigger := range config.Spec.Triggers {
@@ -90,21 +91,21 @@ func (c *ImageChangeController) HandleImageRepo(repo *imageapi.ImageStream) erro
9091
fromNamespace = config.Namespace
9192
}
9293

93-
// only trigger a build if this image repo matches the name and namespace of the ref in the build trigger
94+
// only trigger a build if this image stream matches the name and namespace of the stream ref in the build trigger
9495
// also do not trigger if the imagerepo does not have a valid DockerImageRepository value for us to pull
9596
// the image from
96-
if len(repo.Status.DockerImageRepository) == 0 || fromStreamName != repo.Name || fromNamespace != repo.Namespace {
97+
if len(stream.Status.DockerImageRepository) == 0 || fromStreamName != stream.Name || fromNamespace != stream.Namespace {
9798
continue
9899
}
99100

100101
// This split is safe because ImageStreamTag names always have the form
101102
// name:tag.
102-
latest = imageapi.LatestTaggedImage(repo, tag)
103+
latest = imageapi.LatestTaggedImage(stream, tag)
103104
if latest == nil {
104-
glog.V(4).Infof("unable to find tagged image: no image recorded for %s/%s:%s", repo.Namespace, repo.Name, tag)
105+
glog.V(4).Infof("unable to find tagged image: no image recorded for %s/%s:%s", stream.Namespace, stream.Name, tag)
105106
continue
106107
}
107-
glog.V(4).Infof("Found ImageStream %s/%s with tag %s", repo.Namespace, repo.Name, tag)
108+
glog.V(4).Infof("Found ImageStream %s/%s with tag %s", stream.Namespace, stream.Name, tag)
108109

109110
// (must be different) to trigger a build
110111
last := trigger.ImageChange.LastTriggeredImageID
@@ -155,7 +156,7 @@ func (c *ImageChangeController) HandleImageRepo(repo *imageapi.ImageStream) erro
155156
}
156157
}
157158
if hasError {
158-
return fmt.Errorf("an error occurred processing 1 or more build configurations; the image change trigger for image stream %s will be retried", repo.Status.DockerImageRepository)
159+
return fmt.Errorf("an error occurred processing 1 or more build configurations; the image change trigger for image stream %s will be retried", stream.Status.DockerImageRepository)
159160
}
160161
return nil
161162
}

pkg/build/controller/image_change_controller_test.go

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ func TestNewImageID(t *testing.T) {
2626
bcInstantiator := controller.BuildConfigInstantiator.(*buildConfigInstantiator)
2727
bcUpdater := bcInstantiator.buildConfigUpdater
2828

29-
err := controller.HandleImageRepo(imageStream)
29+
err := controller.HandleImageStream(imageStream)
3030
if err != nil {
31-
t.Fatalf("Unexpected error %v from HandleImageRepo", err)
31+
t.Fatalf("Unexpected error %v from HandleImageStream", err)
3232
}
3333

3434
if len(bcInstantiator.name) == 0 {
@@ -54,9 +54,9 @@ func TestNewImageIDDefaultTag(t *testing.T) {
5454
bcInstantiator := controller.BuildConfigInstantiator.(*buildConfigInstantiator)
5555
bcUpdater := bcInstantiator.buildConfigUpdater
5656

57-
err := controller.HandleImageRepo(imageStream)
57+
err := controller.HandleImageStream(imageStream)
5858
if err != nil {
59-
t.Fatalf("Unexpected error %v from HandleImageRepo", err)
59+
t.Fatalf("Unexpected error %v from HandleImageStream", err)
6060
}
6161
if len(bcInstantiator.name) == 0 {
6262
t.Error("Expected build generation when new image was created!")
@@ -82,9 +82,9 @@ func TestNonExistentImageStream(t *testing.T) {
8282
bcInstantiator := controller.BuildConfigInstantiator.(*buildConfigInstantiator)
8383
bcUpdater := bcInstantiator.buildConfigUpdater
8484

85-
err := controller.HandleImageRepo(imageStream)
85+
err := controller.HandleImageStream(imageStream)
8686
if err != nil {
87-
t.Fatalf("Unexpected error %v from HandleImageRepo", err)
87+
t.Fatalf("Unexpected error %v from HandleImageStream", err)
8888
}
8989
if len(bcInstantiator.name) != 0 {
9090
t.Error("New build generated when a different repository was updated!")
@@ -103,9 +103,9 @@ func TestNewImageDifferentTagUpdate(t *testing.T) {
103103
bcInstantiator := controller.BuildConfigInstantiator.(*buildConfigInstantiator)
104104
bcUpdater := bcInstantiator.buildConfigUpdater
105105

106-
err := controller.HandleImageRepo(imageStream)
106+
err := controller.HandleImageStream(imageStream)
107107
if err != nil {
108-
t.Errorf("Unexpected error %v from HandleImageRepo", err)
108+
t.Errorf("Unexpected error %v from HandleImageStream", err)
109109
}
110110
if len(bcInstantiator.name) != 0 {
111111
t.Error("New build generated when a different repository was updated!")
@@ -126,9 +126,9 @@ func TestNewImageDifferentTagUpdate2(t *testing.T) {
126126
bcInstantiator := controller.BuildConfigInstantiator.(*buildConfigInstantiator)
127127
bcUpdater := bcInstantiator.buildConfigUpdater
128128

129-
err := controller.HandleImageRepo(imageStream)
129+
err := controller.HandleImageStream(imageStream)
130130
if err != nil {
131-
t.Errorf("Unexpected error %v from HandleImageRepo", err)
131+
t.Errorf("Unexpected error %v from HandleImageStream", err)
132132
}
133133
if len(bcInstantiator.name) != 0 {
134134
t.Error("New build generated when a different repository was updated!")
@@ -147,9 +147,9 @@ func TestNewDifferentImageUpdate(t *testing.T) {
147147
bcInstantiator := controller.BuildConfigInstantiator.(*buildConfigInstantiator)
148148
bcUpdater := bcInstantiator.buildConfigUpdater
149149

150-
err := controller.HandleImageRepo(imageStream)
150+
err := controller.HandleImageStream(imageStream)
151151
if err != nil {
152-
t.Errorf("Unexpected error %v from HandleImageRepo", err)
152+
t.Errorf("Unexpected error %v from HandleImageStream", err)
153153
}
154154
if len(bcInstantiator.name) != 0 {
155155
t.Error("New build generated when a different repository was updated!")
@@ -170,9 +170,9 @@ func TestSameStreamNameDifferentNamespaces(t *testing.T) {
170170
bcInstantiator := controller.BuildConfigInstantiator.(*buildConfigInstantiator)
171171
bcUpdater := bcInstantiator.buildConfigUpdater
172172

173-
err := controller.HandleImageRepo(imageStream)
173+
err := controller.HandleImageStream(imageStream)
174174
if err != nil {
175-
t.Errorf("Unexpected error %v from HandleImageRepo", err)
175+
t.Errorf("Unexpected error %v from HandleImageStream", err)
176176
}
177177
if len(bcInstantiator.name) != 0 {
178178
t.Error("New build generated when a different repository was updated!")
@@ -192,9 +192,9 @@ func TestBuildConfigWithDifferentTriggerType(t *testing.T) {
192192
bcInstantiator := controller.BuildConfigInstantiator.(*buildConfigInstantiator)
193193
bcUpdater := bcInstantiator.buildConfigUpdater
194194

195-
err := controller.HandleImageRepo(imageStream)
195+
err := controller.HandleImageStream(imageStream)
196196
if err != nil {
197-
t.Errorf("Unexpected error %v from HandleImageRepo", err)
197+
t.Errorf("Unexpected error %v from HandleImageStream", err)
198198
}
199199
if len(bcInstantiator.name) != 0 {
200200
t.Error("New build generated when a different repository was updated!")
@@ -215,9 +215,9 @@ func TestNoImageIDChange(t *testing.T) {
215215
bcInstantiator := controller.BuildConfigInstantiator.(*buildConfigInstantiator)
216216
bcUpdater := bcInstantiator.buildConfigUpdater
217217

218-
err := controller.HandleImageRepo(imageStream)
218+
err := controller.HandleImageStream(imageStream)
219219
if err != nil {
220-
t.Errorf("Unexpected error %v from HandleImageRepo", err)
220+
t.Errorf("Unexpected error %v from HandleImageStream", err)
221221
}
222222
if len(bcInstantiator.name) != 0 {
223223
t.Error("New build generated when no change happened!")
@@ -237,9 +237,9 @@ func TestBuildConfigInstantiatorError(t *testing.T) {
237237
bcInstantiator.err = fmt.Errorf("instantiating error")
238238
bcUpdater := bcInstantiator.buildConfigUpdater
239239

240-
err := controller.HandleImageRepo(imageStream)
240+
err := controller.HandleImageStream(imageStream)
241241
if err == nil || !strings.Contains(err.Error(), "will be retried") {
242-
t.Fatalf("Expected 'will be retried' from HandleImageRepo, got %s", err.Error())
242+
t.Fatalf("Expected 'will be retried' from HandleImageStream, got %s", err.Error())
243243
}
244244
if actual, expected := bcInstantiator.newBuild.Spec.Strategy.DockerStrategy.From.Name, "registry.com/namespace/imagename:newImageID123"; actual != expected {
245245
t.Errorf("Image substitutions not properly setup for new build. Expected %s, got %s |", expected, actual)
@@ -259,12 +259,12 @@ func TestBuildConfigUpdateError(t *testing.T) {
259259
bcUpdater := bcInstantiator.buildConfigUpdater
260260
bcUpdater.err = kerrors.NewConflict(buildapi.Resource("BuildConfig"), buildcfg.Name, errors.New("foo"))
261261

262-
err := controller.HandleImageRepo(imageStream)
262+
err := controller.HandleImageStream(imageStream)
263263
if len(bcInstantiator.name) == 0 {
264264
t.Error("Expected build generation when new image was created!")
265265
}
266266
if err == nil || !strings.Contains(err.Error(), "will be retried") {
267-
t.Fatalf("Expected 'will be retried' from HandleImageRepo, got %s", err.Error())
267+
t.Fatalf("Expected 'will be retried' from HandleImageStream, got %s", err.Error())
268268
}
269269
}
270270

@@ -277,9 +277,9 @@ func TestNewImageIDNoDockerRepo(t *testing.T) {
277277
bcInstantiator := controller.BuildConfigInstantiator.(*buildConfigInstantiator)
278278
bcUpdater := bcInstantiator.buildConfigUpdater
279279

280-
err := controller.HandleImageRepo(imageStream)
280+
err := controller.HandleImageStream(imageStream)
281281
if err != nil {
282-
t.Errorf("Unexpected error %v from HandleImageRepo", err)
282+
t.Errorf("Unexpected error %v from HandleImageStream", err)
283283
}
284284
if len(bcInstantiator.name) != 0 {
285285
t.Error("New build generated when no change happened!")
@@ -417,7 +417,7 @@ func mockBuildConfigInstantiator(buildcfg *buildapi.BuildConfig, imageStream *im
417417

418418
func mockImageChangeController(buildcfg *buildapi.BuildConfig, imageStream *imageapi.ImageStream, image *imageapi.Image) *ImageChangeController {
419419
return &ImageChangeController{
420-
BuildConfigStore: buildtest.NewFakeBuildConfigStore(buildcfg),
420+
BuildConfigIndex: buildtest.NewFakeBuildConfigIndex(buildcfg),
421421
BuildConfigInstantiator: mockBuildConfigInstantiator(buildcfg, imageStream, image),
422422
}
423423
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package test
2+
3+
import (
4+
buildapi "github.com/openshift/origin/pkg/build/api"
5+
oscache "github.com/openshift/origin/pkg/client/cache"
6+
imageapi "github.com/openshift/origin/pkg/image/api"
7+
)
8+
9+
type FakeBuildConfigIndex struct {
10+
Build *buildapi.BuildConfig
11+
Err error
12+
}
13+
14+
func NewFakeBuildConfigIndex(build *buildapi.BuildConfig) oscache.StoreToBuildConfigLister {
15+
return &FakeBuildConfigIndex{Build: build}
16+
}
17+
18+
func (i *FakeBuildConfigIndex) List() ([]*buildapi.BuildConfig, error) {
19+
return []*buildapi.BuildConfig{i.Build}, nil
20+
}
21+
22+
func (i *FakeBuildConfigIndex) GetConfigsForImageStreamTrigger(stream *imageapi.ImageStream) ([]*buildapi.BuildConfig, error) {
23+
return []*buildapi.BuildConfig{i.Build}, nil
24+
}

0 commit comments

Comments
 (0)