-
Notifications
You must be signed in to change notification settings - Fork 127
/
pipelinerun.go
136 lines (123 loc) · 5.13 KB
/
pipelinerun.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
Copyright 2020 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package pipelinerun
import (
"context"
"fmt"
signing "github.com/tektoncd/chains/pkg/chains"
"github.com/tektoncd/chains/pkg/chains/objects"
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
"github.com/tektoncd/pipeline/pkg/client/clientset/versioned"
pipelinerunreconciler "github.com/tektoncd/pipeline/pkg/client/injection/reconciler/pipeline/v1beta1/pipelinerun"
listers "github.com/tektoncd/pipeline/pkg/client/listers/pipeline/v1beta1"
"k8s.io/apimachinery/pkg/api/errors"
"knative.dev/pkg/logging"
pkgreconciler "knative.dev/pkg/reconciler"
"knative.dev/pkg/tracker"
)
const (
// SecretPath contains the path to the secrets volume that is mounted in.
SecretPath = "/etc/signing-secrets"
)
type Reconciler struct {
PipelineRunSigner signing.Signer
Pipelineclientset versioned.Interface
TaskRunLister listers.TaskRunLister
Tracker tracker.Interface
}
// Check that our Reconciler implements pipelinerunreconciler.Interface and pipelinerunreconciler.Finalizer
var _ pipelinerunreconciler.Interface = (*Reconciler)(nil)
var _ pipelinerunreconciler.Finalizer = (*Reconciler)(nil)
// ReconcileKind handles a changed or created PipelineRun.
// This is the main entrypoint for chains business logic.
func (r *Reconciler) ReconcileKind(ctx context.Context, pr *v1beta1.PipelineRun) pkgreconciler.Event {
log := logging.FromContext(ctx).With("pipelinerun", fmt.Sprintf("%s/%s", pr.Namespace, pr.Name))
return r.FinalizeKind(logging.WithLogger(ctx, log), pr)
}
// FinalizeKind implements pipelinerunreconciler.Finalizer
// We utilize finalizers to ensure that we get a crack at signing every pipelinerun
// that we see flowing through the system. If we don't add a finalizer, it could
// get cleaned up before we see the final state and sign it.
func (r *Reconciler) FinalizeKind(ctx context.Context, pr *v1beta1.PipelineRun) pkgreconciler.Event {
// Check to make sure the PipelineRun is finished.
if !pr.IsDone() {
logging.FromContext(ctx).Infof("pipelinerun is still running")
return nil
}
pro := objects.NewPipelineRunObject(pr)
// Check to see if it has already been signed.
if signing.Reconciled(pro) {
logging.FromContext(ctx).Infof("pipelinerun has been reconciled")
return nil
}
// Get TaskRun names depending on whether embeddedstatus feature is set or not
var trs []string
if len(pr.Status.ChildReferences) == 0 || len(pr.Status.TaskRuns) > 0 || len(pr.Status.Runs) > 0 {
for trName, ptrs := range pr.Status.TaskRuns {
// TaskRuns within a PipelineRun may not have been finalized yet if the PipelineRun timeout
// has exceeded. Wait to process the PipelineRun on the next update, see
// https://github.com/tektoncd/pipeline/issues/4916
if ptrs.Status == nil || ptrs.Status.CompletionTime == nil {
logging.FromContext(ctx).Infof("taskrun %s within pipelinerun is not yet finalized: embedded status is not complete", trName)
return nil
}
trs = append(trs, trName)
}
} else {
for _, cr := range pr.Status.ChildReferences {
trs = append(trs, cr.Name)
}
}
// Signing both taskruns and pipelineruns causes a race condition when using oci storage
// during the push to the registry. This checks the taskruns to ensure they've been reconciled
// before attempting to sign the pippelinerun.
for _, name := range trs {
tr, err := r.TaskRunLister.TaskRuns(pr.Namespace).Get(name)
if err != nil {
logging.FromContext(ctx).Errorf("Unable to get reconciled status of taskrun %s within pipelinerun", name)
if errors.IsNotFound(err) {
// Since this is an unrecoverable scenario, returning the error would prevent the
// finalizer from being removed, thus preventing the PipelineRun from being deleted.
return nil
}
return err
}
if tr == nil {
logging.FromContext(ctx).Infof("taskrun %s within pipelinerun is not found", name)
return nil
}
if tr.Status.CompletionTime == nil {
logging.FromContext(ctx).Infof("taskrun %s within pipelinerun is not yet finalized: status is not complete", name)
return r.trackTaskRun(tr, pr)
}
reconciled := signing.Reconciled(objects.NewTaskRunObject(tr))
if !reconciled {
logging.FromContext(ctx).Infof("taskrun %s within pipelinerun is not yet reconciled", name)
return r.trackTaskRun(tr, pr)
}
pro.AppendTaskRun(tr)
}
if err := r.PipelineRunSigner.Sign(ctx, pro); err != nil {
return err
}
return nil
}
func (r *Reconciler) trackTaskRun(tr *v1beta1.TaskRun, pr *v1beta1.PipelineRun) error {
ref := tracker.Reference{
APIVersion: "tekton.dev/v1beta1",
Kind: "TaskRun",
Namespace: tr.Namespace,
Name: tr.Name,
}
return r.Tracker.TrackReference(ref, pr)
}