Skip to content

Commit b6fb30d

Browse files
committed
[TEP-0100] Add new updatePipelineRunStatusFromChildRefs function
And of course, this is part of https://github.com/tektoncd/community/blob/main/teps/0100-embedded-taskruns-and-runs-status-in-pipelineruns.md, building on a pile of other PRs (tektoncd#4705, tektoncd#4734, tektoncd#4753, tektoncd#4757). This adds a new function to `pkg/reconciler/pipelinerun/pipelinerun.go`, specifically for updating `pr.Status.ChildReferences` during reconciliation. It's analogous to the existing `updatePipelineRunStatusFromTaskRuns` and `updatePipelineRunStatusFromRuns` functions. This PR doesn't actually call the new function - behavior is exactly the same. But it adds the new function, along with other functions it depends on. In the final step of the implementation, these other functions will also be used in `...FromTaskRuns` and/or `...FromRuns`. I also reworked `pkg/reconciler/pipelinerun/pipelinerun_updatestatus_test.go` to improve its test fixtures, so that they're easier to reuse and instantiated via YAML parsing as much as possible. Signed-off-by: Andrew Bayer <andrew.bayer@gmail.com>
1 parent 8859310 commit b6fb30d

File tree

3 files changed

+849
-330
lines changed

3 files changed

+849
-330
lines changed

pkg/apis/pipeline/v1beta1/pipelinerun_types.go

+15
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,21 @@ type ChildStatusReference struct {
422422
WhenExpressions []WhenExpression `json:"whenExpressions,omitempty"`
423423
}
424424

425+
// GetConditionChecks returns a map representation of this ChildStatusReference's ConditionChecks, in the same form
426+
// as PipelineRunTaskRunStatus.ConditionChecks.
427+
func (cr ChildStatusReference) GetConditionChecks() map[string]*PipelineRunConditionCheckStatus {
428+
if len(cr.ConditionChecks) == 0 {
429+
return nil
430+
}
431+
ccMap := make(map[string]*PipelineRunConditionCheckStatus)
432+
433+
for _, cc := range cr.ConditionChecks {
434+
ccMap[cc.ConditionCheckName] = &cc.PipelineRunConditionCheckStatus
435+
}
436+
437+
return ccMap
438+
}
439+
425440
// PipelineRunStatusFields holds the fields of PipelineRunStatus' status.
426441
// This is defined separately and inlined so that other types can readily
427442
// consume these fields via duck typing.

pkg/reconciler/pipelinerun/pipelinerun.go

+172
Original file line numberDiff line numberDiff line change
@@ -1196,6 +1196,53 @@ func (c *Reconciler) updatePipelineRunStatusFromInformer(ctx context.Context, pr
11961196
return nil
11971197
}
11981198

