-
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
Serialize entire v1beta1 PipelineSpec when converting to v1alpha #3854
Conversation
This should probably get some more thorough testing as well if we decide to move forward with it. |
The following is the coverage report on the affected files.
|
Writing a test for this exposed another field we're silently dropping on conversion: Pipeline's I'm updating this branch to fix that too. |
The following is the coverage report on the affected files.
|
The following is the coverage report on the affected files.
|
The following is the coverage report on the affected files.
|
Remaining TODOs:
|
The following is the coverage report on the affected files.
|
The following is the coverage report on the affected files.
|
The following is the coverage report on the affected files.
|
The following is the coverage report on the affected files.
|
I think that's something to test. If a user I am not sure about service side |
The following is the coverage report on the affected files.
|
Looking at an example Pipeline, let's say it starts as a kind: Pipeline
apiVersion: tekton.dev/v1beta1
metadata:
name: p
spec:
tasks:
- name: t
taskRef:
name: t
when:
- input: "w"
operator: "in"
values: ["x"] On conversion to kind: PipelineRun
apiVersion: tekton.dev/v1alpha1
metadata:
name: p
annotations:
tekton.dev/v1beta1PipelineSpec: `{ tasks: [{ "name": "t", "taskRef": {"name": "t"} "when": [{ "input": "w", "operator": "in", "values": ["x"] }] }] }`
spec:
tasks:
- name: t
taskRef:
name: t Now, let's say the user updates the kind: PipelineRun
apiVersion: tekton.dev/v1alpha1
metadata:
name: p
annotations:
tekton.dev/v1beta1PipelineSpec: `{ tasks: [{ "name": "t", "taskRef": {"name": "t"} "when": [{ "input": "w", "operator": "in", "values": ["x"] }] }] }`
spec:
tasks:
- name: u
taskRef:
name: t ^ Our conversion code can no longer figure out which pipelinetask is the right one to merge the The round-tripped Pipeline ends up reverted to this: kind: Pipeline
apiVersion: tekton.dev/v1beta1
metadata:
name: p
spec:
tasks:
- name: t
taskRef:
name: t
when:
- input: "w"
operator: "in"
values: ["x"] |
Prior to this commit our conversion of pipelines from v1beta1 to v1alpha1 did not account for fields that were solely present in the v1beta1 pipeline spec. This meant, for example, that When Expressions in PipelineTasks were quietly dropped when moving from v1beta1 to v1alpha1. If a user subsequently re-applied that v1alpha1 resource to the cluster then the resource would be upgraded back to v1beta1 prior to storage without the missing when expressions. This problem would only be exacerbated further over time - any new features added to the v1beta1 spec would be lost on conversion. This commit serializes the entire v1beta1 pipeline spec into an annotation on Pipelines and PipelineRuns (for nested pipelineSpec fields). This will protect the entire set of beta-only fields from being lost in translation. Unfortunately this approach does also have drawbacks: if a user makes changes to the v1alpha1 YAML and then re-applies it then those changes will be lost - overwritten by the contents of the annotation. I'm not sure if there's a great way to determine, for all fields, how to successfully "merge" the beta annotation with the contents of the modified v1alpha1 spec when up-converting. An e2e test has been added to send a v1beta1 pipeline through the entire roundtrip flow and then compare the before/after for differences. One more fix is also included here: prior to this commit we were not preserving pipeline results when converting pipelines from v1beta1 to v1alpha1. This commit corrects that by copying pipeline results to the v1alpha1 pipeline and back.
The following is the coverage report on the affected files.
|
@sbwsg: The following tests failed, say
Full PR test history. Your PR dashboard. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
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.
excellent commit message 🎉
Just a couple random nits and thoughts:
- looks like the unit test coverage has gone down :O (looks like some error conditions not being tested?) (maybe that's covered by the TODO you've already got)
- i guess we'll still need to follow this same approach for our other beta types ... and add more of this when we go to v1 as well (i wonder if its worth starting to write a list somewhere of things like this we need to make sure not to forget when we go to v1 - or even just making a note on the v1 issue)
/approve
|
||
if _, ok := pV1alpha1.Annotations[v1alpha1.V1Beta1PipelineSpecSerializedAnnotationKey]; !ok { | ||
t.Fatal("the serialized v1beta1 object is not present in the v1alpha1 object's annotations") | ||
} |
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.
do we also want to assert against the serialized object? (or is it that we feel this is adequately covered by unit tests? might be worth asserting against something in this object just to be sure the contents are at least approximately what we expect)
const FinallyFieldName = "finally" | ||
// This annotation was used to serialize and deserialize Finally tasks in the | ||
// 0.22 Pipelines release. Keep it around to continue supporting any documents | ||
// converted during that time. |
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.
would it make sense to add this to our doc tracking deprecations?
@@ -107,6 +122,7 @@ func (sink *PipelineSpec) ConvertFrom(ctx context.Context, source v1beta1.Pipeli | |||
sink.Params = source.Params | |||
sink.Workspaces = source.Workspaces | |||
sink.Description = source.Description | |||
sink.Results = source.Results |
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.
im curious why this was missing before?
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.
We didn't preserve Pipeline Results
on the roundtrip to v1alpha1 and back :S so users were potentially losing this part of their pipeline specs prior to this commit. 🐛
if meta.Annotations != nil { | ||
if str, ok := meta.Annotations[V1Beta1PipelineSpecSerializedAnnotationKey]; ok { | ||
if err := json.Unmarshal([]byte(str), spec); err != nil { | ||
return fmt.Errorf("error deserializing v1beta1 document from annotation: %w", err) |
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.
maybe im overthinking this but im wondering about the impact of this annotation becoming malformed; i.e. do we want to have an error or just ignore it? (i guess having an error is safer in the long run?)
delete(meta.Annotations, V1Beta1PipelineSpecSerializedAnnotationKey) | ||
if len(meta.Annotations) == 0 { | ||
meta.Annotations = nil | ||
} |
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.
im curious why we are explicitly setting this to nil? (maybe a comment would help)
return false | ||
} | ||
|
||
structField, ok = p.Index(-1).(cmp.StructField) |
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.
the -1 and -2 to me feel like they could use a comment or variable to add some more context
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: bobcatfish 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 |
Right, I think this is where we need to define "precendence" of things. Anything that is present in the spec should take over the annotation I feel. |
Can you go into a bit more detail here because I'm not sure it's possible for nested objects like |
Assumption: I think it would be fair to allow users upgrade the API version in their resources (only via With that assumption in mind we could store in an annotation the api version used at create time, and decide what we allow based on that:
My concern is that I've never seen k8s APIs behave this way - and it would be better to give users a consistent experience in terms of API versioning, unless there is a really good reason to behave differently. |
I'm going to close this for the time being. The next step for anyone picking this up later would be to write a TEP to try and capture the different alternative approaches / tradeoffs and then build a community consensus on best next steps. |
Changes
Fixes #3815
I've added everyone that I've spoken to about this as reviewers on the PR. Sorry
for the spam but I want to widely publicise it before moving ahead.
Prior to this commit our conversion of pipelines from v1beta1 to v1alpha1
did not account for fields that were solely present in the v1beta1
pipeline spec. This meant, for example, that
WhenExpressions
inPipelineTasks
were quietly dropped when moving from v1beta1 to v1alpha1. If a user
subsequently re-applied that v1alpha1 resource to the cluster then
the resource would be upgraded back to v1beta1 for storage without
those when expressions.
Why would this down-conversion happen? Users with older clients that
don't know about v1beta1 yet will still be requesting resources using the v1alpha1
apiVersion
.Over time this problem would only be exacerbated - any new features added to the
v1beta1 spec would be lost on conversion unless we ensured that all new fields were
also added to the v1alpha1 spec (or accounted for in the conversion webhook).
So, to account for all the fields that might be in v1beta1 but not in v1alpha1 this commit
serializes the entire v1beta1 pipeline spec into an annotation
on
Pipelines
andPipelineRuns
(when the nestedpipelineSpec
field is present). This willprotect the entire set of beta-only fields from being lost in translation through this conversion
process. This annotation only exists in the YAML that is returned to the user. This annotation never
gets stored in etcd (unless I'm missing something!)
Unfortunately this approach does also have drawbacks: if a user makes changes
to the v1alpha1 YAML and then re-applies it then those changes
will be lost, overwritten by the contents of the annotation. I'm not sure if
there's a great way to determine, for all fields, how to successfully "merge"
the beta annotation with the contents of the modified v1alpha1 spec when
up-converting. There's no clear signal, as far as I can tell, that any given field has or
has not been modified (beyond performing a
cmp.Diff
? Would that be an acceptable option?)/hold
Submitter Checklist
Release Notes