Skip to content

Commit 5e3db73

Browse files
committed
Respect timeout from pr by default
By default we will respect the timeout from the pr as defined by user or the tekton controller. We properly handle exiting on error if there is any timeouts. Fixes #430 Signed-off-by: Chmouel Boudjnah <[email protected]>
1 parent 3b67589 commit 5e3db73

File tree

10 files changed

+48
-21
lines changed

10 files changed

+48
-21
lines changed

config/302-pac-configmap.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,9 @@ data:
4242
# Add extra IPS (ie: 127.0.0.1) or networks (127.0.0.0/16) separated by commas.
4343
bitbucket-cloud-additional-source-ip: ""
4444

45-
# The default time to wait for a pipelineRun
46-
default-pipelinerun-timeout: "2h"
45+
# Global setting for pipelinerun timeout regardless of how the user
46+
# pipelinerun timeout.
47+
# default-pipelinerun-timeout: "2h"
4748

4849
kind: ConfigMap
4950
metadata:

docs/content/docs/install/settings.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,15 @@ There is a few things you can configure through the configmap
4040

4141
The base URL for the [tekton hub](https://github.com/tektoncd/hub/)
4242
API. default to the [public hub](https://hub.tekton.dev/): <https://api.hub.tekton.dev/v1>
43+
44+
* `default-pipelinerun-timeout`
45+
46+
Let specify a global timeout across all pipeline. If you define the value
47+
every PipelineRun running under Pipelines-as-Code
48+
49+
If it hasn't been set the timeout setting ordering will be :
50+
51+
* Picked up from the timeout setting [as
52+
defined](https://tekton.dev/docs/pipelines/pipelineruns/#configuring-a-failure-timeout)
53+
in the `PipelineRun` spec.timeout.
54+
* If it hasn't defined it will use the default tekton controller timeout setting (default: 1 hour).

pkg/adapter/adapter.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,10 @@ func (l listener) handleEvent() http.HandlerFunc {
129129
localRequest := request.Clone(request.Context())
130130

131131
go func() {
132-
s.processEvent(ctx, localRequest, payload)
132+
err := s.processEvent(ctx, localRequest, payload)
133+
if err != nil {
134+
l.run.Clients.Log.Errorf("an error occurred: %v", err)
135+
}
133136
}()
134137

135138
l.writeResponse(response, http.StatusAccepted, "accepted")

pkg/adapter/sinker.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ type sinker struct {
2020
event *info.Event
2121
}
2222

23-
func (s *sinker) processEvent(ctx context.Context, request *http.Request, payload []byte) {
23+
func (s *sinker) processEvent(ctx context.Context, request *http.Request, payload []byte) error {
2424
var err error
2525
s.event, err = s.vcx.ParsePayload(ctx, s.run, request, string(payload))
2626
if err != nil {
2727
s.run.Clients.Log.Errorf("failed to parse event: %v", err)
28-
return
28+
return err
2929
}
3030
s.event.Request = &info.Request{
3131
Header: request.Header,
@@ -44,4 +44,5 @@ func (s *sinker) processEvent(ctx context.Context, request *http.Request, payloa
4444
s.run.Clients.Log.Errorf("Cannot create status: %s %s", err, createStatusErr)
4545
}
4646
}
47+
return err
4748
}

pkg/kubeinteraction/wait.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import (
1515

1616
const (
1717
interval = 1 * time.Second
18-
timeout = 120 * time.Minute
1918
)
2019

2120
type ConditionAccessorFn func(ca knativeapi.ConditionAccessor) (bool, error)
@@ -83,11 +82,11 @@ func PipelineRunSucceed(name string) ConditionAccessorFn {
8382
return Succeed(name)
8483
}
8584

86-
func PollImmediateWithContext(ctx context.Context, fn func() (bool, error)) error {
87-
return wait.PollImmediate(interval, timeout, func() (bool, error) {
85+
func PollImmediateWithContext(ctx context.Context, pollTimeout time.Duration, fn func() (bool, error)) error {
86+
return wait.PollImmediate(interval, pollTimeout, func() (bool, error) {
8887
select {
8988
case <-ctx.Done():
90-
return true, ctx.Err()
89+
return true, fmt.Errorf("polling timed out, pipelinerun has exceeded its timeout: %v", pollTimeout)
9190
default:
9291
}
9392
return fn()
@@ -101,7 +100,8 @@ func PollImmediateWithContext(ctx context.Context, fn func() (bool, error)) erro
101100
func waitForPipelineRunState(ctx context.Context, tektonbeta1 tektonv1beta1client.TektonV1beta1Interface, pr *v1beta1.PipelineRun, polltimeout time.Duration, inState ConditionAccessorFn) error {
102101
ctx, cancel := context.WithTimeout(ctx, polltimeout)
103102
defer cancel()
104-
return PollImmediateWithContext(ctx, func() (bool, error) {
103+
104+
return PollImmediateWithContext(ctx, polltimeout, func() (bool, error) {
105105
r, err := tektonbeta1.PipelineRuns(pr.Namespace).Get(ctx, pr.Name, metav1.GetOptions{})
106106
if err != nil {
107107
return true, err

pkg/params/info/pac.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ type PacOpts struct {
1717
TektonDashboardURL string
1818
HubURL string
1919
RemoteTasks bool
20-
DefaultPipelineRunTimeout time.Duration
20+
DefaultPipelineRunTimeout *time.Duration
2121

2222
// bitbucket cloud specific fields
2323
BitbucketCloudCheckSourceIP bool

pkg/params/run.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ func (r *Run) GetConfigFromConfigMap(ctx context.Context) error {
3333
if ns == "" {
3434
return fmt.Errorf("failed to find pipelines-as-code installation namespace")
3535
}
36+
// TODO: move this to kubeinteractions class so we can add unittests.
3637
cfg, err := r.Clients.Kube.CoreV1().ConfigMaps(ns).Get(ctx, info.PACConfigmapName, v1.GetOptions{})
3738
if err != nil {
3839
return err
@@ -72,14 +73,10 @@ func (r *Run) GetConfigFromConfigMap(ctx context.Context) error {
7273
if timeout, ok := cfg.Data["default-pipelinerun-timeout"]; ok {
7374
parsedTimeout, err := time.ParseDuration(timeout)
7475
if err != nil {
75-
r.Clients.Log.Infof("failed to parse default-pipelinerun-timeout: %s, using %v as default timeout",
76-
cfg.Data["default-pipelinerun-timeout"], info.DefaultPipelineRunTimeout)
77-
r.Info.Pac.DefaultPipelineRunTimeout = info.DefaultPipelineRunTimeout
76+
r.Clients.Log.Errorf("failed to parse default-pipelinerun-timeout: %s", cfg.Data["default-pipelinerun-timeout"])
7877
} else {
79-
r.Info.Pac.DefaultPipelineRunTimeout = parsedTimeout
78+
r.Info.Pac.DefaultPipelineRunTimeout = &parsedTimeout
8079
}
81-
} else {
82-
r.Info.Pac.DefaultPipelineRunTimeout = info.DefaultPipelineRunTimeout
8380
}
8481

8582
if check, ok := cfg.Data["bitbucket-cloud-check-source-ip"]; ok {

pkg/pipelineascode/pipelineascode.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"path/filepath"
77
"strconv"
8+
"time"
89

910
apipac "github.com/openshift-pipelines/pipelines-as-code/pkg/apis/pipelinesascode"
1011
"github.com/openshift-pipelines/pipelines-as-code/pkg/formatting"
@@ -173,9 +174,18 @@ func Run(ctx context.Context, cs *params.Run, providerintf provider.Interface, k
173174
return fmt.Errorf("cannot create a in_progress status on the provider platform: %w", err)
174175
}
175176

177+
var duration time.Duration
178+
if cs.Info.Pac.DefaultPipelineRunTimeout != nil {
179+
duration = *cs.Info.Pac.DefaultPipelineRunTimeout
180+
} else {
181+
// Tekton Pipeline controller should always set this value.
182+
duration = pr.Spec.Timeout.Duration + 1*time.Minute
183+
}
176184
cs.Clients.Log.Infof("Waiting for PipelineRun %s/%s to Succeed in a maximum time of %s minutes",
177-
pr.Namespace, pr.Name, formatting.HumanDuration(cs.Info.Pac.DefaultPipelineRunTimeout))
178-
if err := k8int.WaitForPipelineRunSucceed(ctx, cs.Clients.Tekton.TektonV1beta1(), pr, cs.Info.Pac.DefaultPipelineRunTimeout); err != nil {
185+
pr.Namespace, pr.Name, formatting.HumanDuration(duration))
186+
if err := k8int.WaitForPipelineRunSucceed(ctx, cs.Clients.Tekton.TektonV1beta1(), pr, duration); err != nil {
187+
// if we have a timeout from the pipeline run, we would not know it. We would need to get the PR status to know.
188+
// maybe something to improve in the future.
179189
return fmt.Errorf("pipelinerun %s in namespace %s has a failed status: %w",
180190
pipelineRun.GetGenerateName(), repo.GetNamespace(), err)
181191
}

pkg/pipelineascode/pipelinesascode_github_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"net/http"
1111
"strings"
1212
"testing"
13+
"time"
1314

1415
"github.com/google/go-github/v43/github"
1516
"github.com/openshift-pipelines/pipelines-as-code/pkg/apis/pipelinesascode/v1alpha1"
@@ -332,6 +333,7 @@ func TestRun(t *testing.T) {
332333
stdata, _ := testclient.SeedTestData(t, ctx, tdata)
333334
tdc := testDynamic.Options{}
334335
dc, _ := tdc.Client()
336+
duration, _ := time.ParseDuration("0h0m5s")
335337
cs := &params.Run{
336338
Clients: clients.Clients{
337339
PipelineAsCode: stdata.PipelineAsCode,
@@ -343,7 +345,8 @@ func TestRun(t *testing.T) {
343345
},
344346
Info: info.Info{
345347
Pac: &info.PacOpts{
346-
SecretAutoCreation: true,
348+
SecretAutoCreation: true,
349+
DefaultPipelineRunTimeout: &duration,
347350
},
348351
},
349352
}

test/pkg/wait/wait.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ type Opts struct {
2323
func UntilRepositoryUpdated(ctx context.Context, clients clients.Clients, opts Opts) error {
2424
ctx, cancel := context.WithTimeout(ctx, opts.PollTimeout)
2525
defer cancel()
26-
return kubeinteraction.PollImmediateWithContext(ctx, func() (bool, error) {
26+
return kubeinteraction.PollImmediateWithContext(ctx, opts.PollTimeout, func() (bool, error) {
2727
clients.PipelineAsCode.PipelinesascodeV1alpha1().Repositories(opts.Namespace)
2828
r, err := clients.PipelineAsCode.PipelinesascodeV1alpha1().Repositories(opts.Namespace).Get(ctx, opts.RepoName,
2929
metav1.GetOptions{})

0 commit comments

Comments
 (0)