Skip to content
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

Introduce ApplicationConfig #1683

Merged
merged 1 commit into from
Mar 26, 2019
Merged

Introduce ApplicationConfig #1683

merged 1 commit into from
Mar 26, 2019

Conversation

geoand
Copy link
Contributor

@geoand geoand commented Mar 25, 2019

This allows users to set a desired name for the applications
(using quarkus.application.name) or version.
The idea came from:

#1300 (comment)

and this configuration is meant to be used by extensions that for some
reason need this information (like the planned kubernetes extension, where we need to inject something like ApplicationConfig in the processor)

Implementation notes:

I am not really sure if this is the simplest solution - it kind of seems like I went overboard...

The idea is to inject an ApplicationInfoBuildItem that has the default values, use that in ConfigurationSetup#initializeConfiguration to create a new ConfigSource with the default values.
This new source has a lower ordinal that the application.properties source and thus if values are set there (or in any of the sources with even higher ordinal), those values will be used.

If there is a simpler solution for creating the ApplicationConfig and populating it from with the values from the build, I'd love to hear it and implement it :)

@geoand geoand requested a review from dmlloyd March 25, 2019 17:16
builder.withSources(
inJar,
// the ordinal of 240 because it's slightly lower priority then what inJar uses
new PropertiesConfigSource(appStateProperties, "appState", 240));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't the right way to set default values.

The best way to do it is to just use the defaultValue property on the @ConfigItem. The second-best way is to just implement whatever default behavior you want when the properties are not present in the config object. The third-best way would be to produce default value build items. Adding a config source doesn't even make the list unfortunately. ;-)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you (or anyone) find yourself modifying the core configuration code or the core mojos or main methods in order to add a configuration switch, then a wrong turn was taken at some point. The configuration and build item infrastructures exist so that we don't have to do these things.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really wanted to use defaultValue, but the problem is that default needs to be dynamic, in the sense that it depends on what is in the build.
My idea was that the "client" processors would just inject the ApplicationConfig and not have to worry about how to set default values if users don't.

So just to verify, what your proposing is that the processors would inject ApplicationConfig which would contain whatever the users set and then would also have to inject the default values in some other way?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The build step (singular) would accept the config and produce the build item with the actual app name in it. The build step would also calculate the default value for the build item in the event that it was not given in the config. Everything which needs the application name and/or version would consume the build item.

Copy link
Contributor Author

@geoand geoand Mar 25, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, got it thanks for the explanation!
So I implemented it the other way around. But I still don't understand how I would pull the default values (like the artifactId for the name) unless I am pushing them in when setting up the Augmentor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The kubernetes extension would definitely need those values as well (by the means of injecting a build item that contains the final values).
I really like the idea of having these values settable in application.properties, but I think it would require a fair amount of work. WDYT?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As long as the Kube extension just consumed that build item, and assuming it was produced as I described above, it should just work with a minimum of effort.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having the extension read the config should be easy once everything is in place. The difficulty I see is having all the config (like wiring classes) driven by application.properties

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see. Well it doesn't make sense to force 100% of everything through properties. It's more like two polar endpoints: at one end, all application-wide config must be driven by application.properties, and at the other end, any per-class or per-member behavior should be driven by annotations. In between is where we consider factors to determine if it makes sense to make some configuration be driven one way and some the other, or whether to allow both.

No matter how it goes from the input stage, the next stage is to feed these into build items, so that consumers don't actually care where they came from.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 I will rework this PR starting tomorrow so we have something more concrete to comment on 😊

