-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Config viewer as part of vertx-http in dev mode #7430
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package io.quarkus.vertx.http.configviewer; | ||
|
||
import static io.restassured.RestAssured.when; | ||
import static org.hamcrest.Matchers.hasItem; | ||
|
||
import org.jboss.shrinkwrap.api.ShrinkWrap; | ||
import org.jboss.shrinkwrap.api.asset.StringAsset; | ||
import org.jboss.shrinkwrap.api.spec.JavaArchive; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.extension.RegisterExtension; | ||
|
||
import io.quarkus.test.QuarkusDevModeTest; | ||
import io.restassured.http.ContentType; | ||
|
||
public class ShowConfigTest { | ||
|
||
@RegisterExtension | ||
static final QuarkusDevModeTest test = new QuarkusDevModeTest() | ||
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) | ||
.addAsResource(new StringAsset("foo=bar"), "application.properties")); | ||
|
||
@Test | ||
void testConfig() { | ||
when().get("/config").then() | ||
.statusCode(200) | ||
.contentType(ContentType.JSON) | ||
.body("sources.properties.foo", hasItem("bar")); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,6 +50,10 @@ | |
</exclusion> | ||
</exclusions> | ||
</dependency> | ||
<dependency> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this needed? Isn't the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've tried w/o, but got a `java.lang.ClassNotFoundException:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah yes, that is because we exclude Jackson databind - and we need to continue doing this, we can't let it sneak in. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, using JSON Object "encode" requires Jackson, which we want to avoid in vertx-http. It may require a bit of code, but in your case, Jackson should not be required if you just implement a simple "encode" method doing the ToJson transformation manually. As you know the structure of the result, you can just generate the JSON string. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, I'm going to remove the dependency to Jackson and do the JSON encoding manually. |
||
<groupId>io.vertx</groupId> | ||
<artifactId>vertx-core</artifactId> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package io.quarkus.vertx.http.runtime.devmode; | ||
|
||
import javax.inject.Inject; | ||
|
||
import org.eclipse.microprofile.config.Config; | ||
|
||
public class ConfigHolder { | ||
|
||
@Inject | ||
Config config; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package io.quarkus.vertx.http.runtime.devmode; | ||
|
||
import java.util.Set; | ||
import java.util.SortedSet; | ||
import java.util.TreeSet; | ||
|
||
import org.eclipse.microprofile.config.Config; | ||
import org.eclipse.microprofile.config.spi.ConfigSource; | ||
import org.jboss.logging.Logger; | ||
|
||
import io.vertx.core.json.JsonArray; | ||
import io.vertx.core.json.JsonObject; | ||
|
||
/** | ||
* Turns a {@link Config} into a JSON object with all config sources and properties as JSON. The config sources are | ||
* sorted descending by ordinal, the properties by name. If no config is defined an empty JSON object is returned. | ||
* | ||
* <p> | ||
* A typical output might look like: | ||
* </p> | ||
* | ||
* <pre> | ||
* { | ||
* "sources": [ | ||
* { | ||
* "source": "source0", | ||
* "ordinal": 200, | ||
* "properties": { | ||
* "key": "value" | ||
* } | ||
* }, | ||
* { | ||
* "source": "source1", | ||
* "ordinal": 100, | ||
* "properties": { | ||
* "key": "value" | ||
* } | ||
* } | ||
* ] | ||
* } | ||
* </pre> | ||
*/ | ||
class ConfigViewer { | ||
|
||
private static final Logger LOGGER = Logger.getLogger(ConfigViewer.class.getName()); | ||
|
||
JsonObject dump(Config config) { | ||
JsonObject json = new JsonObject(); | ||
if (config != null) { | ||
if (config.getConfigSources().iterator().hasNext()) { | ||
JsonArray jsonSources = new JsonArray(); | ||
for (ConfigSource source : config.getConfigSources()) { | ||
JsonObject jsonSource = new JsonObject(); | ||
jsonSource.put("source", source.getName()) | ||
.put("ordinal", source.getOrdinal()); | ||
Set<String> propertyNames = source.getPropertyNames(); | ||
if (!propertyNames.isEmpty()) { | ||
SortedSet<String> sortedPropertyNames = new TreeSet<>(propertyNames); | ||
JsonObject jsonProperties = new JsonObject(); | ||
for (String propertyName : sortedPropertyNames) { | ||
try { | ||
jsonProperties.put(propertyName, source.getValue(propertyName)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like this is going to print every config value from every config source (as opposed to printing only the effective values). I assume that this was your intent! One concern I have is that this will expand property expressions. If you don't want that (and I suspect you don't since you're printing all the raw config keys rather than just the effective configuration contents), then the whole thing should be enclosed like this: boolean old = ExpandingConfigSource.setExpanding(false);
try {
// ... do all the work here ...
} finally {
ExpandingConfigSource.setExpanding(old);
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another concern I have is that this might expose secrets/passwords! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks @dmlloyd I don't have a solution how to hide secrets / passwords. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let me post something to the dev list on this. I have an idea... I think. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually I'll post an issue for it... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've opened #7442 for this. |
||
} catch (Throwable t) { | ||
LOGGER.errorf("Cannot get configuration value for '%s': %s", | ||
propertyName, t.getMessage()); | ||
} | ||
} | ||
jsonSource.put("properties", jsonProperties); | ||
} | ||
jsonSources.add(jsonSource); | ||
} | ||
json.put("sources", jsonSources); | ||
} | ||
} | ||
return json; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package io.quarkus.vertx.http.runtime.devmode; | ||
|
||
import javax.enterprise.inject.spi.CDI; | ||
|
||
import io.vertx.core.Handler; | ||
import io.vertx.core.buffer.Buffer; | ||
import io.vertx.core.http.HttpServerResponse; | ||
import io.vertx.core.json.JsonObject; | ||
import io.vertx.ext.web.RoutingContext; | ||
|
||
public class ConfigViewerHandler implements Handler<RoutingContext> { | ||
|
||
@Override | ||
public void handle(RoutingContext routingContext) { | ||
ConfigHolder configHolder = CDI.current().select(ConfigHolder.class).get(); | ||
JsonObject json = new ConfigViewer().dump(configHolder.config); | ||
HttpServerResponse resp = routingContext.response(); | ||
resp.putHeader("content-type", "application/json"); | ||
resp.end(Buffer.buffer(json.encode())); | ||
} | ||
} |
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 dependency is already defined in the vert.x bom. Isn't it?