-
Notifications
You must be signed in to change notification settings - Fork 26
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
Patching from a non-existent 'from' field deletes the 'to' field #85
Comments
I think behavior I describe (deleting the field) makes sense when an optional field path doesn't exist. It's optional after all. It's not ideal for a required field path. We've discussed a couple of ways to handle patching from a required, missing field path to a resource that already exists:
Returning a fatal result is the simplest thing to implement, and I think the simplest thing to reason about. I think the main reason we might not want to return a fatal result is because it prevents eventual consistency. For example if the required 'from' path temporarily went missing, but would be repopulated by running a subsequent patch. If we returned a fatal result, we'd never run that subsequent patch. I think the biggest issue with loading observed state into the 'to' field is that for complex types (objects and arrays) we'd have to figure out how to merge the observed state into our desired state. This could result in issues like crossplane/crossplane#3335. This is more of an intuition, but something about returning observed state as desired state also generally doesn't sit right with me. I'd prefer if an entity observing the function's I like that making it possible to omit a resource from desired state is more obvious. Presumably this would be something like: // A Resource represents the state of a composite or composed resource.
message Resource {
// The JSON representation of the resource.
google.protobuf.Struct resource = 1;
// The resource's connection details.
map<string, bytes> connection_details = 2;
// Ready indicates whether the resource should be considered ready.
Ready ready = 3;
// Error indicates a non-fatal error producing the state for this resource.
// The resource should be skipped (i.e. not applied).
string error = 4;
} One issue with omitting a resource is that other functions now need to be aware of and handle the possibility of an Another issue omitting a resource is the risk of applying partial state. This one is a bit hand wavy, but I'd say it's often preferable to not change anything in the face of an error as opposed to changing some things but not others. The risk being that while doing nothing stops the system's state from proceeding, doing some of the things could push the system into a broken state. You could argue that perhaps this is fine as long as function authors were aware of the tradeoff - functions could still return a fatal result to stop the world in the face of an error. |
Background
I plan to include #81 in the v0.3.0 release of this function.
#81 changes how this function handles patch errors. This includes how the function handles patching from a field path that doesn't exist, which is a kind of patch error.
Most patch errors now cause the function to return a fatal result. A fatal result stops the entire function pipeline. The fatal result will appear as an event associated with the XR. For example a type mismatch like patching from an integer field to an array field would cause a fatal error.
We treat errors that occur due to missing 'from' field paths specially. Each patch can configure whether the 'from' field path is optional (the default) or required. This is because more than any other kind of error, a missing field path is likely to fix itself eventually.
Consider for example a composition that patches from MR A's status to the XR's spec, then patches that XR spec field to MR B's spec. MR B's spec is derived from MR A's status. It's normal for the patches to fail due to a missing field path until the status field is populated from the external system.
Sometimes it's fine for MR B to be created, then have its spec field derived from MR A's status once that status becomes available. You use an optional field path patch for this.
Other times MR B should not be created at all until the data from MR A's status is available. You use a required field path patch for this.
After #81 this function behaves per this table:
Another way to look at this is:
The Issue
This function computes desired state similarly to native P&T, but applies it differently. Functions use server-side apply (SSA), while native P&T uses client-side apply. One of the benefits of server-side apply is that it supports deleting fields. Our client-side apply implementation does not. This leads to issues like crossplane/crossplane#4162.
This means that when native P&T skips a patch, the field it's patching to just remains how it was.
Because SSA interprets omitting a field from desired state as a desired to delete that field, when this functions skips a patch the field will be deleted.
This means that:
This function will omit the 'to' field path from its desired state, causing it to be deleted.
The text was updated successfully, but these errors were encountered: