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

Improve error feedback for Keycloak dev service startup #28533

Merged
merged 1 commit into from
Oct 12, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -181,17 +181,24 @@ public DevServicesResultBuildItem startKeycloakContainer(
}
capturedDevServicesConfiguration = currentDevServicesConfiguration;
StartupLogCompressor compressor = new StartupLogCompressor(
(launchMode.isTest() ? "(test) " : "") + "KeyCloak Dev Services Starting:",
(launchMode.isTest() ? "(test) " : "") + "Keycloak Dev Services Starting:",
consoleInstalledBuildItem, loggingSetupBuildItem);
if (vertxInstance == null) {
vertxInstance = Vertx.vertx();
}
try {
List<String> errors = new ArrayList<>();

RunningDevService newDevService = startContainer(dockerStatusBuildItem, keycloakBuildItemBuildProducer,
!devServicesSharedNetworkBuildItem.isEmpty(),
devServicesConfig.timeout);
devServicesConfig.timeout,
errors);
if (newDevService == null) {
compressor.close();
if (errors.isEmpty()) {
compressor.close();
} else {
compressor.closeAndDumpCaptured();
}
return null;
}

Expand Down Expand Up @@ -227,10 +234,10 @@ public void run() {
}

capturedRealmFileLastModifiedDate = getRealmFileLastModifiedDate(capturedDevServicesConfiguration.realmPath);
if (devService == null) {
compressor.closeAndDumpCaptured();
} else {
if (devService != null && errors.isEmpty()) {
compressor.close();
} else {
compressor.closeAndDumpCaptured();
}
} catch (Throwable t) {
compressor.closeAndDumpCaptured();
Expand All @@ -241,14 +248,14 @@ public void run() {
return devService.toBuildItem();
}

private String startURL(String host, Integer port, boolean isKeyCloakX) {
return "http://" + host + ":" + port + (isKeyCloakX ? "" : "/auth");
private String startURL(String host, Integer port, boolean isKeycloakX) {
return "http://" + host + ":" + port + (isKeycloakX ? "" : "/auth");
}

private Map<String, String> prepareConfiguration(
BuildProducer<KeycloakDevServicesConfigBuildItem> keycloakBuildItemBuildProducer, String internalURL,
String hostURL, RealmRepresentation realmRep,
boolean keycloakX) {
boolean keycloakX, List<String> errors) {
final String realmName = realmRep != null ? realmRep.getRealm() : getDefaultRealmName();
final String authServerInternalUrl = realmsURL(internalURL, realmName);

Expand All @@ -266,9 +273,10 @@ private Map<String, String> prepareConfiguration(
try {
String adminToken = getAdminToken(client, clientAuthServerBaseUrl);
if (createDefaultRealm) {
createDefaultRealm(client, adminToken, clientAuthServerBaseUrl, users, oidcClientId, oidcClientSecret);
createDefaultRealm(client, adminToken, clientAuthServerBaseUrl, users, oidcClientId, oidcClientSecret,
errors);
} else if (realmRep != null && keycloakX) {
createRealm(client, adminToken, clientAuthServerBaseUrl, realmRep);
createRealm(client, adminToken, clientAuthServerBaseUrl, realmRep, errors);
}
} finally {
client.close();
Expand Down Expand Up @@ -300,7 +308,8 @@ private String getDefaultRealmName() {

private RunningDevService startContainer(DockerStatusBuildItem dockerStatusBuildItem,
BuildProducer<KeycloakDevServicesConfigBuildItem> keycloakBuildItemBuildProducer,
boolean useSharedNetwork, Optional<Duration> timeout) {
boolean useSharedNetwork, Optional<Duration> timeout,
List<String> errors) {
if (!capturedDevServicesConfiguration.enabled) {
// explicitly disabled
LOG.debug("Not starting Dev Services for Keycloak as it has been disabled in the config");
Expand Down Expand Up @@ -342,7 +351,8 @@ private RunningDevService startContainer(DockerStatusBuildItem dockerStatusBuild
capturedDevServicesConfiguration.shared,
capturedDevServicesConfiguration.javaOpts,
capturedDevServicesConfiguration.startCommand,
capturedDevServicesConfiguration.showLogs);
capturedDevServicesConfiguration.showLogs,
errors);

timeout.ifPresent(oidcContainer::withStartupTimeout);
oidcContainer.start();
Expand All @@ -356,7 +366,8 @@ private RunningDevService startContainer(DockerStatusBuildItem dockerStatusBuild

Map<String, String> configs = prepareConfiguration(keycloakBuildItemBuildProducer, internalUrl, hostUrl,
oidcContainer.realmRep,
oidcContainer.keycloakX);
oidcContainer.keycloakX,
errors);
return new RunningDevService(KEYCLOAK_CONTAINER_NAME, oidcContainer.getContainerId(),
oidcContainer::close, configs);
};
Expand All @@ -366,7 +377,7 @@ private RunningDevService startContainer(DockerStatusBuildItem dockerStatusBuild
// TODO: this probably needs to be addressed
Map<String, String> configs = prepareConfiguration(keycloakBuildItemBuildProducer,
getSharedContainerUrl(containerAddress),
getSharedContainerUrl(containerAddress), null, false);
getSharedContainerUrl(containerAddress), null, false, errors);
return new RunningDevService(KEYCLOAK_CONTAINER_NAME, containerAddress.getId(), null, configs);
})
.orElseGet(defaultKeycloakContainerSupplier);
Expand Down Expand Up @@ -395,10 +406,12 @@ private static class QuarkusOidcContainer extends GenericContainer<QuarkusOidcCo
private RealmRepresentation realmRep;
private final Optional<String> startCommand;
private final boolean showLogs;
private final List<String> errors;

public QuarkusOidcContainer(DockerImageName dockerImageName, OptionalInt fixedExposedPort, boolean useSharedNetwork,
Optional<String> realmPath, String containerLabelValue,
boolean sharedContainer, Optional<String> javaOpts, Optional<String> startCommand, boolean showLogs) {
boolean sharedContainer, Optional<String> javaOpts, Optional<String> startCommand, boolean showLogs,
List<String> errors) {
super(dockerImageName);

this.useSharedNetwork = useSharedNetwork;
Expand All @@ -418,6 +431,7 @@ public QuarkusOidcContainer(DockerImageName dockerImageName, OptionalInt fixedEx
this.fixedExposedPort = fixedExposedPort;
this.startCommand = startCommand;
this.showLogs = showLogs;
this.errors = errors;

super.setWaitStrategy(Wait.forLogMessage(".*Keycloak.*started.*", 1));
}
Expand Down Expand Up @@ -468,7 +482,7 @@ protected void configure() {
if (realmPath.isPresent()) {
URL realmPathUrl = null;
if ((realmPathUrl = Thread.currentThread().getContextClassLoader().getResource(realmPath.get())) != null) {
realmRep = readRealmFile(realmPathUrl, realmPath.get());
realmRep = readRealmFile(realmPathUrl, realmPath.get(), errors);
if (!keycloakX) {
withClasspathResourceMapping(realmPath.get(), KEYCLOAK_DOCKER_REALM_PATH, BindMode.READ_ONLY);
}
Expand All @@ -478,9 +492,11 @@ protected void configure() {
if (!keycloakX) {
withFileSystemBind(realmPath.get(), KEYCLOAK_DOCKER_REALM_PATH, BindMode.READ_ONLY);
}
realmRep = readRealmFile(filePath.toUri(), realmPath.get());
realmRep = readRealmFile(filePath.toUri(), realmPath.get(), errors);
} else {
LOG.debugf("Realm %s resource is not available", realmPath.get());
errors.add(String.format("Realm %s resource is not available", realmPath.get()));
Copy link
Member Author

Choose a reason for hiding this comment

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

I put the full error message here but it's actually not used, it's just a marker.


LOG.errorf("Realm %s resource is not available", realmPath.get());
}
}

Expand All @@ -507,21 +523,23 @@ private Integer findRandomPort() {
}
}

private RealmRepresentation readRealmFile(URI uri, String realmPath) {
private RealmRepresentation readRealmFile(URI uri, String realmPath, List<String> errors) {
try {
return readRealmFile(uri.toURL(), realmPath);
return readRealmFile(uri.toURL(), realmPath, errors);
} catch (MalformedURLException ex) {
// Will not happen as this method is called only when it is confirmed the file exists
throw new RuntimeException(ex);
}
}

private RealmRepresentation readRealmFile(URL url, String realmPath) {
private RealmRepresentation readRealmFile(URL url, String realmPath, List<String> errors) {
try {
try (InputStream is = url.openStream()) {
return JsonSerialization.readValue(is, RealmRepresentation.class);
}
} catch (IOException ex) {
errors.add(String.format("Realm %s resource can not be opened: %s", realmPath, ex.getMessage()));

LOG.errorf("Realm %s resource can not be opened: %s", realmPath, ex.getMessage());
}
return null;
Expand Down Expand Up @@ -578,15 +596,16 @@ private FileTime getRealmFileLastModifiedDate(Optional<String> realm) {

private void createDefaultRealm(WebClient client, String token, String keycloakUrl, Map<String, String> users,
String oidcClientId,
String oidcClientSecret) {
String oidcClientSecret,
List<String> errors) {
RealmRepresentation realm = createDefaultRealmRep();

realm.getClients().add(createClient(oidcClientId, oidcClientSecret));
for (Map.Entry<String, String> entry : users.entrySet()) {
realm.getUsers().add(createUser(entry.getKey(), entry.getValue(), getUserRoles(entry.getKey())));
}

createRealm(client, token, keycloakUrl, realm);
createRealm(client, token, keycloakUrl, realm, errors);
}

private String getAdminToken(WebClient client, String keycloakUrl) {
Expand All @@ -602,7 +621,8 @@ private String getAdminToken(WebClient client, String keycloakUrl) {
return null;
}

private void createRealm(WebClient client, String token, String keycloakUrl, RealmRepresentation realm) {
private void createRealm(WebClient client, String token, String keycloakUrl, RealmRepresentation realm,
List<String> errors) {
try {
LOG.tracef("Creating the realm %s", realm.getRealm());
HttpResponse<Buffer> createRealmResponse = client.postAbs(keycloakUrl + "/admin/realms")
Expand All @@ -612,6 +632,10 @@ private void createRealm(WebClient client, String token, String keycloakUrl, Rea
.await().atMost(oidcConfig.devui.webClientTimeout);

if (createRealmResponse.statusCode() > 299) {
errors.add(String.format("Realm %s can not be created %d - %s ", realm.getRealm(),
createRealmResponse.statusCode(),
createRealmResponse.statusMessage()));

LOG.errorf("Realm %s can not be created %d - %s ", realm.getRealm(), createRealmResponse.statusCode(),
createRealmResponse.statusMessage());
}
Expand All @@ -635,6 +659,8 @@ private void createRealm(WebClient client, String token, String keycloakUrl, Rea
});
realmStatusCodeUni.await().atMost(Duration.ofSeconds(10));
} catch (Throwable t) {
errors.add(String.format("Realm %s can not be created: %s", realm.getRealm(), t.getMessage()));

LOG.errorf("Realm %s can not be created: %s", realm.getRealm(), t.getMessage());
}
}
Expand Down