-
Notifications
You must be signed in to change notification settings - Fork 180
Add FieldExport CRD and field export reconciler
#75
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
Add FieldExport CRD and field export reconciler
#75
Conversation
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.
Looking really good, @RedbackThomson! A few minor suggestions inline along with one major comment about the handling of Recoverable conditions...
| // NamespacedTargetKubernetesResource provides all the values necessary to identify an ACK | ||
| // resource of a given type (within the same namespace). | ||
| type NamespacedTargetKubernetesResource struct { | ||
| metav1.GroupKind `json:""` |
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.
I think you should leave off the json:"" if you want to "inline" the GroupKind's fields.
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.
Other way around. Including the json tag inlines it.
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.
Not according to this: https://stackoverflow.com/questions/43077665/how-do-i-inline-fields-when-marshalling-json
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.
Not sure what to say haha. The AdoptedResource CRD remains the same if I do it this way - you can check the diff to verify.
apis/core/v1alpha1/identifiers.go
Outdated
| } | ||
|
|
||
| // FieldExportOutputSelector provides the values necessary to identify the | ||
| // output path for a field export (within the same namespace). |
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.
If this is "(within the same namespace)", then a) the name of the struct should begin with Namespaced to align with the other namespace-scoped structs above like NamespacedTargetKubernetesResource and b) why does this struct have an optional Namespace field?
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.
Yeah this comment is incorrect. The output can be into a separate namespace. The default is the same namespace (which is why namespace is optional).
| type AdoptedResourceSpec struct { | ||
| // +kubebuilder:validation:Required | ||
| Kubernetes *TargetKubernetesResource `json:"kubernetes"` | ||
| Kubernetes *AdoptedResourceTarget `json:"kubernetes"` |
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.
this is going to break any existing ACK controller, no?
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.
It's just been renamed. The only thing that changes are the docstrings
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.
Existing AdoptedResource CRs in an existing installation of a controller would fail to be read into the controller, no? Since the over-wire format of the schema would be different...
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.
Protobuf does not care about the field names. As long as I don't mess with the tag numbers, which I believe are auto-generated based on the order of the field, then I should be okay. Citation: https://stackoverflow.com/questions/45431685/protocol-buffer-does-changing-field-name-break-the-message
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.
Protobuf does not care about the field names. As long as I don't mess with the tag numbers, which I believe are auto-generated based on the order of the field, then I should be okay. Citation: https://stackoverflow.com/questions/45431685/protocol-buffer-does-changing-field-name-break-the-message
You aren't changing the name of the field above, though... You're changing the data type.
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.
I reached out to Ellis about this:
[Nick] I feel that if the CRD is identical, there shouldn't be a difference?
[Ellis] The API Server serializes it using the CRD
[Ellis] Exactly
[Ellis] The APIServer isn't aware of your go struct, just the CRD
[Ellis] We do this regularly in karpenter w/ our go types
So we don't need to worry about etcd serialization. Just that we are maintaining the same contract with the API server, which is the CRD. I have confirmed that the CRD remains untouched.
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 work! Left some minor comments.
| from acktypes.AWSResource, | ||
| desired ackv1alpha1.FieldExport, | ||
| ) error { | ||
| r.clearConditions(ctx, &desired) |
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.
Minor Suggestion: This will add extra patchStatus call to API server. I think conditions can be handled without this extra call by keeping a copy of desired in memory, updating that copy and then patch once at the end using desired as base.
The approach may look like:
a) Create latest by deepCopying desired.
b) clearConditions on latest in memory (do not patch)
c) Use latest inside the Sync function and set Apt conditions (Recoverable, Terminal, etc) in memory
d) PatchStatus at the very end, using desired as "base" .
The above approach will only make single call to APIServer for status patching. Currently there is one call for clearing condition and another per condition.
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.
Getting there, @RedbackThomson thank you! Left a number of suggestions inline for ya.
| type AdoptedResourceSpec struct { | ||
| // +kubebuilder:validation:Required | ||
| Kubernetes *TargetKubernetesResource `json:"kubernetes"` | ||
| Kubernetes *AdoptedResourceTarget `json:"kubernetes"` |
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.
Protobuf does not care about the field names. As long as I don't mess with the tag numbers, which I believe are auto-generated based on the order of the field, then I should be okay. Citation: https://stackoverflow.com/questions/45431685/protocol-buffer-does-changing-field-name-break-the-message
You aren't changing the name of the field above, though... You're changing the data type.
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.
@RedbackThomson the whole fieldExportReconciler single reconciler struct for both source resource and FieldExport resources is still rubbing me the wrong way. Please see my comment inline about having two reconciler structs, one for FieldExports and another for source resources.
| // Handle query errors | ||
| if err, ok := result.(error); ok { | ||
| if err != nil { | ||
| return nil, &terminalError{err: errors.Wrap(err, ackerr.FieldExportQueryFailed.Error())} |
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.
why not put terminalError into pkg/errors and actually define pkg/errors.FieldExportQueryFailed as wrapping terminalError?
45a7832 to
bfa7ba4
Compare
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.
There's enough good here that I'm willing to address a few things about the fieldExportReconciler struct in followup PRs. 👍
|
/lgtm |
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: jaypipes, RedbackThomson, vijtrip2 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 |
|
@RedbackThomson @jaypipes Sorry I'm late on this one, but is this a CRD that would be packaged with every controller just like the |
Correct. This CRD is handled exactly in the same way as |
|
@RedbackThomson Looking again at this PR and the code we have here I think adding this would be covered by whats in place. Can you please take a look and confirm? Thanks! |
Exactly! I tried to future proof it, and I think this still holds. |
|
Yeah, It looks that way, missed it on the first pass of looking at this PR. |
Issue #, if available: aws-controllers-k8s/community#740
Description of changes:
Creates a new
FieldExportCRD as outlined this proposal. Also creates a new reconciler that reconciles changes toFieldExportand changes to any ACK resource recognised by the current controller.The path for reconciling a
FieldExport:FieldExportSourceresource group matches the current controller's group3a. If no source object is found, stop reconciling
gojqlibrary to parse the unstructured source objectConfigMap/SecretThe path when any ACK resource is updated:
FieldExporttypes in the namespace that reference the current resource as itsSourceFieldExportdo steps 3 and 4 from the previous pathThe reconciler converts all primitive types into strings (ConfigMap is a string-string map, Secret is a string-byte[] map). If the jq query returns a list of results, we will only take the first result (this PR does not support exporting slices/maps). If the jq query returns a struct, we will not take any action, treating the query as a failure.
The reconciler will not delete any values from the ConfigMap or Secret. If the referenced field is removed from the object, the reconciler will no-op, rather than overwriting the data with an empty string. When the
FieldExportis deleted, the ConfigMap or Secret will also be left untouched - meaning it contains whatever was last written to it.Upon creating a
FieldExportCR, the reconciler will initially attempt to export the field. If it fails, it will not attempt to retry. After the first sync, the reconciler will only wait until theResourceVersionof the source object changes for it to trigger a new update.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.