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.
| ... | ... |
@@ -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 |
|