1
1
package generictrigger
2
2
3
3
import (
4
+ "reflect"
4
5
"time"
5
6
6
7
"github.com/golang/glog"
@@ -14,6 +15,7 @@ import (
14
15
15
16
osclient "github.com/openshift/origin/pkg/client"
16
17
deployapi "github.com/openshift/origin/pkg/deploy/api"
18
+ deployutil "github.com/openshift/origin/pkg/deploy/util"
17
19
imageapi "github.com/openshift/origin/pkg/image/api"
18
20
)
19
21
@@ -28,7 +30,7 @@ const (
28
30
)
29
31
30
32
// NewDeploymentTriggerController returns a new DeploymentTriggerController.
31
- func NewDeploymentTriggerController (dcInformer , streamInformer framework.SharedIndexInformer , oc osclient.Interface , codec runtime.Codec ) * DeploymentTriggerController {
33
+ func NewDeploymentTriggerController (dcInformer , rcInformer , streamInformer framework.SharedIndexInformer , oc osclient.Interface , codec runtime.Codec ) * DeploymentTriggerController {
32
34
c := & DeploymentTriggerController {
33
35
dn : oc ,
34
36
@@ -37,18 +39,19 @@ func NewDeploymentTriggerController(dcInformer, streamInformer framework.SharedI
37
39
codec : codec ,
38
40
}
39
41
40
- c .dcStore .Indexer = dcInformer .GetIndexer ()
41
42
dcInformer .AddEventHandler (framework.ResourceEventHandlerFuncs {
42
43
AddFunc : c .addDeploymentConfig ,
43
44
UpdateFunc : c .updateDeploymentConfig ,
44
45
})
45
- c .dcStoreSynced = dcInformer .HasSynced
46
-
47
46
streamInformer .AddEventHandler (framework.ResourceEventHandlerFuncs {
48
47
AddFunc : c .addImageStream ,
49
48
UpdateFunc : c .updateImageStream ,
50
49
})
51
50
51
+ c .dcLister .Indexer = dcInformer .GetIndexer ()
52
+ c .rcLister .Indexer = rcInformer .GetIndexer ()
53
+ c .dcListerSynced = dcInformer .HasSynced
54
+ c .rcListerSynced = rcInformer .HasSynced
52
55
return c
53
56
}
54
57
@@ -76,8 +79,8 @@ func (c *DeploymentTriggerController) Run(workers int, stopCh <-chan struct{}) {
76
79
func (c * DeploymentTriggerController ) waitForSyncedStore (ready chan <- struct {}, stopCh <- chan struct {}) {
77
80
defer utilruntime .HandleCrash ()
78
81
79
- for ! c .dcStoreSynced () {
80
- glog .V (4 ).Infof ("Waiting for the deployment config cache to sync before starting the trigger controller workers" )
82
+ for ! c .dcListerSynced () || ! c . rcListerSynced () {
83
+ glog .V (4 ).Infof ("Waiting for the dc and rc caches to sync before starting the trigger controller workers" )
81
84
select {
82
85
case <- time .After (storeSyncedPollPeriod ):
83
86
case <- stopCh :
@@ -89,24 +92,64 @@ func (c *DeploymentTriggerController) waitForSyncedStore(ready chan<- struct{},
89
92
90
93
func (c * DeploymentTriggerController ) addDeploymentConfig (obj interface {}) {
91
94
dc := obj .(* deployapi.DeploymentConfig )
95
+
96
+ // No need to enqueue deployment configs that have no triggers or are paused.
92
97
if len (dc .Spec .Triggers ) == 0 || dc .Spec .Paused {
93
98
return
94
99
}
100
+ // We don't want to compete with the main deployment config controller. Let's process this
101
+ // config once it's synced.
102
+ if ! deployutil .HasSynced (dc , dc .Generation ) {
103
+ return
104
+ }
105
+
95
106
c .enqueueDeploymentConfig (dc )
96
107
}
97
108
98
109
func (c * DeploymentTriggerController ) updateDeploymentConfig (old , cur interface {}) {
99
- // If there is no generation update for this deployment config,
100
- // we have a good indication to not enqueue it.
101
110
newDc := cur .(* deployapi.DeploymentConfig )
102
111
oldDc := old .(* deployapi.DeploymentConfig )
103
- if newDc .Generation == oldDc .Generation {
112
+
113
+ // A periodic relist will send update events for all known deployment configs.
114
+ if newDc .ResourceVersion == oldDc .ResourceVersion {
104
115
return
105
116
}
106
-
117
+ // No need to enqueue deployment configs that have no triggers or are paused.
107
118
if len (newDc .Spec .Triggers ) == 0 || newDc .Spec .Paused {
108
119
return
109
120
}
121
+ // We don't want to compete with the main deployment config controller. Let's process this
122
+ // config once it's synced. Note that this does not eliminate conflicts between the two
123
+ // controllers because the main controller is constantly updating deployment configs as
124
+ // owning replication controllers and pods are updated.
125
+ if ! deployutil .HasSynced (newDc , newDc .Generation ) {
126
+ return
127
+ }
128
+ // Enqueue the deployment config if it hasn't been deployed yet.
129
+ if newDc .Status .LatestVersion == 0 {
130
+ c .enqueueDeploymentConfig (newDc )
131
+ return
132
+ }
133
+ // Compare deployment config templates before enqueueing. This reduces the amount of times
134
+ // we will try to instantiate a deployment config at the expense of duplicating some of the
135
+ // work that the instantiate endpoint is already doing but I think this is fine.
136
+ shouldInstantiate := true
137
+ latestRc , err := c .rcLister .ReplicationControllers (newDc .Namespace ).Get (deployutil .LatestDeploymentNameForConfig (newDc ))
138
+ if err != nil {
139
+ // If we get an error here it may be due to the rc cache lagging behind. In such a case
140
+ // just defer to the api server (instantiate REST) where we will retry this.
141
+ glog .V (2 ).Infof ("Cannot get latest rc for dc %s:%d (%v) - will defer to instantiate" , deployutil .LabelForDeploymentConfig (newDc ), newDc .Status .LatestVersion , err )
142
+ } else {
143
+ initial , err := deployutil .DecodeDeploymentConfig (latestRc , c .codec )
144
+ if err != nil {
145
+ glog .V (2 ).Infof ("Cannot decode dc from replication controller %s: %v" , deployutil .LabelForDeployment (latestRc ), err )
146
+ return
147
+ }
148
+ shouldInstantiate = ! reflect .DeepEqual (newDc .Spec .Template , initial .Spec .Template )
149
+ }
150
+ if ! shouldInstantiate {
151
+ return
152
+ }
110
153
111
154
c .enqueueDeploymentConfig (newDc )
112
155
}
@@ -115,10 +158,12 @@ func (c *DeploymentTriggerController) updateDeploymentConfig(old, cur interface{
115
158
func (c * DeploymentTriggerController ) addImageStream (obj interface {}) {
116
159
stream := obj .(* imageapi.ImageStream )
117
160
glog .V (4 ).Infof ("Image stream %q added." , stream .Name )
118
- dcList , err := c .dcStore .GetConfigsForImageStream (stream )
161
+ dcList , err := c .dcLister .GetConfigsForImageStream (stream )
119
162
if err != nil {
120
163
return
121
164
}
165
+ // TODO: We could check image stream tags here and enqueue only deployment configs
166
+ // with stale lastTriggeredImages.
122
167
for _ , dc := range dcList {
123
168
c .enqueueDeploymentConfig (dc )
124
169
}
@@ -134,10 +179,12 @@ func (c *DeploymentTriggerController) updateImageStream(old, cur interface{}) {
134
179
}
135
180
136
181
glog .V (4 ).Infof ("Image stream %q updated." , newStream .Name )
137
- dcList , err := c .dcStore .GetConfigsForImageStream (newStream )
182
+ dcList , err := c .dcLister .GetConfigsForImageStream (newStream )
138
183
if err != nil {
139
184
return
140
185
}
186
+ // TODO: We could check image stream tags here and enqueue only deployment configs
187
+ // with stale lastTriggeredImages.
141
188
for _ , dc := range dcList {
142
189
c .enqueueDeploymentConfig (dc )
143
190
}
@@ -183,7 +230,7 @@ func (c *DeploymentTriggerController) work() bool {
183
230
}
184
231
185
232
func (c * DeploymentTriggerController ) getByKey (key string ) (* deployapi.DeploymentConfig , error ) {
186
- obj , exists , err := c .dcStore .Indexer .GetByKey (key )
233
+ obj , exists , err := c .dcLister .Indexer .GetByKey (key )
187
234
if err != nil {
188
235
glog .Infof ("Unable to retrieve deployment config %q from store: %v" , key , err )
189
236
c .queue .Add (key )
0 commit comments