Skip to content

Commit ca1435d

Browse files
committed
Introduce InternalTektonResultType as a ResultType
In light of tektoncd#3087 the need for a ResultType that is not exposed as a TaskRunResult or PipelineResourceResult arises. In tektoncd#3087, a Step can emit a result indicating a Step timeout has occurred. This is a result that should not be exposed hence the need for a new ResultType called InternalTektonResultType. This commit ensures results of this type are filtered out. Introducing an InternalTektonResultType ensures a future proof solution to internal results that should not be exposed. Aside from the example in tektoncd#3087, a present candidate is the result written out by a Step containing a "StartedAt" key. Currently this result is filtered out with a specific function. Marking it as an InternalTektonResultTypes now allows for this result to automatically be filtered out.
1 parent fb296e6 commit ca1435d

File tree

6 files changed

+439
-398
lines changed

6 files changed

+439
-398
lines changed

pkg/apis/pipeline/v1beta1/task_types.go

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ const (
2626
TaskRunResultType ResultType = "TaskRunResult"
2727
// PipelineResourceResultType default pipeline result value
2828
PipelineResourceResultType ResultType = "PipelineResourceResult"
29+
// InternalTektonResultType default internal tekton result value
30+
InternalTektonResultType ResultType = "InternalTektonResult"
2931
// UnknownResultType default unknown result type value
3032
UnknownResultType ResultType = ""
3133
)