@@ -54,6 +58,9 @@ public static void main(String... args) throws Exception {
classesRoot = new File(args[0]);
wiringDir = new File(args[1]);
cacheDir = new File(args[2]);
group = args[3];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like we shouldn't be passing this in this way; the input should simply be the build configuration.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that this is not cool, but I am not clear on how to pass the build configuration to the runtime runner

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "normal" approach would be to rely 100% on the configuration value and use a config root whose visibility is BUILD_AND_RUN_TIME_FIXED. However as discussed above, this wouldn't suffice in the case where no value was given and the default has to be computed.

So, we have to bring it in some other way. There are a few possibilities off the top of my head:

  • Produce a resource that contains the application name & version and load it at boot using a static init build step
  • Put it in a MANIFEST.MF property and load it at boot using a static init build step
  • Just generate a class with fields containing the name and version, hard-coded to the computed name and version

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is exactly the info I needed to close the loop, thank you! Now everything makes sense. I hadn't seen the any relevant parts of the code so I didn't know how to handle such cases, but with the explanation you just provided plus the information from the other comment I see the way forward.

I'll pick this up again tomorrow most likely and come up with proper solution that adheres to these guidelines.

Thanks for taking the time to explain!

@@ -84,6 +85,11 @@ public BuildResult run() throws Exception {
.addInitial(LaunchModeBuildItem.class)
.addInitial(AdditionalApplicationArchiveBuildItem.class)
.addInitial(ExtensionClassLoaderBuildItem.class);

if (!applicationInfo.isUnset()) {
chainBuilder.addInitial(ApplicationInfoBuildItem.class);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could just as well be produced from a build step which consumes the ApplicationConfig object.

@@ -103,6 +109,11 @@ public BuildResult run() throws Exception {
.produce(new ShutdownContextBuildItem())
.produce(new LaunchModeBuildItem(launchMode))
.produce(new ExtensionClassLoaderBuildItem(classLoader));

if (!applicationInfo.isUnset()) {
execBuilder.produce(new ApplicationInfoBuildItem(applicationInfo));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

@geoand
Copy link
Contributor Author

geoand commented Mar 26, 2019

@dmlloyd I pushed a completely revised version. It should be simpler and move inline with the internal Quarkus philosophy ( I hope :) ). The names are probably bad, since I am pretty terrible at naming...
Comments obviously more than welcome.

@geoand geoand requested a review from dmlloyd March 26, 2019 11:28
@geoand geoand force-pushed the appconfig branch 2 times, most recently from a687249 to 81d61b6 Compare March 26, 2019 12:20
Copy link
Member

@dmlloyd dmlloyd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The passing of values through a properties file isn't quite what I had in mind, but it's OK because we don't really have anything better at the moment. I'll take on an issue to improve that.

@dmlloyd
Copy link
Member

dmlloyd commented Mar 26, 2019

Pending CI.

@geoand
Copy link
Contributor Author

geoand commented Mar 26, 2019

@dmlloyd Just out of curiosity, what do you have in mind as far as improvements go?
Also FYI, I'm probably going to need to add more properties (coming from the build environment like wiring-classes) for the kubernetes extension.

@dmlloyd
Copy link
Member

dmlloyd commented Mar 26, 2019

I've opened #1693 with more info on that.

@geoand
Copy link
Contributor Author

geoand commented Mar 26, 2019

Cool

@geoand
Copy link
Contributor Author

geoand commented Mar 26, 2019

The native test seems to be failing with:

Error: Class initialization failed: io.quarkus.runtime.generated.BuildTimeConfig
Original exception that caused the problem: java.lang.NoClassDefFoundError: io/quarkus/deployment/ApplicationConfig$$accessor

in HibernateValidatorFunctionalityTest.

This seems pretty weird... Is there anything that you see that I have missed @dmlloyd ?

@dmlloyd
Copy link
Member

dmlloyd commented Mar 26, 2019

Yes, I see the bug. The config class is in the deployment module but it has a run time retention.

Since you're using build items anyway, the config scope for that ConfigRoot should just be BUILD_TIME.

This allows users to set a desired name for the applications
(using quarkus.application.name) or version.
The idea came from:

quarkusio#1300 (comment)

and this configuration is meant to be used by extensions that for some
reason need this information (like the planned kubernetes extension)
@geoand
Copy link
Contributor Author

geoand commented Mar 26, 2019

Thanks! PR updated

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants