@@ -14,11 +14,12 @@ import (
14
14
"k8s.io/apimachinery/pkg/runtime"
15
15
"k8s.io/apimachinery/pkg/util/wait"
16
16
"k8s.io/apimachinery/pkg/watch"
17
+ "k8s.io/client-go/scale"
17
18
"k8s.io/client-go/tools/record"
19
+ "k8s.io/client-go/util/retry"
18
20
kapi "k8s.io/kubernetes/pkg/apis/core"
19
21
kclientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
20
22
kcoreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
21
- "k8s.io/kubernetes/pkg/kubectl"
22
23
23
24
appsapi "github.com/openshift/origin/pkg/apps/apis/apps"
24
25
strat "github.com/openshift/origin/pkg/apps/strategy"
@@ -41,30 +42,27 @@ type RecreateDeploymentStrategy struct {
41
42
until string
42
43
// rcClient is a client to access replication controllers
43
44
rcClient kcoreclient.ReplicationControllersGetter
45
+ // scaleClient is a client to access scaling
46
+ scaleClient scale.ScalesGetter
44
47
// podClient is used to list and watch pods.
45
48
podClient kcoreclient.PodsGetter
46
49
// eventClient is a client to access events
47
50
eventClient kcoreclient.EventsGetter
48
51
// getUpdateAcceptor returns an UpdateAcceptor to verify the first replica
49
52
// of the deployment.
50
53
getUpdateAcceptor func (time.Duration , int32 ) strat.UpdateAcceptor
51
- // scaler is used to scale replication controllers.
52
- scaler kubectl.Scaler
53
54
// codec is used to decode DeploymentConfigs contained in deployments.
54
55
decoder runtime.Decoder
55
56
// hookExecutor can execute a lifecycle hook.
56
57
hookExecutor stratsupport.HookExecutor
57
- // retryPeriod is how often to try updating the replica count.
58
- retryPeriod time.Duration
59
- // retryParams encapsulates the retry parameters
60
- retryParams * kubectl.RetryParams
61
58
// events records the events
62
59
events record.EventSink
63
60
}
64
61
65
62
// NewRecreateDeploymentStrategy makes a RecreateDeploymentStrategy backed by
66
63
// a real HookExecutor and client.
67
- func NewRecreateDeploymentStrategy (client kclientset.Interface , tagClient imageclient.ImageStreamTagsGetter , events record.EventSink , decoder runtime.Decoder , out , errOut io.Writer , until string ) * RecreateDeploymentStrategy {
64
+ func NewRecreateDeploymentStrategy (client kclientset.Interface , tagClient imageclient.ImageStreamTagsGetter ,
65
+ events record.EventSink , decoder runtime.Decoder , out , errOut io.Writer , until string ) * RecreateDeploymentStrategy {
68
66
if out == nil {
69
67
out = ioutil .Discard
70
68
}
@@ -78,15 +76,14 @@ func NewRecreateDeploymentStrategy(client kclientset.Interface, tagClient imagec
78
76
events : events ,
79
77
until : until ,
80
78
rcClient : client .Core (),
79
+ scaleClient : appsutil .NewReplicationControllerV1ScaleClient (client ),
81
80
eventClient : client .Core (),
82
81
podClient : client .Core (),
83
82
getUpdateAcceptor : func (timeout time.Duration , minReadySeconds int32 ) strat.UpdateAcceptor {
84
83
return stratsupport .NewAcceptAvailablePods (out , client .Core (), timeout )
85
84
},
86
- scaler : appsutil .NewReplicationControllerV1Scaler (client ),
87
85
decoder : decoder ,
88
86
hookExecutor : stratsupport .NewHookExecutor (client .Core (), tagClient , client .Core (), os .Stdout , decoder ),
89
- retryPeriod : 1 * time .Second ,
90
87
}
91
88
}
92
89
@@ -108,25 +105,22 @@ func (s *RecreateDeploymentStrategy) DeployWithAcceptor(from *kapi.ReplicationCo
108
105
return fmt .Errorf ("couldn't decode config from deployment %s: %v" , to .Name , err )
109
106
}
110
107
111
- retryTimeout := time .Duration (appsapi .DefaultRecreateTimeoutSeconds ) * time .Second
108
+ recreateTimeout := time .Duration (appsapi .DefaultRecreateTimeoutSeconds ) * time .Second
112
109
params := config .Spec .Strategy .RecreateParams
113
110
rollingParams := config .Spec .Strategy .RollingParams
114
111
115
112
if params != nil && params .TimeoutSeconds != nil {
116
- retryTimeout = time .Duration (* params .TimeoutSeconds ) * time .Second
113
+ recreateTimeout = time .Duration (* params .TimeoutSeconds ) * time .Second
117
114
}
118
115
119
116
// When doing the initial rollout for rolling strategy we use recreate and for that we
120
117
// have to set the TimeoutSecond based on the rollling strategy parameters.
121
118
if rollingParams != nil && rollingParams .TimeoutSeconds != nil {
122
- retryTimeout = time .Duration (* rollingParams .TimeoutSeconds ) * time .Second
119
+ recreateTimeout = time .Duration (* rollingParams .TimeoutSeconds ) * time .Second
123
120
}
124
121
125
- s .retryParams = kubectl .NewRetryParams (s .retryPeriod , retryTimeout )
126
- waitParams := kubectl .NewRetryParams (s .retryPeriod , retryTimeout )
127
-
128
122
if updateAcceptor == nil {
129
- updateAcceptor = s .getUpdateAcceptor (retryTimeout , config .Spec .MinReadySeconds )
123
+ updateAcceptor = s .getUpdateAcceptor (recreateTimeout , config .Spec .MinReadySeconds )
130
124
}
131
125
132
126
// Execute any pre-hook.
@@ -147,7 +141,7 @@ func (s *RecreateDeploymentStrategy) DeployWithAcceptor(from *kapi.ReplicationCo
147
141
// Scale down the from deployment.
148
142
if from != nil {
149
143
fmt .Fprintf (s .out , "--> Scaling %s down to zero\n " , from .Name )
150
- _ , err := s .scaleAndWait (from , 0 , s . retryParams , waitParams )
144
+ _ , err := s .scaleAndWait (from , 0 , recreateTimeout )
151
145
if err != nil {
152
146
return fmt .Errorf ("couldn't scale %s to 0: %v" , from .Name , err )
153
147
}
@@ -177,7 +171,7 @@ func (s *RecreateDeploymentStrategy) DeployWithAcceptor(from *kapi.ReplicationCo
177
171
// Scale up to 1 and validate the replica,
178
172
// aborting if the replica isn't acceptable.
179
173
fmt .Fprintf (s .out , "--> Scaling %s to 1 before performing acceptance check\n " , to .Name )
180
- updatedTo , err := s .scaleAndWait (to , 1 , s . retryParams , waitParams )
174
+ updatedTo , err := s .scaleAndWait (to , 1 , recreateTimeout )
181
175
if err != nil {
182
176
return fmt .Errorf ("couldn't scale %s to 1: %v" , to .Name , err )
183
177
}
@@ -195,7 +189,7 @@ func (s *RecreateDeploymentStrategy) DeployWithAcceptor(from *kapi.ReplicationCo
195
189
// Complete the scale up.
196
190
if to .Spec .Replicas != int32 (desiredReplicas ) {
197
191
fmt .Fprintf (s .out , "--> Scaling %s to %d\n " , to .Name , desiredReplicas )
198
- updatedTo , err := s .scaleAndWait (to , desiredReplicas , s . retryParams , waitParams )
192
+ updatedTo , err := s .scaleAndWait (to , desiredReplicas , recreateTimeout )
199
193
if err != nil {
200
194
return fmt .Errorf ("couldn't scale %s to %d: %v" , to .Name , desiredReplicas , err )
201
195
}
@@ -224,32 +218,48 @@ func (s *RecreateDeploymentStrategy) DeployWithAcceptor(from *kapi.ReplicationCo
224
218
return nil
225
219
}
226
220
227
- func (s * RecreateDeploymentStrategy ) scaleAndWait (deployment * kapi.ReplicationController , replicas int , retry * kubectl. RetryParams , retryParams * kubectl. RetryParams ) (* kapi.ReplicationController , error ) {
221
+ func (s * RecreateDeploymentStrategy ) scaleAndWait (deployment * kapi.ReplicationController , replicas int , retryTimeout time. Duration ) (* kapi.ReplicationController , error ) {
228
222
if int32 (replicas ) == deployment .Spec .Replicas && int32 (replicas ) == deployment .Status .Replicas {
229
223
return deployment , nil
230
224
}
231
- var scaleErr error
232
- err := wait .PollImmediate (1 * time .Second , 30 * time .Second , func () (bool , error ) {
233
- scaleErr = s .scaler .Scale (deployment .Namespace , deployment .Name , uint (replicas ), & kubectl.ScalePrecondition {Size : - 1 , ResourceVersion : "" }, retry , retryParams , kapi .Resource ("replicationcontrollers" ))
234
- if scaleErr == nil {
235
- return true , nil
236
- }
237
- // This error is returned when the lifecycle admission plugin cache is not fully
238
- // synchronized. In that case the scaling should be retried.
239
- //
240
- // FIXME: The error returned from admission should not be forbidden but come-back-later error.
241
- if errors .IsForbidden (scaleErr ) && strings .Contains (scaleErr .Error (), "not yet ready to handle request" ) {
225
+ alreadyScaled := false
226
+ // Scale the replication controller.
227
+ // In case the cache is not fully synced, retry the scaling.
228
+ err := wait .PollImmediate (1 * time .Second , retryTimeout , func () (bool , error ) {
229
+ updateScaleErr := retry .RetryOnConflict (retry .DefaultRetry , func () error {
230
+ curScale , err := s .scaleClient .Scales (deployment .Namespace ).Get (kapi .Resource ("replicationcontrollers" ), deployment .Name )
231
+ if err != nil {
232
+ return err
233
+ }
234
+ if curScale .Status .Replicas == int32 (replicas ) {
235
+ alreadyScaled = true
236
+ return nil
237
+ }
238
+ curScaleCopy := curScale .DeepCopy ()
239
+ curScaleCopy .Spec .Replicas = int32 (replicas )
240
+ _ , scaleErr := s .scaleClient .Scales (deployment .Namespace ).Update (kapi .Resource ("replicationcontrollers" ), curScaleCopy )
241
+ return scaleErr
242
+ })
243
+ // FIXME: The error admission returns here should be 503 (come back later) or similar.
244
+ if errors .IsForbidden (updateScaleErr ) && strings .Contains (updateScaleErr .Error (), "not yet ready to handle request" ) {
242
245
return false , nil
243
246
}
244
- return false , scaleErr
247
+ return true , updateScaleErr
245
248
})
246
- if err == wait .ErrWaitTimeout {
247
- return nil , fmt .Errorf ("%v: %v" , err , scaleErr )
248
- }
249
249
if err != nil {
250
250
return nil , err
251
251
}
252
-
252
+ // Wait for the scale to take effect.
253
+ if ! alreadyScaled {
254
+ // FIXME: This should really be a watch, however the scaler client does not implement the watch interface atm.
255
+ err = wait .PollImmediate (1 * time .Second , retryTimeout , func () (bool , error ) {
256
+ curScale , err := s .scaleClient .Scales (deployment .Namespace ).Get (kapi .Resource ("replicationcontrollers" ), deployment .Name )
257
+ if err != nil {
258
+ return false , err
259
+ }
260
+ return curScale .Status .Replicas == int32 (replicas ), nil
261
+ })
262
+ }
253
263
return s .rcClient .ReplicationControllers (deployment .Namespace ).Get (deployment .Name , metav1.GetOptions {})
254
264
}
255
265
0 commit comments