pkg/entrypoint/entrypointer.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,9 @@ func (e Entrypointer) Go() error {
102102
// *but* we write postfile to make next steps bail too.
103103
e.WritePostFile(e.PostFile, err)
104104
output = append(output, v1beta1.PipelineResourceResult{
105-
Key: "StartedAt",
106-
Value: time.Now().Format(timeFormat),
105+
Key: "StartedAt",
106+
Value: time.Now().Format(timeFormat),
107+
ResultType: v1beta1.InternalTektonResultType,
107108
})
108109

109110
return err
@@ -114,8 +115,9 @@ func (e Entrypointer) Go() error {
114115
e.Args = append([]string{e.Entrypoint}, e.Args...)
115116
}
116117
output = append(output, v1beta1.PipelineResourceResult{
117-
Key: "StartedAt",
118-
Value: time.Now().Format(timeFormat),
118+
Key: "StartedAt",
119+
Value: time.Now().Format(timeFormat),
120+
ResultType: v1beta1.InternalTektonResultType,
119121
})
120122

121123
err := e.Runner.Run(e.Args...)

pkg/pod/status.go

+81-39
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ limitations under the License.
1717
package pod
1818

1919
import (
20-
"encoding/json"
2120
"fmt"
2221
"sort"
2322
"strings"
@@ -97,27 +96,51 @@ func SidecarsReady(podStatus corev1.PodStatus) bool {
9796
}
9897

9998
// MakeTaskRunStatus returns a TaskRunStatus based on the Pod's status.
100-
func MakeTaskRunStatus(logger *zap.SugaredLogger, tr v1beta1.TaskRun, pod *corev1.Pod, taskSpec v1beta1.TaskSpec) v1beta1.TaskRunStatus {
99+
func MakeTaskRunStatus(logger *zap.SugaredLogger, tr v1beta1.TaskRun, pod *corev1.Pod, taskSpec v1beta1.TaskSpec) (v1beta1.TaskRunStatus, error) {
101100
trs := &tr.Status
102101
if trs.GetCondition(apis.ConditionSucceeded) == nil || trs.GetCondition(apis.ConditionSucceeded).Status == corev1.ConditionUnknown {
103102
// If the taskRunStatus doesn't exist yet, it's because we just started running
104103
MarkStatusRunning(trs, v1beta1.TaskRunReasonRunning.String(), "Not all Steps in the Task have finished executing")
105104
}
106105

106+
// Complete if we did not find a step that is not complete, or the pod is in a definitely complete phase
107+
complete := areStepsComplete(pod) || pod.Status.Phase == corev1.PodSucceeded || pod.Status.Phase == corev1.PodFailed
108+
109+
if complete {
110+
updateCompletedTaskRun(trs, pod)
111+
} else {
112+
updateIncompleteTaskRun(trs, pod)
113+
}
114+
107115
trs.PodName = pod.Name
108116
trs.Steps = []v1beta1.StepState{}
109117
trs.Sidecars = []v1beta1.SidecarState{}
110118

119+
var err error
120+
111121
for _, s := range pod.Status.ContainerStatuses {
112122
if IsContainerStep(s.Name) {
113123
if s.State.Terminated != nil && len(s.State.Terminated.Message) != 0 {
114-
message, time, err := removeStartInfoFromTerminationMessage(s)
124+
125+
var results []v1beta1.PipelineResourceResult
126+
results, err = termination.ParseMessage(s.State.Terminated.Message)
115127
if err != nil {
116-
logger.Errorf("error setting the start time of step %q in taskrun %q: %w", s.Name, tr.Name, err)
117-
}
118-
if time != nil {
119-
s.State.Terminated.StartedAt = *time
120-
s.State.Terminated.Message = message
128+
logger.Errorf("termination message could not be parsed as JSON: %v", err)
129+
} else {
130+
//Further processing if the termination message is JSON formatted
131+
var time *metav1.Time
132+
time, err = extractStartedAtTimeFromResults(results)
133+
if err != nil {
134+
logger.Errorf("error setting the start time of step %q in taskrun %q: %v", s.Name, tr.Name, err)
135+
}
136+
if time != nil {
137+
s.State.Terminated.StartedAt = *time
138+
}
139+
if tr.IsSuccessful() {
140+
taskResults, pipelineResourceResults := filterResultsAndResources(results)
141+
trs.TaskRunResults = append(trs.TaskRunResults, taskResults...)
142+
trs.ResourcesResult = append(trs.ResourcesResult, pipelineResourceResults...)
143+
}
121144
}
122145
}
123146
trs.Steps = append(trs.Steps, v1beta1.StepState{
@@ -135,51 +158,70 @@ func MakeTaskRunStatus(logger *zap.SugaredLogger, tr v1beta1.TaskRun, pod *corev
135158
})
136159
}
137160
}
138-
139-
// Complete if we did not find a step that is not complete, or the pod is in a definitely complete phase
140-
complete := areStepsComplete(pod) || pod.Status.Phase == corev1.PodSucceeded || pod.Status.Phase == corev1.PodFailed
141-
142-
if complete {
143-
updateCompletedTaskRun(trs, pod)
144-
} else {
145-
updateIncompleteTaskRun(trs, pod)
146-
}
161+
trs.TaskRunResults = removeDuplicateResults(trs.TaskRunResults)
147162

148163
// Sort step states according to the order specified in the TaskRun spec's steps.
149164
trs.Steps = sortTaskRunStepOrder(trs.Steps, taskSpec.Steps)
150165

151-
return *trs
166+
return *trs, err
167+
}
168+
169+
func filterResultsAndResources(results []v1beta1.PipelineResourceResult) ([]v1beta1.TaskRunResult, []v1beta1.PipelineResourceResult) {
170+
var taskResults []v1beta1.TaskRunResult
171+
var pipelineResourceResults []v1beta1.PipelineResourceResult
172+
for _, r := range results {
173+
switch r.ResultType {
174+
case v1beta1.TaskRunResultType:
175+
taskRunResult := v1beta1.TaskRunResult{
176+
Name: r.Key,
177+
Value: r.Value,
178+
}
179+
taskResults = append(taskResults, taskRunResult)
180+
case v1beta1.InternalTektonResultType:
181+
// Internal messages are ignored because they're not used as external result
182+
continue
183+
case v1beta1.PipelineResourceResultType:
184+
fallthrough
185+
default:
186+
pipelineResourceResults = append(pipelineResourceResults, r)
187+
}
188+
}
189+
190+
return taskResults, pipelineResourceResults
152191
}
153192

154-
// removeStartInfoFromTerminationMessage searches for a result called "StartedAt" in the JSON-formatted
155-
// termination message of a step and returns the values to use for sets State.Terminated if it's
156-
// found. The "StartedAt" result is also removed from the list of results in the container status.
157-
func removeStartInfoFromTerminationMessage(s corev1.ContainerStatus) (string, *metav1.Time, error) {
158-
r, err := termination.ParseMessage(s.State.Terminated.Message)
159-
if err != nil {
160-
return "", nil, fmt.Errorf("termination message could not be parsed as JSON: %w", err)
193+
func removeDuplicateResults(taskRunResult []v1beta1.TaskRunResult) []v1beta1.TaskRunResult {
194+
if len(taskRunResult) == 0 {
195+
return nil
196+
}
197+
198+
uniq := make([]v1beta1.TaskRunResult, 0)
199+
latest := make(map[string]v1beta1.TaskRunResult, 0)
200+
for _, res := range taskRunResult {
201+
if _, seen := latest[res.Name]; !seen {
202+
uniq = append(uniq, res)
203+
}
204+
latest[res.Name] = res
205+
}
206+
for i, res := range uniq {
207+
uniq[i] = latest[res.Name]
161208
}
162-
for index, result := range r {
209+
return uniq
210+
}
211+
212+
func extractStartedAtTimeFromResults(results []v1beta1.PipelineResourceResult) (*metav1.Time, error) {
213+
214+
for _, result := range results {
163215
if result.Key == "StartedAt" {
164216
t, err := time.Parse(timeFormat, result.Value)
165217
if err != nil {
166-
return "", nil, fmt.Errorf("could not parse time value %q in StartedAt field: %w", result.Value, err)
218+
return nil, fmt.Errorf("could not parse time value %q in StartedAt field: %w", result.Value, err)
167219
}
168-
message := ""
169220
startedAt := metav1.NewTime(t)
170-
// remove the entry for the starting time
171-
r = append(r[:index], r[index+1:]...)
172-
if len(r) == 0 {
173-
message = ""
174-
} else if bytes, err := json.Marshal(r); err != nil {
175-
return "", nil, fmt.Errorf("error marshalling remaining results back into termination message: %w", err)
176-
} else {
177-
message = string(bytes)
178-
}
179-
return message, &startedAt, nil
221+
return &startedAt, nil
180222
}
181223
}
182-
return "", nil, nil
224+
return nil, nil
183225
}
184226

185227
func updateCompletedTaskRun(trs *v1beta1.TaskRunStatus, pod *corev1.Pod) {

0 commit comments

Comments
 (0)