Skip to content

Commit 30a00dc

Browse files
author
OpenShift Bot
authored
Merge pull request #11484 from mfojtik/set-deploy-hooks-timeout
Merged by openshift-bot
2 parents 1197998 + 95fafba commit 30a00dc

File tree

2 files changed

+182
-120
lines changed

2 files changed

+182
-120
lines changed

pkg/deploy/strategy/support/lifecycle.go

+48-65
Original file line numberDiff line numberDiff line change
@@ -35,39 +35,38 @@ const HookContainerName = "lifecycle"
3535

3636
// HookExecutor executes a deployment lifecycle hook.
3737
type HookExecutor struct {
38-
// podClient provides access to pods.
39-
podClient HookExecutorPodClient
38+
// pods provides client to pods
39+
pods kclient.PodsNamespacer
4040
// tags allows setting image stream tags
4141
tags client.ImageStreamTagsNamespacer
4242
// out is where hook pod logs should be written to.
4343
out io.Writer
44-
// podLogStream provides a reader for a pod's logs.
45-
podLogStream func(namespace, name string, opts *kapi.PodLogOptions) (io.ReadCloser, error)
4644
// decoder is used for encoding/decoding.
4745
decoder runtime.Decoder
4846
// recorder is used to emit events from hooks
4947
events kclient.EventNamespacer
48+
// getPodLogs knows how to get logs from a pod and is used for testing
49+
getPodLogs func(*kapi.Pod) (io.ReadCloser, error)
5050
}
5151

5252
// NewHookExecutor makes a HookExecutor from a client.
53-
func NewHookExecutor(client kclient.PodsNamespacer, tags client.ImageStreamTagsNamespacer, events kclient.EventNamespacer, out io.Writer, decoder runtime.Decoder) *HookExecutor {
54-
return &HookExecutor{
55-
tags: tags,
56-
events: events,
57-
podClient: &HookExecutorPodClientImpl{
58-
CreatePodFunc: func(namespace string, pod *kapi.Pod) (*kapi.Pod, error) {
59-
return client.Pods(namespace).Create(pod)
60-
},
61-
PodWatchFunc: func(namespace, name, resourceVersion string, stopChannel chan struct{}) func() *kapi.Pod {
62-
return NewPodWatch(client, namespace, name, resourceVersion, stopChannel)
63-
},
64-
},
65-
podLogStream: func(namespace, name string, opts *kapi.PodLogOptions) (io.ReadCloser, error) {
66-
return client.Pods(namespace).GetLogs(name, opts).Stream()
67-
},
53+
func NewHookExecutor(pods kclient.PodsNamespacer, tags client.ImageStreamTagsNamespacer, events kclient.EventNamespacer, out io.Writer, decoder runtime.Decoder) *HookExecutor {
54+
executor := &HookExecutor{
55+
tags: tags,
56+
pods: pods,
57+
events: events,
6858
out: out,
6959
decoder: decoder,
7060
}
61+
executor.getPodLogs = func(pod *kapi.Pod) (io.ReadCloser, error) {
62+
opts := &kapi.PodLogOptions{
63+
Container: HookContainerName,
64+
Follow: true,
65+
Timestamps: false,
66+
}
67+
return executor.pods.Pods(pod.Namespace).GetLogs(pod.Name, opts).Stream()
68+
}
69+
return executor
7170
}
7271

7372
// Execute executes hook in the context of deployment. The suffix is used to
@@ -83,26 +82,30 @@ func (e *HookExecutor) Execute(hook *deployapi.LifecycleHook, deployment *kapi.R
8382
tagEventMessages = append(tagEventMessages, fmt.Sprintf("image %q as %q", image, t.To.Name))
8483
}
8584
}
86-
strategyutil.RecordConfigEvent(e.events, deployment, e.decoder, kapi.EventTypeNormal, "Started", fmt.Sprintf("Running %s-hook (TagImages) %s for deployment %s/%s", label, strings.Join(tagEventMessages, ","), deployment.Namespace, deployment.Name))
85+
strategyutil.RecordConfigEvent(e.events, deployment, e.decoder, kapi.EventTypeNormal, "Started",
86+
fmt.Sprintf("Running %s-hook (TagImages) %s for deployment %s/%s", label, strings.Join(tagEventMessages, ","), deployment.Namespace, deployment.Name))
8787
err = e.tagImages(hook, deployment, suffix, label)
8888
case hook.ExecNewPod != nil:
89-
strategyutil.RecordConfigEvent(e.events, deployment, e.decoder, kapi.EventTypeNormal, "Started", fmt.Sprintf("Running %s-hook (%q) for deployment %s/%s", label, strings.Join(hook.ExecNewPod.Command, " "), deployment.Namespace, deployment.Name))
89+
strategyutil.RecordConfigEvent(e.events, deployment, e.decoder, kapi.EventTypeNormal, "Started",
90+
fmt.Sprintf("Running %s-hook (%q) for deployment %s/%s", label, strings.Join(hook.ExecNewPod.Command, " "), deployment.Namespace, deployment.Name))
9091
err = e.executeExecNewPod(hook, deployment, suffix, label)
9192
}
9293

