-
Notifications
You must be signed in to change notification settings - Fork 2.9k
[receiver/k8sobjectsreceiver] Properly deep copy the K8sObjectsConfig struct #39644
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
[receiver/k8sobjectsreceiver] Properly deep copy the K8sObjectsConfig struct #39644
Conversation
The original issue advised to refactor the config struct to separate mutable fields into a new struct. I tried that, but I felt it was much cleaner to simply keep it as is. I'm not sure if there was reasoning other than code readability, but I'm happy to change this if reviewers still want the refactor. |
@@ -129,3 +129,40 @@ func (c *Config) getValidObjects() (map[string][]*schema.GroupVersionResource, e | |||
} | |||
return validObjects, nil | |||
} | |||
|
|||
func (k *K8sObjectsConfig) DeepCopy() *K8sObjectsConfig { | |||
copied := &K8sObjectsConfig{ |
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.
Re-using the same struct might not be the best option here. I would define a new one called for example K8sObjectTarget
. That'd probably be with non-public fields unless there is need for having them public.
Apart from making it clear in the name that it's not about "Config" anymore will ensure that we won't have issues in the future in case we want to diverge the 2 different structs. WDYT?
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.
Got it. Sounds good. The one thing is that we have to keep the fields public for mapstructure
to work properly. (I tried unexporting to namespaces
and excludeWatchType
and things broke)
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.
Thank's @petern48 for working on this! I left few suggestions.
Moving to draft while you review suggestions, please mark ready to review once done. |
@ChrsMark I incorporated your feedback. Let me know if this is what you had in mind. |
FieldSelector string `mapstructure:"field_selector"` | ||
Interval time.Duration `mapstructure:"interval"` | ||
ResourceVersion string `mapstructure:"resource_version"` | ||
K8sObjectTarget `mapstructure:",squash"` |
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 this needs to be part of the config? I was thinking that those 2 should be independent. Then you can do the following to instantiate the targets:
targetObject := newTargetObject(configObject)
After this point we don't need the K8sObjectsConfig
object anymore and we only work with the targetObject
which is of type K8sObjectTarget
.
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 see. It makes a lot more sense that you were considering separating the objects altogether. However, I'm not quite seeing where you imagine this being stored. Don't we still need to maintain one K8sObjectTarget
per corresponding object?
The only way I can see doing that while keeping it outside of K8ObjectsConfig
is by adding a new corresponding slice inside of Config
, like below. Is that what you had in mind?
type Config struct {
k8sconfig.APIConfig `mapstructure:",squash"`
Objects []*K8sObjectsConfig `mapstructure:"objects"`
+ Targets []*K8sObjectTarget `mapstructure:"targets"`
Or do you mean to somehow separate it from the Config
object as well? Although that doesn't add up since the example line you gave indicates the config object would have that info to create the new copy.
targetObject := newTargetObject(configObject)
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 we already store the "copies" at
objects []*K8sObjectsConfig |
k8sobjectsreceiver
instance. I would just use this field and have the full/deep copy to happen at newReceiver
.
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 we already store the "copies" at
objects []*K8sObjectsConfig as part of the
k8sobjectsreceiver
instance. I would just use this field and have the full/deep copy to happen atnewReceiver
.
Sorry, I'm still confused. This sounds like what the current implementation is doing. Maybe I'm missing something, but I don't see how we can accomplish this while fulfilling your earlier request of moving K8sObjectTarget
outside of the config struct (K8sObjectsConfig
). Wouldn't K8sObjectTarget
have to be inside of K8sObjectsConfig
if we want to re-use this 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.
My suggestion is to make objects
field of type K8sObjectTarget
. Then objects
will be deep copies of the initially provided K8sObjectsConfig
objects of the Config
.
After this point we only interact and handle with the objects
field (type K8sObjectTarget
) and we don't need the K8sObjectsConfig
any more.
Otherwise we should only interact with K8sObjectsConfig
in read-only mode to unpack the configurations and create mutable K8sObjectTarget
objects that will be the ones we will be using during the execution of the receiver.
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've looked into it, and I don't think it's quite possible to never touch the kr.config
object after newReceiver()
since many of the struct methods use fields that are inside of immutable fields in k8sObjectConfig
, that aren't in K8sObjectTarget
. We need some way to access those fields in the struct methods, so using the k8sObjectConfig
s through kr.config
looks like the easiest way. Let me know if you think otherwise. I'll need a little more time to figure out and propose a clean way to implement this.
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.
use fields that are inside of immutable fields in k8sObjectConfig, that aren't in K8sObjectTarget
Why then we don't make them part of the K8sObjectTarget
as well?
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.
Well then, at that point, we've gone full circle and have a struct named K8sObjectTarget
that's the same as the k8sObjectConfig
struct as we originally did, so effectively all we would be doing is renaming the struct... I'm honestly not seeing tremendous value from trying to refactor the code anymore. If we remove the K8sObjectTarget
struct and simply deep copy the original k8sObjectConfig
, then we can fix the deep copy issue without adding additional complexity. WDYT?
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 see. The reason for introducing a 2nd struct was described at #39644 (comment).
However, let's solve the deep copy issue for now using the same struct (K8sObjectConfig
) as you suggest (removing the use of K8sObjectTarget
since it's essentially the same) and maybe we can revisit in a follow-up PR.
Thank's!
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.
Got it, yeah. I just reverted to the deep copy-only code.
Please address the feedback of the codeowner and mark ready for review once done. |
This PR was marked stale due to lack of activity. It will be closed in 14 days. |
…tor-contrib into refactor_k8_config
f1c78f9
to
35c3fb7
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.
LGTM
.chloggen/refactor_k8_config.yaml
Outdated
component: k8sobjectsreceiver | ||
|
||
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). | ||
note: Properly deep copy the K8sObjectsConfig struct in the k8sobjectsreceiver and separate mutable 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.
This would need an update? Probably we don't need a change-log at all since it's a code refactoring.
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.
Got it, just removed it. You'll need to add the Skip changelog
label for CI to pass, as mentioned here.
… struct (open-telemetry#39644) <!--Ex. Fixing a bug - Describe the bug and how this fixes the issue. Ex. Adding a feature - Explain what this achieves.--> #### Description In `newReceiver()` , we perform a shallow copy of the K8sObjectsConfig objects instead of a deep one. <!-- Issue number (e.g. open-telemetry#1234) or full URL to issue, if applicable. --> #### Link to tracking issue Fixes open-telemetry#39553 <!--Describe what testing was performed and which tests were added.--> #### Testing Added `TestDeepCopy` inside of `config_test.go` <!--Describe the documentation added. #### Documentation --> <!--Please delete paragraphs that you did not use before submitting.-->
… struct (open-telemetry#39644) <!--Ex. Fixing a bug - Describe the bug and how this fixes the issue. Ex. Adding a feature - Explain what this achieves.--> #### Description In `newReceiver()` , we perform a shallow copy of the K8sObjectsConfig objects instead of a deep one. <!-- Issue number (e.g. #1234) or full URL to issue, if applicable. --> #### Link to tracking issue Fixes open-telemetry#39553 <!--Describe what testing was performed and which tests were added.--> #### Testing Added `TestDeepCopy` inside of `config_test.go` <!--Describe the documentation added. #### Documentation --> <!--Please delete paragraphs that you did not use before submitting.-->
Description
In
newReceiver()
, we perform a shallow copy of the K8sObjectsConfig objects instead of a deep one.Link to tracking issue
Fixes #39553
Testing
Added
TestDeepCopy
inside ofconfig_test.go