Skip to content

Commit 49e8b67

Browse files
committed
Merge pull request #1 from soltysh/card282
Added startup handling for ImageChangeController
2 parents f4dc902 + 7767026 commit 49e8b67

File tree

6 files changed

+261
-58
lines changed

6 files changed

+261
-58
lines changed

pkg/build/api/types.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,9 @@ type ImageChangeTrigger struct {
245245
ImageRepositoryRef *kapi.ObjectReference `json:"imageRepositoryRef" yaml:"imageRepositoryRef"`
246246
// Tag is the name of an image repository tag to watch for changes.
247247
Tag string `json:"tag,omitempty" yaml:"tag,omitempty"`
248+
// LastTriggeredImageID is used internally by the ImageChangeController to save last
249+
// used image ID for build
250+
LastTriggeredImageID string `json:"lastTriggeredImageID,omitempty" yaml:"lastTriggeredImageID,omitempty"`
248251
}
249252

250253
// BuildTriggerPolicy describes a policy for a single trigger that results in a new Build.

pkg/build/api/v1beta1/types.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,9 @@ type ImageChangeTrigger struct {
240240
ImageRepositoryRef *kapi.ObjectReference `json:"imageRepositoryRef" yaml:"imageRepositoryRef"`
241241
// Tag is the name of an image repository tag to watch for changes.
242242
Tag string `json:"tag,omitempty" yaml:"tag,omitempty"`
243+
// LastTriggeredImageID is used internally by the ImageChangeController to save last
244+
// used image ID for build
245+
LastTriggeredImageID string `json:"lastTriggeredImageID,omitempty" yaml:"lastTriggeredImageID,omitempty"`
243246
}
244247

245248
// BuildTriggerPolicy describes a policy for a single trigger that results in a new Build.

pkg/build/controller/factory/factory.go

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,9 @@ func (factory *ImageChangeControllerFactory) Create() *controller.ImageChangeCon
8585
cache.NewReflector(&buildConfigLW{client: factory.Client}, &buildapi.BuildConfig{}, store).Run()
8686