9394
if err == nil {
94-
strategyutil.RecordConfigEvent(e.events, deployment, e.decoder, kapi.EventTypeNormal, "Completed", fmt.Sprintf("The %s-hook for deployment %s/%s completed successfully", label, deployment.Namespace, deployment.Name))
95+
strategyutil.RecordConfigEvent(e.events, deployment, e.decoder, kapi.EventTypeNormal, "Completed",
96+
fmt.Sprintf("The %s-hook for deployment %s/%s completed successfully", label, deployment.Namespace, deployment.Name))
9597
return nil
9698
}
9799

98100
// Retry failures are treated the same as Abort.
99101
switch hook.FailurePolicy {
100102
case deployapi.LifecycleHookFailurePolicyAbort, deployapi.LifecycleHookFailurePolicyRetry:
101-
strategyutil.RecordConfigEvent(e.events, deployment, e.decoder, kapi.EventTypeWarning, "Failed", fmt.Sprintf("The %s-hook failed: %v, aborting deployment %s/%s", label, err, deployment.Namespace, deployment.Name))
103+
strategyutil.RecordConfigEvent(e.events, deployment, e.decoder, kapi.EventTypeWarning, "Failed",
104+
fmt.Sprintf("The %s-hook failed: %v, aborting deployment %s/%s", label, err, deployment.Namespace, deployment.Name))
102105
return fmt.Errorf("the %s hook failed: %v, aborting deployment: %s/%s", label, err, deployment.Namespace, deployment.Name)
103106
case deployapi.LifecycleHookFailurePolicyIgnore:
104-
strategyutil.RecordConfigEvent(e.events, deployment, e.decoder, kapi.EventTypeWarning, "Failed", fmt.Sprintf("The %s-hook failed: %v (ignore), deployment %s/%s will continue", label, err, deployment.Namespace, deployment.Name))
105-
fmt.Fprintf(e.out, "the %s hook failed: %v (ignore), deployment %s/%s will continue", label, err, deployment.Namespace, deployment.Name)
107+
strategyutil.RecordConfigEvent(e.events, deployment, e.decoder, kapi.EventTypeWarning, "Failed",
108+
fmt.Sprintf("The %s-hook failed: %v (ignore), deployment %s/%s will continue", label, err, deployment.Namespace, deployment.Name))
106109
return nil
107110
default:
108111
return err
@@ -170,8 +173,13 @@ func (e *HookExecutor) executeExecNewPod(hook *deployapi.LifecycleHook, deployme
170173
return err
171174
}
172175

176+
deployerPod, err := e.pods.Pods(deployment.Namespace).Get(deployutil.DeployerPodNameForDeployment(deployment.Name))
177+
if err != nil {
178+
return err
179+
}
180+
173181
// Build a pod spec from the hook config and deployment
174-
podSpec, err := makeHookPod(hook, deployment, &config.Spec.Strategy, suffix)
182+
podSpec, err := makeHookPod(hook, deployment, deployerPod, &config.Spec.Strategy, suffix)
175183
if err != nil {
176184
return err
177185
}
@@ -181,7 +189,7 @@ func (e *HookExecutor) executeExecNewPod(hook *deployapi.LifecycleHook, deployme
181189
completed, created := false, false
182190

183191
// Try to create the pod.
184-
pod, err := e.podClient.CreatePod(deployment.Namespace, podSpec)
192+
pod, err := e.pods.Pods(deployment.Namespace).Create(podSpec)
185193
if err != nil {
186194
if !kerrors.IsAlreadyExists(err) {
187195
return fmt.Errorf("couldn't create lifecycle pod for %s: %v", deployment.Name, err)
@@ -196,7 +204,7 @@ func (e *HookExecutor) executeExecNewPod(hook *deployapi.LifecycleHook, deployme
196204

197205
stopChannel := make(chan struct{})
198206
defer close(stopChannel)
199-
nextPod := e.podClient.PodWatch(pod.Namespace, pod.Name, pod.ResourceVersion, stopChannel)
207+
nextPod := NewPodWatch(e.pods.Pods(pod.Namespace), pod.Namespace, pod.Name, pod.ResourceVersion, stopChannel)
200208

201209
// Wait for the hook pod to reach a terminal phase. Start reading logs as
202210
// soon as the pod enters a usable phase.
@@ -264,12 +272,7 @@ waitLoop:
264272
// done.
265273
func (e *HookExecutor) readPodLogs(pod *kapi.Pod, wg *sync.WaitGroup) {
266274
defer wg.Done()
267-
opts := &kapi.PodLogOptions{
268-
Container: HookContainerName,
269-
Follow: true,
270-
Timestamps: false,
271-
}
272-
logStream, err := e.podLogStream(pod.Namespace, pod.Name, opts)
275+
logStream, err := e.getPodLogs(pod)
273276
if err != nil || logStream == nil {
274277
fmt.Fprintf(e.out, "warning: Unable to retrieve hook logs from %s: %v\n", pod.Name, err)
275278
return
@@ -282,7 +285,7 @@ func (e *HookExecutor) readPodLogs(pod *kapi.Pod, wg *sync.WaitGroup) {
282285
}
283286

284287
// makeHookPod makes a pod spec from a hook and deployment.
285-
func makeHookPod(hook *deployapi.LifecycleHook, deployment *kapi.ReplicationController, strategy *deployapi.DeploymentStrategy, suffix string) (*kapi.Pod, error) {
288+
func makeHookPod(hook *deployapi.LifecycleHook, deployment *kapi.ReplicationController, deployerPod *kapi.Pod, strategy *deployapi.DeploymentStrategy, suffix string) (*kapi.Pod, error) {
286289
exec := hook.ExecNewPod
287290
var baseContainer *kapi.Container
288291
for _, container := range deployment.Spec.Template.Spec.Containers {
@@ -318,7 +321,7 @@ func makeHookPod(hook *deployapi.LifecycleHook, deployment *kapi.ReplicationCont
318321
}
319322

320323
// Assigning to a variable since its address is required
321-
maxDeploymentDurationSeconds := deployapi.MaxDeploymentDurationSeconds
324+
maxDeploymentDurationSeconds := deployapi.MaxDeploymentDurationSeconds - int64(time.Since(deployerPod.Status.StartTime.Time).Seconds())
322325

323326
// Let the kubelet manage retries if requested
324327
restartPolicy := kapi.RestartPolicyNever
@@ -405,40 +408,20 @@ func canRetryReading(pod *kapi.Pod, restarts int32) (bool, int32) {
405408
return pod.Spec.RestartPolicy == kapi.RestartPolicyOnFailure && restartCount > restarts, restartCount
406409
}
407410

408-
// HookExecutorPodClient abstracts access to pods.
409-
type HookExecutorPodClient interface {
410-
CreatePod(namespace string, pod *kapi.Pod) (*kapi.Pod, error)
411-
PodWatch(namespace, name, resourceVersion string, stopChannel chan struct{}) func() *kapi.Pod
412-
}
413-
414-
// HookExecutorPodClientImpl is a pluggable HookExecutorPodClient.
415-
type HookExecutorPodClientImpl struct {
416-
CreatePodFunc func(namespace string, pod *kapi.Pod) (*kapi.Pod, error)
417-
PodWatchFunc func(namespace, name, resourceVersion string, stopChannel chan struct{}) func() *kapi.Pod
418-
}
419-
420-
func (i *HookExecutorPodClientImpl) CreatePod(namespace string, pod *kapi.Pod) (*kapi.Pod, error) {
421-
return i.CreatePodFunc(namespace, pod)
422-
}
423-
424-
func (i *HookExecutorPodClientImpl) PodWatch(namespace, name, resourceVersion string, stopChannel chan struct{}) func() *kapi.Pod {
425-
return i.PodWatchFunc(namespace, name, resourceVersion, stopChannel)
426-
}
427-
428411
// NewPodWatch creates a pod watching function which is backed by a
429412
// FIFO/reflector pair. This avoids managing watches directly.
430413
// A stop channel to close the watch's reflector is also returned.
431414
// It is the caller's responsibility to defer closing the stop channel to prevent leaking resources.
432-
func NewPodWatch(client kclient.PodsNamespacer, namespace, name, resourceVersion string, stopChannel chan struct{}) func() *kapi.Pod {
415+
func NewPodWatch(client kclient.PodInterface, namespace, name, resourceVersion string, stopChannel chan struct{}) func() *kapi.Pod {
433416
fieldSelector := fields.OneTermEqualSelector("metadata.name", name)
434417
podLW := &cache.ListWatch{
435418
ListFunc: func(options kapi.ListOptions) (runtime.Object, error) {
436-
opts := kapi.ListOptions{FieldSelector: fieldSelector}
437-
return client.Pods(namespace).List(opts)
419+
options.FieldSelector = fieldSelector
420+
return client.List(options)
438421
},
439422
WatchFunc: func(options kapi.ListOptions) (watch.Interface, error) {
440-
opts := kapi.ListOptions{FieldSelector: fieldSelector, ResourceVersion: options.ResourceVersion}
441-
return client.Pods(namespace).Watch(opts)
423+
options.FieldSelector = fieldSelector
424+
return client.Watch(options)
442425
},
443426
}
444427

@@ -472,12 +455,12 @@ func NewAcceptNewlyObservedReadyPods(
472455
store := cache.NewStore(cache.MetaNamespaceKeyFunc)
473456
lw := &cache.ListWatch{
474457
ListFunc: func(options kapi.ListOptions) (runtime.Object, error) {
475-
opts := kapi.ListOptions{LabelSelector: selector}
476-
return kclient.Pods(deployment.Namespace).List(opts)
458+
options.LabelSelector = selector
459+
return kclient.Pods(deployment.Namespace).List(options)
477460
},
478461
WatchFunc: func(options kapi.ListOptions) (watch.Interface, error) {
479-
opts := kapi.ListOptions{LabelSelector: selector, ResourceVersion: options.ResourceVersion}
480-
return kclient.Pods(deployment.Namespace).Watch(opts)
462+
options.LabelSelector = selector
463+
return kclient.Pods(deployment.Namespace).Watch(options)
481464
},
482465
}
483466
stop := make(chan struct{})

0 commit comments

Comments
 (0)