Skip to content

Commit 1db139a

Browse files
committed
WIP redo image triggering and generator
1 parent fab57a5 commit 1db139a

File tree

4 files changed

+138
-255
lines changed

4 files changed

+138
-255
lines changed

pkg/deploy/api/types.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,12 @@ type DeploymentTriggerImageChangeParams struct {
182182
From kapi.ObjectReference `json:"from"`
183183
// Tag is the name of an image repository tag to watch for changes.
184184
Tag string `json:"tag,omitempty"`
185+
// Status is the status
186+
Status DeploymentTriggerImageChangeParamsStatus `json:"status"`
187+
}
188+
189+
type DeploymentTriggerImageChangeParamsStatus struct {
190+
LastTriggeredImage string `json:"lastTriggeredImage"`
185191
}
186192

187193
// DeploymentDetails captures information about the causes of a deployment.

pkg/deploy/controller/imagechange/controller.go

Lines changed: 49 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import (
55

66
"github.com/golang/glog"
77

8-
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
9-
108
deployapi "github.com/openshift/origin/pkg/deploy/api"
119
imageapi "github.com/openshift/origin/pkg/image/api"
1210
)
@@ -26,62 +24,63 @@ func (e fatalError) Error() string { return "fatal error handling imageRepositor
2624

2725
// Handle processes image change triggers associated with imageRepo.
2826
func (c *ImageChangeController) Handle(imageRepo *imageapi.ImageRepository) error {
29-
configsToGenerate := []*deployapi.DeploymentConfig{}
30-
firedTriggersForConfig := make(map[string][]deployapi.DeploymentTriggerImageChangeParams)
31-
3227
configs, err := c.deploymentConfigClient.listDeploymentConfigs()
3328
if err != nil {
3429
return fmt.Errorf("couldn't get list of deploymentConfigs while handling imageRepo %s: %v", labelForRepo(imageRepo), err)
3530
}
3631

32+
// Find any configs which should be updated based on the new image state
33+
configsToUpdate := map[string]*deployapi.DeploymentConfig{}
3734
for _, config := range configs {
3835
glog.V(4).Infof("Detecting changed images for deploymentConfig %s", labelFor(config))
3936

40-
// Extract relevant triggers for this imageRepo for this config
41-
triggersForConfig := []deployapi.DeploymentTriggerImageChangeParams{}
4237
for _, trigger := range config.Triggers {
43-
if trigger.Type != deployapi.DeploymentTriggerOnImageChange ||
44-
!trigger.ImageChangeParams.Automatic {
38+
params := trigger.ImageChangeParams
39+
40+
// Only automatic image change triggers should fire
41+
if trigger.Type != deployapi.DeploymentTriggerOnImageChange || !params.Automatic {
4542
continue
4643
}
47-
if triggerMatchesImage(config, trigger.ImageChangeParams, imageRepo) {
48-
glog.V(4).Infof("Found matching %s trigger for deploymentConfig %s: %#v", trigger.Type, labelFor(config), trigger.ImageChangeParams)
49-
triggersForConfig = append(triggersForConfig, *trigger.ImageChangeParams)
44+
45+
// Check if the image repo matches the trigger
46+
if !triggerMatchesImage(config, params, imageRepo) {
47+
continue
5048
}
51-
}
5249

53-
for _, params := range triggersForConfig {
54-
glog.V(4).Infof("Processing image triggers for deploymentConfig %s", labelFor(config))
55-
containerNames := util.NewStringSet(params.ContainerNames...)
56-
for _, container := range config.Template.ControllerTemplate.Template.Spec.Containers {
57-
if !containerNames.Has(container.Name) {
58-
continue
59-
}
60-
61-
tagChanged, last, next, err := imageapi.DiffTag(params.Tag, container.Image, imageRepo)
62-
if err != nil {
63-
glog.V(4).Infof("Couldn't detect tag update for container %s in config %s: %v", container.Name, labelFor(config), err)
64-
continue
65-
}
66-
67-
if !tagChanged {
68-
continue
69-
}
70-
71-
glog.V(4).Infof("Container %s in config %s: image id changed from %q to %q; regenerating config", container.Name, labelFor(config), last, next)
72-
configsToGenerate = append(configsToGenerate, config)
73-
firedTriggersForConfig[config.Name] = append(firedTriggersForConfig[config.Name], params)
50+
// Find the latest tag event for the trigger tag
51+
latestEvent, err := imageapi.LatestTaggedImage(imageRepo, params.Tag)
52+
if err != nil {
53+
glog.V(4).Infof("Couldn't find latest tag event for tag %s in imageRepo %s: %s", params.Tag, labelForRepo(imageRepo), err)
54+
continue
55+
}
56+
57+
// If the tag event doesn't have an image ID yet, we can't determine
58+
// whether there was really a change
59+
if len(latestEvent.Image) == 0 {
60+
glog.V(4).Infof("Won't trigger for imageRepo %s because it has no image ID", labelForRepo(imageRepo))
61+
continue
7462
}
63+
64+
// Ensure a change occured
65+
if latestEvent.Image == params.Status.LastTriggeredImage {
66+
continue
67+
}
68+
69+
// Mark the config for regeneration
70+
configsToUpdate[config.Name] = config
7571
}
7672
}
7773

74+
// Attempt to regenerate all configs which may contain image updates
7875
anyFailed := false
79-
for _, config := range configsToGenerate {
80-
err := c.regenerate(imageRepo, config, firedTriggersForConfig[config.Name])
76+
for _, config := range configsToUpdate {
77+
err := c.regenerate(config)
8178
if err != nil {
8279
anyFailed = true
80+
glog.Infof("couldn't regenerate depoymentConfig %s: %s", labelFor(config), err)
8381
continue
8482
}
83+
8584
glog.V(4).Infof("Updated deploymentConfig %s in response to image change trigger", labelFor(config))
8685
}
8786

@@ -97,64 +96,40 @@ func (c *ImageChangeController) Handle(imageRepo *imageapi.ImageRepository) erro
9796
// When matching:
9897
// - The trigger From field is preferred over the deprecated RepositoryName field.
9998
// - The namespace of the trigger is preferred over the config's namespace.
100-
func triggerMatchesImage(config *deployapi.DeploymentConfig, trigger *deployapi.DeploymentTriggerImageChangeParams, repo *imageapi.ImageRepository) bool {
101-
if len(trigger.From.Name) > 0 {
102-
namespace := trigger.From.Namespace
99+
func triggerMatchesImage(config *deployapi.DeploymentConfig, params *deployapi.DeploymentTriggerImageChangeParams, repo *imageapi.ImageRepository) bool {
100+
if len(params.From.Name) > 0 {
101+
namespace := params.From.Namespace
103102
if len(namespace) == 0 {
104103
namespace = config.Namespace
105104
}
106105

107-
return repo.Namespace == namespace && repo.Name == trigger.From.Name
106+
return repo.Namespace == namespace && repo.Name == params.From.Name
108107
}
109108

110109
// This is an invalid state (as one of From.Name or RepositoryName is required), but
111110
// account for it anyway.
112-
if len(trigger.RepositoryName) == 0 {
111+
if len(params.RepositoryName) == 0 {
113112
return false
114113
}
115114

116115
// If the repo's repository information isn't yet available, we can't assume it'll match.
117116
return len(repo.Status.DockerImageRepository) > 0 &&
118-
trigger.RepositoryName == repo.Status.DockerImageRepository
117+
params.RepositoryName == repo.Status.DockerImageRepository
119118
}
120119

121-
func (c *ImageChangeController) regenerate(imageRepo *imageapi.ImageRepository, config *deployapi.DeploymentConfig, triggers []deployapi.DeploymentTriggerImageChangeParams) error {
120+
// regenerate calls the generator to get a new config. If the newly generated
121+
// config's version is newer, update the old config to be the new config.
122+
// Otherwise do nothing.
123+
func (c *ImageChangeController) regenerate(config *deployapi.DeploymentConfig) error {
122124
// Get a regenerated config which includes the new image repo references
123125
newConfig, err := c.deploymentConfigClient.generateDeploymentConfig(config.Namespace, config.Name)
124126
if err != nil {
125127
return fmt.Errorf("error generating new version of deploymentConfig %s: %v", labelFor(config), err)
126128
}
127129

128-
// Update the deployment config with the trigger that resulted in the new config
129-
causes := []*deployapi.DeploymentCause{}
130-
for _, trigger := range triggers {
131-
repoName := trigger.RepositoryName
132-
133-
if len(repoName) == 0 {
134-
if len(imageRepo.Status.DockerImageRepository) == 0 {
135-
// If the trigger relies on a image repo reference, and we don't know what docker repo
136-
// it points at, we can't build a cause for the reference yet.
137-
continue
138-
}
139-
140-
latest, err := imageapi.LatestTaggedImage(imageRepo, trigger.Tag)
141-
if err != nil {
142-
return fmt.Errorf("error generating new version of deploymentConfig: %s: %s", labelFor(config), err)
143-
}
144-
repoName = latest.DockerImageReference
145-
}
146-
147-
causes = append(causes,
148-
&deployapi.DeploymentCause{
149-
Type: deployapi.DeploymentTriggerOnImageChange,
150-
ImageTrigger: &deployapi.DeploymentCauseImageTrigger{
151-
RepositoryName: repoName,
152-
Tag: trigger.Tag,
153-
},
154-
})
155-
}
156-
newConfig.Details = &deployapi.DeploymentDetails{
157-
Causes: causes,
130+
// No update occured
131+
if config.LatestVersion == newConfig.LatestVersion {
132+
return nil
158133
}
159134

160135
// Persist the new config
@@ -163,6 +138,7 @@ func (c *ImageChangeController) regenerate(imageRepo *imageapi.ImageRepository,
163138
return err
164139
}
165140

141+
glog.Infof("Regenerated depoymentConfig %s for image updates", labelFor(config))
166142
return nil
167143
}
168144

0 commit comments

Comments
 (0)