-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Converts ResultType from string to int enum #4186
Conversation
@sbwsg Could you take a look and let me know if I am right track? 😅 |
One potential risk here is if a controller is upgraded while a TaskRun is mid-execution. If that would happen then the taskrun's pod could return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me so far!
cca4451
to
15fe177
Compare
/kind cleanup |
The following is the coverage report on the affected files.
|
15fe177
to
e38dd57
Compare
The following is the coverage report on the affected files.
|
@sbwsg updated the pr, ptal :) |
/retest |
Hey @sm43 thanks a lot for this! I think we might be better off removing the field name change ("type" -> "t") and only changing the value's type. The reason for that is then we wouldn't need the new // PipelineResourceResult used to export the image name and digest as json
type PipelineResourceResult struct {
// ...
ResultType ResultType `json:"type,omitempty"`
}
// ResultType used to find out whether a PipelineResourceResult is from a task result or not
type ResultType int
// UnmarshalJSON unmarshals either an int or a string into a ResultType. String
// ResultTypes were removed because they made JSON messages bigger, which in
// turn limited the amount of space in termination messages for task results. String
// support is maintained for backwards compatibility - the Pipelines controller could
// be stopped midway through TaskRun execution, updated with support for int in place
// of string, and then fail the running TaskRun because it doesn't know how to interpret
// the string value that the TaskRun's entrypoint will emit when it completes.
func (r *ResultType) UnmarshalJSON(data []byte) error {
var asInt int
var intErr error
if err := json.Unmarshal(data, &asInt); err != nil {
intErr = err
} else {
*r = ResultType(asInt)
return nil
}
var asString string
if err := json.Unmarshal(data, &asString); err != nil {
return fmt.Errorf("unsupported value type, neither int nor string: %v", multierror.Append(intErr, err).ErrorOrNil())
}
switch asString {
case "TaskRunResult":
*r = TaskRunResultType
case "PipelineResourceResult":
*r = PipelineResourceResultType
case "InternalTektonResult":
*r = InternalTektonResultType
default:
*r = UnknownResultType
}
return nil
} We still lose a few bytes because "type" remains but I think it's better not to introduce any new intermediary types to our openapi or swagger. What do you think? I tested this using the unit tests you wrote, here's the diff for those: diff --git a/pkg/apis/pipeline/v1beta1/resource_types_test.go b/pkg/apis/pipeline/v1beta1/resource_types_test.go
index 6cafbbe7d..3108c2ce6 100644
--- a/pkg/apis/pipeline/v1beta1/resource_types_test.go
+++ b/pkg/apis/pipeline/v1beta1/resource_types_test.go
@@ -15,7 +15,6 @@ package v1beta1_test
import (
"encoding/json"
- "reflect"
"testing"
"github.com/google/go-cmp/cmp"
@@ -147,7 +146,6 @@ func TestApplyTaskModifier_AlreadyAdded(t *testing.T) {
}
func TestPipelineResourceResult_UnmarshalJSON(t *testing.T) {
-
testcases := []struct {
name string
data string
@@ -163,7 +161,7 @@ func TestPipelineResourceResult_UnmarshalJSON(t *testing.T) {
pr: v1beta1.PipelineResourceResult{Key: "resultName", Value: "", ResultType: v1beta1.InternalTektonResultType},
}, {
name: "already defined as int",
- data: "{\"key\":\"resultName\",\"value\":\"\", \"t\": 1}",
+ data: "{\"key\":\"resultName\",\"value\":\"\", \"type\": 1}",
pr: v1beta1.PipelineResourceResult{Key: "resultName", Value: "", ResultType: v1beta1.TaskRunResultType},
}}
@@ -173,8 +171,8 @@ func TestPipelineResourceResult_UnmarshalJSON(t *testing.T) {
if err := json.Unmarshal([]byte(tc.data), &pipRes); err != nil {
t.Errorf("Unexpected error when unmarshalling the json into PipelineResourceResult")
}
- if !reflect.DeepEqual(pipRes, tc.pr) {
- t.Errorf("Unexpected error: both objects are different")
+ if d := cmp.Diff(tc.pr, pipRes); d != "" {
+ t.Errorf(diff.PrintWantGot(d))
}
})
} and diff --git a/pkg/pod/status_test.go b/pkg/pod/status_test.go
index c451608a9..d18aa823a 100644
--- a/pkg/pod/status_test.go
+++ b/pkg/pod/status_test.go
@@ -549,7 +549,7 @@ func TestMakeTaskRunStatus(t *testing.T) {
Name: "step-bar",
State: corev1.ContainerState{
Terminated: &corev1.ContainerStateTerminated{
- Message: `[{"key":"resultName","value":"resultValue", "t":1}, {"key":"digest","value":"sha256:1234","resourceRef":{"name":"source-image"}}]`,
+ Message: `[{"key":"resultName","value":"resultValue", "type":1}, {"key":"digest","value":"sha256:1234","resourceRef":{"name":"source-image"}}]`,
},
},
}},
@@ -560,7 +560,7 @@ func TestMakeTaskRunStatus(t *testing.T) {
Steps: []v1beta1.StepState{{
ContainerState: corev1.ContainerState{
Terminated: &corev1.ContainerStateTerminated{
- Message: `[{"key":"digest","value":"sha256:1234","resourceRef":{"name":"source-image"}},{"key":"resultName","value":"resultValue","t":1}]`,
+ Message: `[{"key":"digest","value":"sha256:1234","resourceRef":{"name":"source-image"}},{"key":"resultName","value":"resultValue","type":1}]`,
}},
Name: "bar",
ContainerName: "step-bar",
@@ -587,7 +587,7 @@ func TestMakeTaskRunStatus(t *testing.T) {
Name: "step-banana",
State: corev1.ContainerState{
Terminated: &corev1.ContainerStateTerminated{
- Message: `[{"key":"resultName","value":"resultValue", "t":1}, {"key":"digest","value":"sha256:1234","resourceRef":{"name":"source-image"}}]`,
+ Message: `[{"key":"resultName","value":"resultValue", "type":1}, {"key":"digest","value":"sha256:1234","resourceRef":{"name":"source-image"}}]`,
},
},
}},
@@ -598,7 +598,7 @@ func TestMakeTaskRunStatus(t *testing.T) {
Steps: []v1beta1.StepState{{
ContainerState: corev1.ContainerState{
Terminated: &corev1.ContainerStateTerminated{
- Message: `[{"key":"digest","value":"sha256:1234","resourceRef":{"name":"source-image"}},{"key":"resultName","value":"resultValue","t":1}]`,
+ Message: `[{"key":"digest","value":"sha256:1234","resourceRef":{"name":"source-image"}},{"key":"resultName","value":"resultValue","type":1}]`,
}},
Name: "banana",
ContainerName: "step-banana",
@@ -625,14 +625,14 @@ func TestMakeTaskRunStatus(t *testing.T) {
Name: "step-one",
State: corev1.ContainerState{
Terminated: &corev1.ContainerStateTerminated{
- Message: `[{"key":"resultNameOne","value":"resultValueOne", "t":1}, {"key":"resultNameTwo","value":"resultValueTwo", "t":1}]`,
+ Message: `[{"key":"resultNameOne","value":"resultValueOne", "type":1}, {"key":"resultNameTwo","value":"resultValueTwo", "type":1}]`,
},
},
}, {
Name: "step-two",
State: corev1.ContainerState{
Terminated: &corev1.ContainerStateTerminated{
- Message: `[{"key":"resultNameOne","value":"resultValueThree","t":1},{"key":"resultNameTwo","value":"resultValueTwo","t":1}]`,
+ Message: `[{"key":"resultNameOne","value":"resultValueThree","type":1},{"key":"resultNameTwo","value":"resultValueTwo","type":1}]`,
},
},
}},
@@ -643,14 +643,14 @@ func TestMakeTaskRunStatus(t *testing.T) {
Steps: []v1beta1.StepState{{
ContainerState: corev1.ContainerState{
Terminated: &corev1.ContainerStateTerminated{
- Message: `[{"key":"resultNameOne","value":"resultValueOne","t":1},{"key":"resultNameTwo","value":"resultValueTwo","t":1}]`,
+ Message: `[{"key":"resultNameOne","value":"resultValueOne","type":1},{"key":"resultNameTwo","value":"resultValueTwo","type":1}]`,
}},
Name: "one",
ContainerName: "step-one",
}, {
ContainerState: corev1.ContainerState{
Terminated: &corev1.ContainerStateTerminated{
- Message: `[{"key":"resultNameOne","value":"resultValueThree","t":1},{"key":"resultNameTwo","value":"resultValueTwo","t":1}]`,
+ Message: `[{"key":"resultNameOne","value":"resultValueThree","type":1},{"key":"resultNameTwo","value":"resultValueTwo","type":1}]`,
}},
Name: "two",
ContainerName: "step-two",
@@ -727,7 +727,7 @@ func TestMakeTaskRunStatus(t *testing.T) {
Name: "step-pear",
State: corev1.ContainerState{
Terminated: &corev1.ContainerStateTerminated{
- Message: `[{"key":"resultNameOne","value":"","t":2}, {"key":"resultNameTwo","value":"","t":3}, {"key":"resultNameThree","value":"","t":1}]`},
+ Message: `[{"key":"resultNameOne","value":"","type":2}, {"key":"resultNameTwo","value":"","type":3}, {"key":"resultNameThree","value":"","type":1}]`},
},
}},
},
@@ -737,7 +737,7 @@ func TestMakeTaskRunStatus(t *testing.T) {
Steps: []v1beta1.StepState{{
ContainerState: corev1.ContainerState{
Terminated: &corev1.ContainerStateTerminated{
- Message: `[{"key":"resultNameOne","value":"","t":2},{"key":"resultNameThree","value":"","t":1}]`,
+ Message: `[{"key":"resultNameOne","value":"","type":2},{"key":"resultNameThree","value":"","type":1}]`,
}},
Name: "pear",
ContainerName: "step-pear",
@@ -775,7 +775,7 @@ func TestMakeTaskRunStatus(t *testing.T) {
Steps: []v1beta1.StepState{{
ContainerState: corev1.ContainerState{
Terminated: &corev1.ContainerStateTerminated{
- Message: `[{"key":"resultNameOne","value":"","t":2},{"key":"resultNameThree","value":"","t":1}]`,
+ Message: `[{"key":"resultNameOne","value":"","type":2},{"key":"resultNameThree","value":"","type":1}]`,
}},
Name: "pear",
ContainerName: "step-pear",
|
if err := json.Unmarshal([]byte(tc.data), &pipRes); err != nil { | ||
t.Errorf("Unexpected error when unmarshalling the json into PipelineResourceResult") | ||
} | ||
if !reflect.DeepEqual(pipRes, tc.pr) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggest using cmp.Diff
here so that devs can see which fields are incorrect. Here's example usage:
if d := cmp.Diff(tc.pr, pipRes); d != "" {
t.Errorf(diff.PrintWantGot(d))
}
// UnknownResultType default unknown result type value | ||
UnknownResultType ResultType = "" | ||
UnknownResultType = 4 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Q: Can we set "UnknownResultType" to a higher value, e.g. 10 or 100? So that, in future more types can be added.
e38dd57
to
14818ab
Compare
The following is the coverage report on the affected files.
|
This converts the ResultType in PipelineResourceResult from string to int enum to curtail the size of json object emittted by steps. ResultTypes were removed because they made JSON messages bigger, which in turn limited the amount of space in termination messages for task results. String support is maintained for backwards compatibility. Closes tektoncd#4150 Signed-off-by: Shivam Mukhade <[email protected]>
14818ab
to
d21e087
Compare
The following is the coverage report on the affected files.
|
@sbwsg yeah that make sense to not change |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fantastic, thanks a lot @sm43 !
// UnknownResultType default unknown result type value | ||
UnknownResultType ResultType = "" | ||
UnknownResultType = 10 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: sbwsg The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A very naive question, isn't this kind-of breaking the API ? Even though pipeline doesn't consume it, there might be tools that are consuming this and used to see strings (like TaskRunResult
) and will see an int now, isn't it ?
@vdemeester the way we pass messages from Tasks to the controller is an internal implementation detail isn't it? |
Well, isn't this "exposed" as part of the |
It's exposed at the following location in taskruns: status:
steps:
- container: step-print-date-human-readable
terminated:
message: '[{"key":"current-date-human-readable","value":"Mon Sep 13 14:28:59
UTC 2021\n","type":"TaskRunResult"},{"key":"current-date-unix-timestamp","value":"1631543338\n","type":"TaskRunResult"}]' To be super explicit: we're talking about the stringified JSON blob in the termination message field. The "type" field in that stringified JSON blob will change from a string ("TaskRunResult") to an int. You're saying that consumers of our API are parsing the stringified JSON blob for this data rather than looking in the |
They might but yes, if it's only exposed there, then I think we are safe 😛 |
I kind of agree with @vdemeester, whoever is looking at the I would like to see the changes in the release notes to be on the safer side. @sm43 will you be able to please add the release notes with the status JSON blob change. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this!
I agree with @pritidesai, we need to call this out in the release notes of this PR and of next release. We might want to document that the termination message is not meant as a stable API, even if it's exposed within the status.
Once the release notes are updated this lgtm.
Nice idea @afrittoli I'll make a PR to document the lack of guarantees around the termination message. |
Created #4226 to capture termination message note. |
@sbwsg @pritidesai added release notes, ptal if it looks okay. |
thanks @sm43 /lgtm |
This converts the ResultType in PipelineResourceResult from string
to int enum to curtail the size of json object emittted by steps.
ResultTypes are converted because they made JSON messages bigger, which in
turn limited the amount of space in termination messages for task results. String
support is maintained for backwards compatibility.
Closes #4150
Signed-off-by: Shivam Mukhade [email protected]
Submitter Checklist
As the author of this PR, please check off the items in this checklist:
functionality, content, code)
Release Notes
ResultType in JSON blob of termination message is changed from String to Int. So, for ex previouly we used to have
"type": "TaskRunResultType"
in the terminaton message which now would appear as"type": 1
to curtail the size of json.