1199+
// filterTaskRunsForPipelineRun returns TaskRuns owned by the PipelineRun and their condition checks
1200+
func filterTaskRunsForPipelineRun(logger *zap.SugaredLogger, pr *v1beta1.PipelineRun, trs []*v1beta1.TaskRun) ([]*v1beta1.TaskRun, map[string][]*v1beta1.TaskRun) {
1201+
var normalTaskRuns []*v1beta1.TaskRun
1202+
conditionTaskRuns := make(map[string][]*v1beta1.TaskRun)
1203+
1204+
for _, tr := range trs {
1205+
// Only process TaskRuns that are owned by this PipelineRun.
1206+
// This skips TaskRuns that are indirectly created by the PipelineRun (e.g. by custom tasks).
1207+
if len(tr.OwnerReferences) < 1 || tr.OwnerReferences[0].UID != pr.ObjectMeta.UID {
1208+
logger.Debugf("Found a TaskRun %s that is not owned by this PipelineRun", tr.Name)
1209+
continue
1210+
}
1211+
lbls := tr.GetLabels()
1212+
pipelineTaskName := lbls[pipeline.PipelineTaskLabelKey]
1213+
if _, ok := lbls[pipeline.ConditionCheckKey]; ok {
1214+
// Save condition for looping over them after this
1215+
if _, ok := conditionTaskRuns[pipelineTaskName]; !ok {
1216+
// If it's the first condition taskrun, initialise the slice
1217+
conditionTaskRuns[pipelineTaskName] = []*v1beta1.TaskRun{}
1218+
}
1219+
conditionTaskRuns[pipelineTaskName] = append(conditionTaskRuns[pipelineTaskName], tr)
1220+
} else {
1221+
normalTaskRuns = append(normalTaskRuns, tr)
1222+
}
1223+
}
1224+
1225+
return normalTaskRuns, conditionTaskRuns
1226+
}
1227+
1228+
// filterRunsForPipelineRun filters the given slice of Runs, returning only those owned by the given PipelineRun.
1229+
func filterRunsForPipelineRun(logger *zap.SugaredLogger, pr *v1beta1.PipelineRun, runs []*v1alpha1.Run) []*v1alpha1.Run {
1230+
var runsToInclude []*v1alpha1.Run
1231+
1232+
// Loop over all the Runs associated to Tasks
1233+
for _, run := range runs {
1234+
// Only process Runs that are owned by this PipelineRun.
1235+
// This skips Runs that are indirectly created by the PipelineRun (e.g. by custom tasks).
1236+
if len(run.OwnerReferences) < 1 || run.OwnerReferences[0].UID != pr.ObjectMeta.UID {
1237+
logger.Debugf("Found a Run %s that is not owned by this PipelineRun", run.Name)
1238+
continue
1239+
}
1240+
runsToInclude = append(runsToInclude, run)
1241+
}
1242+
1243+
return runsToInclude
1244+
}
1245+
11991246
func updatePipelineRunStatusFromTaskRuns(logger *zap.SugaredLogger, pr *v1beta1.PipelineRun, trs []*v1beta1.TaskRun) {
12001247
// If no TaskRun was found, nothing to be done. We never remove taskruns from the status
12011248
if trs == nil || len(trs) == 0 {
@@ -1286,6 +1333,38 @@ func updatePipelineRunStatusFromTaskRuns(logger *zap.SugaredLogger, pr *v1beta1.
12861333
}
12871334
}
12881335

1336+
// getNewConditionChecksForTaskRun returns a map of condition task name to condition check status for each condition TaskRun
1337+
// provided which isn't already present in the existing map of condition checks.
1338+
func getNewConditionChecksForTaskRun(logger *zap.SugaredLogger, existingChecks map[string]*v1beta1.PipelineRunConditionCheckStatus,
1339+
actualConditionTaskRuns []*v1beta1.TaskRun) map[string]*v1beta1.PipelineRunConditionCheckStatus {
1340+
// If we don't have any condition task runs to process, just return nil.
1341+
if len(actualConditionTaskRuns) == 0 {
1342+
return nil
1343+
}
1344+
1345+
newChecks := make(map[string]*v1beta1.PipelineRunConditionCheckStatus)
1346+
1347+
for i, foundTaskRun := range actualConditionTaskRuns {
1348+
lbls := foundTaskRun.GetLabels()
1349+
if _, ok := existingChecks[foundTaskRun.Name]; !ok {
1350+
// The condition check was not found, so we need to add it
1351+
// We only add the condition name, the status can now be gathered by the
1352+
// normal reconcile process
1353+
if conditionName, ok := lbls[pipeline.ConditionNameKey]; ok {
1354+
newChecks[foundTaskRun.Name] = &v1beta1.PipelineRunConditionCheckStatus{
1355+
ConditionName: fmt.Sprintf("%s-%s", conditionName, strconv.Itoa(i)),
1356+
}
1357+
} else {
1358+
// The condition name label is missing, so we cannot recover this
1359+
logger.Warnf("found an orphaned condition taskrun %#v with missing %s label",
1360+
foundTaskRun, pipeline.ConditionNameKey)
1361+
}
1362+
}
1363+
}
1364+
1365+
return newChecks
1366+
}
1367+
12891368
func updatePipelineRunStatusFromRuns(logger *zap.SugaredLogger, pr *v1beta1.PipelineRun, runs []*v1alpha1.Run) {
12901369
// If no Run was found, nothing to be done. We never remove runs from the status
12911370
if runs == nil || len(runs) == 0 {
@@ -1313,3 +1392,96 @@ func updatePipelineRunStatusFromRuns(logger *zap.SugaredLogger, pr *v1beta1.Pipe
13131392
}
13141393
}
13151394
}
1395+
1396+
func updatePipelineRunStatusFromChildRefs(logger *zap.SugaredLogger, pr *v1beta1.PipelineRun, trs []*v1beta1.TaskRun, runs []*v1alpha1.Run) {
1397+
// If no TaskRun or Run was found, nothing to be done. We never remove child references from the status.
1398+
// We do still return an empty map of TaskRun/Run names keyed by PipelineTask name for later functions.
1399+
if len(trs) == 0 && len(runs) == 0 {
1400+
return
1401+
}
1402+
1403+
// Map PipelineTask names to TaskRun child references that were already in the status
1404+
childRefByPipelineTask := make(map[string]*v1beta1.ChildStatusReference)
1405+
1406+
for i := range pr.Status.ChildReferences {
1407+
childRefByPipelineTask[pr.Status.ChildReferences[i].PipelineTaskName] = &pr.Status.ChildReferences[i]
1408+
}
1409+
1410+
taskRuns, conditionTaskRuns := filterTaskRunsForPipelineRun(logger, pr, trs)
1411+
1412+
// Loop over all the TaskRuns associated to Tasks
1413+
for _, tr := range taskRuns {
1414+
lbls := tr.GetLabels()
1415+
pipelineTaskName := lbls[pipeline.PipelineTaskLabelKey]
1416+
1417+
if _, ok := childRefByPipelineTask[pipelineTaskName]; !ok {
1418+
// This tr was missing from the status.
1419+
// Add it without conditions, which are handled in the next loop
1420+
logger.Infof("Found a TaskRun %s that was missing from the PipelineRun status", tr.Name)
1421+
1422+
// Since this was recovered now, add it to the map, or it might be overwritten
1423+
childRefByPipelineTask[pipelineTaskName] = &v1beta1.ChildStatusReference{
1424+
TypeMeta: runtime.TypeMeta{
1425+
APIVersion: v1beta1.SchemeGroupVersion.String(),
1426+
Kind: "TaskRun",
1427+
},
1428+
Name: tr.Name,
1429+
PipelineTaskName: pipelineTaskName,
1430+
}
1431+
}
1432+
}
1433+
1434+
// Loop over all the Runs associated to Tasks
1435+
for _, r := range filterRunsForPipelineRun(logger, pr, runs) {
1436+
lbls := r.GetLabels()
1437+
pipelineTaskName := lbls[pipeline.PipelineTaskLabelKey]
1438+
1439+
if _, ok := childRefByPipelineTask[pipelineTaskName]; !ok {
1440+
// This run was missing from the status.
1441+
// Add it without conditions, which are handled in the next loop
1442+
logger.Infof("Found a Run %s that was missing from the PipelineRun status", r.Name)
1443+
1444+
// Since this was recovered now, add it to the map, or it might be overwritten
1445+
childRefByPipelineTask[pipelineTaskName] = &v1beta1.ChildStatusReference{
1446+
TypeMeta: runtime.TypeMeta{
1447+
APIVersion: v1alpha1.SchemeGroupVersion.String(),
1448+
Kind: "Run",
1449+
},
1450+
Name: r.Name,
1451+
PipelineTaskName: pipelineTaskName,
1452+
}
1453+
}
1454+
}
1455+
1456+
// Then loop by pipelinetask name over all the TaskRuns associated to Conditions
1457+
for pipelineTaskName, actualConditionTaskRuns := range conditionTaskRuns {
1458+
// GetTaskRunName will look in first ChildReferences and then TaskRuns to see if there's already a TaskRun name
1459+
// for this pipelineTaskName, and if not, it will generate one.
1460+
taskRunName := resources.GetTaskRunName(pr.Status.TaskRuns, pr.Status.ChildReferences, pipelineTaskName, pr.Name)
1461+
if _, ok := childRefByPipelineTask[pipelineTaskName]; !ok {
1462+
childRefByPipelineTask[pipelineTaskName] = &v1beta1.ChildStatusReference{
1463+
TypeMeta: runtime.TypeMeta{
1464+
APIVersion: v1beta1.SchemeGroupVersion.String(),
1465+
Kind: "TaskRun",
1466+
},
1467+
Name: taskRunName,
1468+
PipelineTaskName: pipelineTaskName,
1469+
}
1470+
}
1471+
1472+
for k, v := range getNewConditionChecksForTaskRun(logger, childRefByPipelineTask[pipelineTaskName].GetConditionChecks(), actualConditionTaskRuns) {
1473+
// Just append any new condition checks to the relevant ChildStatusReference.ConditionChecks.
1474+
childRefByPipelineTask[pipelineTaskName].ConditionChecks = append(childRefByPipelineTask[pipelineTaskName].ConditionChecks,
1475+
&v1beta1.PipelineRunChildConditionCheckStatus{
1476+
PipelineRunConditionCheckStatus: *v,
1477+
ConditionCheckName: k,
1478+
})
1479+
}
1480+
}
1481+
1482+
var newChildRefs []v1beta1.ChildStatusReference
1483+
for k := range childRefByPipelineTask {
1484+
newChildRefs = append(newChildRefs, *childRefByPipelineTask[k])
1485+
}
1486+
pr.Status.ChildReferences = newChildRefs
1487+
}

0 commit comments

Comments
 (0)