-
Notifications
You must be signed in to change notification settings - Fork 220
Extract controller configuration handling and provide Quarkus extension #238
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
Extract controller configuration handling and provide Quarkus extension #238
Conversation
If I understand it correctly the intention is making the Quarkus native builds possible, right? |
The intent is to be able to replace a lot (all) of what is currently done at runtime (e.g. annotation processing, reflection) by build time processing when running in a Quarkus environment.
What do you mean by "exposed to the developer"? As things are, the intention is that things will keep working as they currently are when not using Quarkus but the configuration implementation will be swapped out by Quarkus. |
The controller interface is having a new method called I think we can achieve the same things just by giving a hint to the graalVM to keep the Reflection metadata in the image. By doing so we don't need to put the effort into having 2 different implementations. |
Note that this change is not Quarkus-specific: if we want to be able to externalize the configuration, we will need to provide different implementations of how the configuration is retrieved/computed. This is also helpful for Spring Boot or other frameworks for example, where each could provide their own way of retrieving the configuration. If adding a Another point that I think is worth mentioning: there's a lot more to Quarkus than native compilation. Its JVM mode also provides reduced memory size, faster startup, smaller binary size. I think it's worth making sure that we can support all these aspects and not simply focus on native compilation. In order to be able to support these other benefits, more work is needed, especially when things can be properly computed at build time instead of runtime. Registering things for reflection is quite costly even for native compilation. |
be7b6d8
to
70f6bf7
Compare
I'm all in for replacing whole runtime logic with built time configuration. |
So things are getting interesting and I'm making some rather significant changes which I would like input on. The main idea behind these changes is to extract the parts that are done to make it easier to work with native compilation and isolate them in such a way that they can be used when needed but don't impact a future Quarkus extension. The parts in question are all the runtime configuration aspects along with the annotation processor and mapper parts as they would be not only be redundant with what Quarkus would be doing but actually be detrimental. What do you think @adam-sandor @csviri @psycho-ir @kirek007? |
Do you think it makes sense to write a one-pager doc about the change? I'm not sure about others but at least it would be very helpful for me and also can be added to the decision log or part of the SDK doc later on. |
@psycho-ir the changes are now made in this PR (though I still need to go through the tests to see if everything works as expected). The main idea as previously mentioned: there's a new Both approaches are discouraged when using Quarkus, which is why this PR makes that behavior optional so that other implementations such as one based on Quarkus, could implement a The new approach is visible in the sample projects where projects now depend on the Of note, an |
b63473e
to
027134f
Compare
Quarkus extension is not finished yet but I'd like to get some feedback on the rest of the changes. |
1267463
to
e200c2e
Compare
058060b
to
ef8e1c4
Compare
Seems like the issue with the tests is the fact that the sample classes are currently in the |
The purpose is to be able to use a different implementation depending on the execution context. For example, a Quarkus-specific implementation would process the annotation at build time instead of doing so at runtime.
operator-framework module now also creates a jar out of its test classes for reuse purposes. This should probably be extracted more cleanly at some point.
This is the module that should now be imported by non-Quarkus apps
The issue is that since the sample code was living under the operator-framework-core module, which doesn't include the annotation processor, the controller implementations were not processed and thus not found by the runtime when needed. This should, hopefully, address the issue.
@@ -18,6 +18,6 @@ public void returnsLatestOfEventType() { | |||
new EventList( | |||
Arrays.asList(mock(Event.class), new TimerEvent("2", null), event2, mock(Event.class))); | |||
|
|||
assertThat(eventList.getLatestOfType(TimerEvent.class).get()).isSameInstanceAs(event2); | |||
Assertions.assertThat(eventList.getLatestOfType(TimerEvent.class).get()).isEqualTo(event2); |
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.
IMO the static import makes it cleaner
bd0e35b
to
d0e3774
Compare
AnnotationValue::asBoolean, | ||
() -> true), | ||
valueOrDefault( | ||
controllerAnnotation, "isClusterScoped", AnnotationValue::asBoolean, () -> false), |
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.
is isClusterScoped
used anywhere?
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 used when the controller is registered with the Operator to know under which scope to register (namespace vs. cluster).
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.
Or at least, it should be but, indeed, it doesn't appear to be used at the moment. I'd keep it, though, because that's an option that we'd want to enable for controllers. That said, I'd rather fix this issue (and possibly others) into subsequent PRs than keeping this one open any longer. It's a pain to maintain and a huge Damocles' sword over people's head :)
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 you point me to the code? Couldn't find it in the changeset.
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.
Or at least, it should be but, indeed, it doesn't appear to be used at the moment. I'd keep it, though, because that's an option that we'd want to enable for controllers. That said, I'd rather fix this issue (and possibly others) into subsequent PRs than keeping this one open any longer. It's a pain to maintain and a huge Damocles' sword over people's head :)
As an alternative, it can be removed from the code and be addressed as part of the relevant issue.
IMHO it Would be good practice to develop a feature that has definition of done.
operator-framework/src/test/java/io/javaoperatorsdk/operator/IntegrationTestSupport.java
Show resolved
Hide resolved
this.crClass = crClass; | ||
this.doneableClassName = doneableClassName; | ||
this.watchAllNamespaces = this.namespaces.contains(WATCH_ALL_NAMESPACES_MARKER); | ||
this.retryConfiguration = |
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.
how can the user configure the retry in quarkus projects?
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 need to add the configuration part, indeed. I will create an issue for it.
Operator operator = new Operator(new DefaultKubernetesClient()); | ||
operator.registerController(new WebServerController()); | ||
Operator operator = new Operator(new DefaultKubernetesClient(), | ||
DefaultConfigurationService.instance()); |
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 not really easy to understand what DefaultConfigurationService is :(.
I think there is a way to make better before the final release.
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 problem is to be able to provide the configuration from the annotation processor in the absence of injection. What would you propose to make this simpler/clearer?
The same thing could apply to DefaultKubernetesClient
for that matter… it shouldn't be exposed either, IMO.
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.
ConfigurationProvider
might be a better 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.
From the user's point of view, there is only one ConfigurationService in the classpath belonging to the imported dependency, so would be best to hide it completely from the user by default.
I'm fine with the current approach and naming though, can become simpler in next iterations.
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.
@psycho-ir the problem is that we cannot put it there by default because then it would be pulled in by the Quarkus implementation as well, which is exactly what I'm trying to avoid 😄
The idea is for Quarkus to be able to replace the default implementation by an implementation computed at build time.