-
Notifications
You must be signed in to change notification settings - Fork 344
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
No modify annotation when injecting #902
Conversation
4f86b64
to
a8cff50
Compare
Let's consider also a scenario when:
In this case we should not break existing injected agents. |
@pavolloffay good point, I'll check that case. But, if you add a four step: Then the deployment with inject annotation = true, should be injected with the new side-car, right? |
A good point. @jpkrohling what do you think? It really depends on how we define the behavior. |
I used to think that We might have all the bits necessary for this already: we have the annotation |
@jpkrohling yes that is what I was thinking, using the label for disambiguate, I think this is the best approach as we avoid touching values defined by the user, (the label is completely handled by the operator). |
@pavolloffay do you agree with the expected behavior? If so, @rubenvp8510 could you then adapt this PR to what we discussed above, adding tests to confirm that this new behavior is in place? |
👍 It sounds good to me |
f2d94b4
to
f1b93fa
Compare
cd184b4
to
22af302
Compare
Signed-off-by: Ruben Vargas <[email protected]>
Signed-off-by: Ruben Vargas <[email protected]>
22af302
to
d60c42f
Compare
05c5457
to
399c303
Compare
this is ready for another review. |
test/e2e/sidecar_test.go
Outdated
cleanupOptions := &framework.CleanupOptions{TestContext: ctx, Timeout: timeout, RetryInterval: retryInterval} | ||
|
||
jaegerInstanceName := "agent-as-sidecar" | ||
j := getJaegerAgentAsSidecarDefinition(jaegerInstanceName, namespace) | ||
defer func() { | ||
if !agentAsSideCarDeleted { |
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 is this check needed? The variable is intialized and set in the middle of the tests. Isn't the deterministic at the end of the test?
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 extended this test to test the case addressed by this PR.
At some point in this test I create a new instance and delete the "agent-as-sidecar" Jaeger instance. If I don't do this check the test fails because it tries to delete an non-exist instance at the end.
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 also got confused by this, but I think I understand what's going on: if the test fails midway of the execution, this instance will be lingering around, which is why you need the conditional undeploy.
It might be better to change the undeployJaegerInstance
to return a bool
indicating whether it was able to find and remove the instance. In most cases, the caller wouldn't care about whether the Jaeger has been undeployed correctly, I suppose, but in the cases where it does care, it could just call require.True(t, undeployJaegerInstance(j))
.
cc @kevinearls
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.
@jpkrohling agreed, I think we can change that to return a bool and let the caller decide if they care about failure.
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.
+1
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.
@jpkrohling @kevinearls @pavolloffay I'll do the suggested change but Is it ok to maintain this in a single test? or better to split?
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.
@rubenvp8510 I think it would be better to split.
pkg/inject/sidecar.go
Outdated
|
||
if jaeger == nil || (dep.Annotations[Annotation] != jaeger.Name && dep.Annotations[AnnotationLegacy] != jaeger.Name) { | ||
labelValue, hasLabel := dep.Labels[Label] | ||
if jaeger == nil || (hasLabel && labelValue != jaeger.Name) { |
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.
Can be the hasLabel
omitted? e.g. if jaeger == nil || (labelValue != jaeger.Name)
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 don't think it can be omitted.
The logic is this: if deployment doesn't have a label, that means that it needs to be injected. If it has a label, we need to check if the label is equal to jaeger instance. The latest only applies in the case of an update, while the former is for new deployments. Remember, now inject.Select
function doesn't have side effects, nor modify the deployment.
If we don't check for hasLabel
some sidecar tests will fail. For instance, TestInjectSidecar
will fail because it will try to inject a sidecar in a deployment that doesn't have any label (the label is added when the sidecar is injected). If we check only labelValue != jaeger.Name
the deployment will never be injected. The first time, when it doesn't have a label, labelValue
will be an empty string.
On the other hand, if we check for hasLabel
we will inject the side car the first time. Of course I can do a labelValue != "",
but I would prefer to use the value returned by go maps for key existence.
Does that makes sense?
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'm not a huge fan of this conditional. How about something like this?
if jaeger == nil {
logFields.Trace("no Jaeger instance found, skipping sidecar injection")
return dep
}
if val, ok := dep.Labels[Label]; ok && val != jaeger.Name {
logFields.Trace("deployment is assigned to a different Jager instance, skipping sidecar injection")
return dep
}
decorate(dep)
logFields.Debug("injecting sidecar")
dep.Spec.Template.Spec.Containers = append(dep.Spec.Template.Spec.Containers, container(jaeger, dep))
setInjectedInstanceLabel(dep, jaeger)
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.
One more thing I wanted to check: this changes the behavior of the Sidecar
function, so that it won't check the Annotation
at all anymore. Therefore, this test would be outdated:
jaeger-operator/pkg/inject/sidecar_test.go
Lines 33 to 40 in 4424e8a
func TestInjectSidecar(t *testing.T) { | |
jaeger := v1.NewJaeger(types.NamespacedName{Name: "TestInjectSidecar"}) | |
dep := dep(map[string]string{Annotation: jaeger.Name}, map[string]string{}) | |
dep = Sidecar(jaeger, dep) | |
assert.Len(t, dep.Spec.Template.Spec.Containers, 2) | |
assert.Contains(t, dep.Spec.Template.Spec.Containers[1].Image, "jaeger-agent") | |
assert.Len(t, dep.Spec.Template.Spec.Containers[0].Env, 0) | |
} |
Removing the Annotation
would still get this test passing, which proves the change in behavior. If this is desired, then please change the existing tests, including the one above, but make sure that the contract with the consumers isn't broken: people annotating their deployments have to get the same behavior as 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.
True, I need to update the above test, (and I need to review if I need to update more). The contract with the consumer isn't broken, the only difference is that now the annotation is only used for select the instance (in the select function) and not for inject. but If I'm not wrong or miss something, that is transparent for the consumer.
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'm not a huge fan of this conditional. How about something like this?
if jaeger == nil { logFields.Trace("no Jaeger instance found, skipping sidecar injection") return dep } if val, ok := dep.Labels[Label]; ok && val != jaeger.Name { logFields.Trace("deployment is assigned to a different Jager instance, skipping sidecar injection") return dep } decorate(dep) logFields.Debug("injecting sidecar") dep.Spec.Template.Spec.Containers = append(dep.Spec.Template.Spec.Containers, container(jaeger, dep)) setInjectedInstanceLabel(dep, jaeger)
Is essentially the same, but more separated, and with better log messages :) I'll do the 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.
I find it easier to read and understand, but if you disagree, feel free to keep the current version.
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 indeed think your suggestion is a good idea, improves a lot the readability.
Signed-off-by: Ruben Vargas <[email protected]>
2078004
to
4424e8a
Compare
@jpkrohling please review :) |
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 a clarification needed around the change in Sidecar
behavior. All other requests are optional.
pkg/inject/sidecar.go
Outdated
|
||
if jaeger == nil || (dep.Annotations[Annotation] != jaeger.Name && dep.Annotations[AnnotationLegacy] != jaeger.Name) { | ||
labelValue, hasLabel := dep.Labels[Label] | ||
if jaeger == nil || (hasLabel && labelValue != jaeger.Name) { |
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'm not a huge fan of this conditional. How about something like this?
if jaeger == nil {
logFields.Trace("no Jaeger instance found, skipping sidecar injection")
return dep
}
if val, ok := dep.Labels[Label]; ok && val != jaeger.Name {
logFields.Trace("deployment is assigned to a different Jager instance, skipping sidecar injection")
return dep
}
decorate(dep)
logFields.Debug("injecting sidecar")
dep.Spec.Template.Spec.Containers = append(dep.Spec.Template.Spec.Containers, container(jaeger, dep))
setInjectedInstanceLabel(dep, jaeger)
pkg/inject/sidecar.go
Outdated
@@ -80,6 +73,15 @@ func Needed(dep *appsv1.Deployment, ns *corev1.Namespace) bool { | |||
return !HasJaegerAgent(dep) | |||
} | |||
|
|||
func setInjectedInstanceLabel(target *appsv1.Deployment, jaeger *v1.Jaeger) { |
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.
In new code, we are trying to avoid changing the parameters we receive, returning new values instead. Like:
func setInjectedInstanceLabel(target *appsv1.Deployment, jaeger *v1.Jaeger) *appsv1.Deployment {
ret := *target
...
return &ret
}
In this particular case, I would actually not split it in a separate function, as it this is very simple and, apparently, needed only in the Sidecar
function.
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 don't remember why I split this.. I think it was due some codeclimate issues. I'll check but seems to not be necessary
test/e2e/sidecar_test.go
Outdated
cleanupOptions := &framework.CleanupOptions{TestContext: ctx, Timeout: timeout, RetryInterval: retryInterval} | ||
|
||
jaegerInstanceName := "agent-as-sidecar" | ||
j := getJaegerAgentAsSidecarDefinition(jaegerInstanceName, namespace) | ||
defer func() { | ||
if !agentAsSideCarDeleted { |
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 also got confused by this, but I think I understand what's going on: if the test fails midway of the execution, this instance will be lingering around, which is why you need the conditional undeploy.
It might be better to change the undeployJaegerInstance
to return a bool
indicating whether it was able to find and remove the instance. In most cases, the caller wouldn't care about whether the Jaeger has been undeployed correctly, I suppose, but in the cases where it does care, it could just call require.True(t, undeployJaegerInstance(j))
.
cc @kevinearls
pkg/inject/sidecar.go
Outdated
|
||
if jaeger == nil || (dep.Annotations[Annotation] != jaeger.Name && dep.Annotations[AnnotationLegacy] != jaeger.Name) { | ||
labelValue, hasLabel := dep.Labels[Label] | ||
if jaeger == nil || (hasLabel && labelValue != jaeger.Name) { |
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.
One more thing I wanted to check: this changes the behavior of the Sidecar
function, so that it won't check the Annotation
at all anymore. Therefore, this test would be outdated:
jaeger-operator/pkg/inject/sidecar_test.go
Lines 33 to 40 in 4424e8a
func TestInjectSidecar(t *testing.T) { | |
jaeger := v1.NewJaeger(types.NamespacedName{Name: "TestInjectSidecar"}) | |
dep := dep(map[string]string{Annotation: jaeger.Name}, map[string]string{}) | |
dep = Sidecar(jaeger, dep) | |
assert.Len(t, dep.Spec.Template.Spec.Containers, 2) | |
assert.Contains(t, dep.Spec.Template.Spec.Containers[1].Image, "jaeger-agent") | |
assert.Len(t, dep.Spec.Template.Spec.Containers[0].Env, 0) | |
} |
Removing the Annotation
would still get this test passing, which proves the change in behavior. If this is desired, then please change the existing tests, including the one above, but make sure that the contract with the consumers isn't broken: people annotating their deployments have to get the same behavior as before.
Signed-off-by: Ruben Vargas <[email protected]>
Codecov Report
@@ Coverage Diff @@
## master #902 +/- ##
==========================================
+ Coverage 64.04% 64.40% +0.36%
==========================================
Files 79 82 +3
Lines 6427 6535 +108
==========================================
+ Hits 4116 4209 +93
- Misses 2173 2181 +8
- Partials 138 145 +7
Continue to review full report at Codecov.
|
Signed-off-by: Ruben Vargas <[email protected]>
Signed-off-by: Ruben Vargas <[email protected]>
I updated the sidecar tests, but as you mentioned on one of your comments, the annotation is irrelevant for those tests (except the This is because this PR is not validating for annotation on Summary: This PR uses the annotations only for select the correct Jaeger instance. and use label for check if the deployment already have an agent and which Jaeger instance is the owner. From the consumer/user perspective it will be the same, the deployments with annotations will be injected. |
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. One point still seems to be pending (split of the tests), but @kevinearls and @rubenvp8510 can come to an agreement about doing it in this PR or in a follow-up PR, in which case an issue has to be created before.
@jpkrohling @rubenvp8510 I'd be ok splitting the tests in a separate PR. |
I'm merging this, but @rubenvp8510, please create an issue to track the splitting of the test. |
Signed-off-by: Ruben Vargas [email protected]
Resolves #899
In the actual code, when Select is called to select a jaeger instance, it modifies the annotation and set the value to the jaeger instance name.
I think this can lead to the scenario when you rename (or recreate) the Jaeger instance and there is no way to map the old name instance to the new one. I would prefer to preserve the value.