8787
return &controller.ImageChangeController{
88-
BuildConfigStore: store,
89-
BuildCreator: &ClientBuildCreator{factory.Client},
88+
BuildConfigStore: store,
89+
BuildConfigUpdater: &ClientBuildConfigUpdater{factory.Client},
90+
BuildCreator: &ClientBuildCreator{factory.Client},
9091
NextImageRepository: func() *imageapi.ImageRepository {
9192
repo := queue.Pop().(*imageapi.ImageRepository)
9293
panicIfStopped(factory.Stop, "build image change controller stopped")
@@ -219,7 +220,12 @@ func (c ClientPodManager) CreatePod(namespace string, pod *kapi.Pod) (*kapi.Pod,
219220
return c.KubeClient.Pods(namespace).Create(pod)
220221
}
221222

222-
// ClientBuildUpdater is a buildUpdater which delegates to the OpenShift client interfaces
223+
// DeletePod destroys a pod using the Kubernetes client.
224+
func (c ClientPodManager) DeletePod(namespace string, pod *kapi.Pod) error {
225+
return c.KubeClient.Pods(namespace).Delete(pod.Name)
226+
}
227+
228+
// ClientBuildUpdater is a buildUpdater which delegates to the OpenShift client interfaces.
223229
type ClientBuildUpdater struct {
224230
Client osclient.Interface
225231
}
@@ -229,7 +235,7 @@ func (c ClientBuildUpdater) UpdateBuild(namespace string, build *buildapi.Build)
229235
return c.Client.Builds(namespace).Update(build)
230236
}
231237

232-
// ClientBuildCreator is a buildCreator which delegates to the OpenShift client interfaces
238+
// ClientBuildCreator is a buildCreator which delegates to the OpenShift client interfaces.
233239
type ClientBuildCreator struct {
234240
Client osclient.Interface
235241
}
@@ -247,7 +253,13 @@ func (c *ClientBuildCreator) CreateBuild(config *buildapi.BuildConfig, imageSubs
247253
return nil
248254
}
249255

250-
// DeletePod destroys a pod using the Kubernetes client.
251-
func (c ClientPodManager) DeletePod(namespace string, pod *kapi.Pod) error {
252-
return c.KubeClient.Pods(namespace).Delete(pod.Name)
256+
// ClientBuildConfigUpdater is a buildConfigUpdater which delegates to the OpenShift client interfaces.
257+
type ClientBuildConfigUpdater struct {
258+
Client osclient.Interface
259+
}
260+
261+
// UpdateBuildConfig updates buildConfig using the OpenShift client.
262+
func (c *ClientBuildConfigUpdater) UpdateBuildConfig(buildConfig *buildapi.BuildConfig) error {
263+
_, err := c.Client.BuildConfigs(buildConfig.Namespace).Update(buildConfig)
264+
return err
253265
}

pkg/build/controller/image_change_controller.go

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,16 @@ import (
1616
type ImageChangeController struct {
1717
NextImageRepository func() *imageapi.ImageRepository
1818
BuildConfigStore cache.Store
19+
BuildConfigUpdater buildConfigUpdater
1920
BuildCreator buildCreator
2021
// Stop is an optional channel that controls when the controller exits
2122
Stop <-chan struct{}
2223
}
2324

25+
type buildConfigUpdater interface {
26+
UpdateBuildConfig(buildConfig *buildapi.BuildConfig) error
27+
}
28+
2429
type buildCreator interface {
2530
CreateBuild(build *buildapi.BuildConfig, imageSubstitutions map[string]string) error
2631
}
@@ -42,33 +47,47 @@ func (c *ImageChangeController) HandleImageRepo() {
4247
glog.V(4).Infof("Detecting changed images for buildConfig %s", config.Name)
4348

4449
// Extract relevant triggers for this imageRepo for this config
45-
var triggerForConfig *buildapi.ImageChangeTrigger
50+
shouldTriggerBuild := false
4651
for _, trigger := range config.Triggers {
52+
if trigger.Type != buildapi.ImageChangeBuildTriggerType {
53+
continue
54+
}
4755
// for every ImageChange trigger, record the image it substitutes for and get the latest
4856
// image id from the imagerepository. We will substitute all images in the buildconfig
4957
// with the latest values from the imagerepositories.
50-
if trigger.Type == buildapi.ImageChangeBuildTriggerType {
51-
// TODO: we don't really want to create a build for a buildconfig based the "test" tag if the "prod" tag is what just got
52-
// updated, but ImageRepository doesn't give us that granularity today, so the only way to avoid these spurious builds is
53-
// to check if the new imageid is different from the last time we built this buildcfg. Need to add this check.
54-
// Will be effectively identical the logic needed on startup to spin new builds only if we missed a new image event.
55-
var tag string
56-
if tag = trigger.ImageChange.Tag; len(tag) == 0 {
57-
tag = buildapi.DefaultImageTag
58-
}
59-
if repoImageID, repoHasTag := imageRepo.Tags[tag]; repoHasTag {
60-
imageSubstitutions[trigger.ImageChange.Image] = imageRepo.DockerImageRepository + ":" + repoImageID
61-
}
62-
if trigger.ImageChange.ImageRepositoryRef.Name == imageRepo.Name {
63-
triggerForConfig = trigger.ImageChange
64-
}
58+
icTrigger := trigger.ImageChange
59+
60+
// TODO: we don't really want to create a build for a buildconfig based the "test" tag if the "prod" tag is what just got
61+
// updated, but ImageRepository doesn't give us that granularity today, so the only way to avoid these spurious builds is
62+
// to check if the new imageid is different from the last time we built this buildcfg. Need to add this check.
63+
// Will be effectively identical the logic needed on startup to spin new builds only if we missed a new image event.
64+
tag := icTrigger.Tag
65+
if len(tag) == 0 {
66+
tag = buildapi.DefaultImageTag
67+
}
68+
imageID, hasTag := imageRepo.Tags[tag]
69+
if !hasTag {
70+
continue
71+
}
72+
73+
// comparison requires us to match Name of the image and LastTriggeredImageID
74+
// (must be different) to trigger a build
75+
if icTrigger.ImageRepositoryRef.Name == imageRepo.Name &&
76+
icTrigger.LastTriggeredImageID != imageID {
77+
imageSubstitutions[icTrigger.Image] = imageRepo.DockerImageRepository + ":" + imageID
78+
shouldTriggerBuild = true
79+
icTrigger.LastTriggeredImageID = imageID
6580
}
6681
}
6782

68-
if triggerForConfig != nil {
83+
if shouldTriggerBuild {
6984
glog.V(4).Infof("Running build for buildConfig %s", config.Name)
7085
if err := c.BuildCreator.CreateBuild(config, imageSubstitutions); err != nil {
7186
glog.V(2).Infof("Error starting build for buildConfig %v: %v", config.Name, err)
87+
} else {
88+
if err := c.BuildConfigUpdater.UpdateBuildConfig(config); err != nil {
89+
glog.V(2).Infof("Error updating buildConfig %v: %v", config.Name, err)
90+
}
7291
}
7392
}
7493
}

0 commit comments

Comments
 (0)