[KEYCLOAK-19380] - Import not running once schema is inited and requiring full server setup

This commit is contained in:
Pedro Igor 2021-09-23 13:35:18 -03:00
parent 69a146db7e
commit 6e8cd3262d
5 changed files with 50 additions and 47 deletions

View file

@ -19,11 +19,16 @@ package org.keycloak.cli;
import static org.keycloak.cli.Picocli.error; import static org.keycloak.cli.Picocli.error;
import static org.keycloak.cli.Picocli.println; import static org.keycloak.cli.Picocli.println;
import static org.keycloak.exportimport.ExportImportConfig.ACTION_EXPORT;
import static org.keycloak.exportimport.ExportImportConfig.ACTION_IMPORT;
import static org.keycloak.exportimport.Strategy.IGNORE_EXISTING;
import static org.keycloak.exportimport.Strategy.OVERWRITE_EXISTING;
import io.quarkus.bootstrap.runner.RunnerClassLoader; import io.quarkus.bootstrap.runner.RunnerClassLoader;
import org.keycloak.configuration.KeycloakConfigSourceProvider; import org.keycloak.configuration.KeycloakConfigSourceProvider;
import io.quarkus.bootstrap.runner.QuarkusEntryPoint; import io.quarkus.bootstrap.runner.QuarkusEntryPoint;
import org.keycloak.util.Environment; import org.keycloak.util.Environment;
import picocli.CommandLine; import picocli.CommandLine;
import picocli.CommandLine.Command; import picocli.CommandLine.Command;
@ -31,11 +36,7 @@ import picocli.CommandLine.Model.CommandSpec;
import picocli.CommandLine.Option; import picocli.CommandLine.Option;
import picocli.CommandLine.Spec; import picocli.CommandLine.Spec;
import java.lang.reflect.Field; @Command(name = "keycloak",
import java.nio.file.Path;
import java.util.Map;
@Command(name = "keycloak",
usageHelpWidth = 150, usageHelpWidth = 150,
header = "Keycloak - Open Source Identity and Access Management\n\nFind more information at: https://www.keycloak.org/%n", header = "Keycloak - Open Source Identity and Access Management\n\nFind more information at: https://www.keycloak.org/%n",
description = "Use this command-line tool to manage your Keycloak cluster%n", footerHeading = "%nUse \"${COMMAND-NAME} <command> --help\" for more information about a command.%nUse \"${COMMAND-NAME} options\" for a list of all command-line options.", description = "Use this command-line tool to manage your Keycloak cluster%n", footerHeading = "%nUse \"${COMMAND-NAME} <command> --help\" for more information about a command.%nUse \"${COMMAND-NAME} options\" for a list of all command-line options.",
@ -109,8 +110,7 @@ public class MainCommand {
optionListHeading = "%nOptions%n", optionListHeading = "%nOptions%n",
parameterListHeading = "Available Commands%n") parameterListHeading = "Available Commands%n")
public void startDev(@Option(names = "--verbose", description = "Print out more details when running this command.", required = false) Boolean verbose) { public void startDev(@Option(names = "--verbose", description = "Print out more details when running this command.", required = false) Boolean verbose) {
System.setProperty("kc.profile", "dev"); setProfile("dev");
System.setProperty("quarkus.profile", "dev");
KeycloakMain.start(spec.commandLine()); KeycloakMain.start(spec.commandLine());
} }
@ -126,28 +126,13 @@ public class MainCommand {
@Option(names = "--users", arity = "1", description = "Set how users should be exported. Possible values are: skip, realm_file, same_file, different_files.", paramLabel = "<strategy>", defaultValue = "different_files") String users, @Option(names = "--users", arity = "1", description = "Set how users should be exported. Possible values are: skip, realm_file, same_file, different_files.", paramLabel = "<strategy>", defaultValue = "different_files") String users,
@Option(names = "--users-per-file", arity = "1", description = "Set the number of users per file. Its used only if --users=different_files.", paramLabel = "<number>", defaultValue = "50") Integer usersPerFile, @Option(names = "--users-per-file", arity = "1", description = "Set the number of users per file. Its used only if --users=different_files.", paramLabel = "<number>", defaultValue = "50") Integer usersPerFile,
@Option(names = "--verbose", description = "Print out more details when running this command.", required = false) Boolean verbose) { @Option(names = "--verbose", description = "Print out more details when running this command.", required = false) Boolean verbose) {
System.setProperty("keycloak.migration.action", "export");
if (toDir != null) {
System.setProperty("keycloak.migration.provider", "dir");
System.setProperty("keycloak.migration.dir", toDir);
} else if (toFile != null) {
System.setProperty("keycloak.migration.provider", "singleFile");
System.setProperty("keycloak.migration.file", toFile);
} else {
error(spec.commandLine(), "Must specify either --dir or --file options.");
}
System.setProperty("keycloak.migration.usersExportStrategy", users.toUpperCase()); System.setProperty("keycloak.migration.usersExportStrategy", users.toUpperCase());
if (usersPerFile != null) { if (usersPerFile != null) {
System.setProperty("keycloak.migration.usersPerFile", usersPerFile.toString()); System.setProperty("keycloak.migration.usersPerFile", usersPerFile.toString());
} }
if (realm != null) { runImportExport(ACTION_EXPORT, toDir, toFile, realm, verbose);
System.setProperty("keycloak.migration.realmName", realm);
}
KeycloakMain.start(spec.commandLine());
} }
@Command(name = "import", @Command(name = "import",
@ -161,24 +146,9 @@ public class MainCommand {
@Option(names = "--realm", arity = "1", description = "Set the name of the realm to import", paramLabel = "<realm>") String realm, @Option(names = "--realm", arity = "1", description = "Set the name of the realm to import", paramLabel = "<realm>") String realm,
@Option(names = "--override", arity = "1", description = "Set if existing data should be skipped or overridden.", paramLabel = "false", defaultValue = "true") boolean override, @Option(names = "--override", arity = "1", description = "Set if existing data should be skipped or overridden.", paramLabel = "false", defaultValue = "true") boolean override,
@Option(names = "--verbose", description = "Print out more details when running this command.", required = false) Boolean verbose) { @Option(names = "--verbose", description = "Print out more details when running this command.", required = false) Boolean verbose) {
System.setProperty("keycloak.migration.action", "import"); System.setProperty("keycloak.migration.strategy", override ? OVERWRITE_EXISTING.name() : IGNORE_EXISTING.name());
if (toDir != null) {
System.setProperty("keycloak.migration.provider", "dir");
System.setProperty("keycloak.migration.dir", toDir);
} else if (toFile != null) {
System.setProperty("keycloak.migration.provider", "singleFile");
System.setProperty("keycloak.migration.file", toFile);
} else {
error(spec.commandLine(), "Must specify either --dir or --file options.");
}
if (realm != null) { runImportExport(ACTION_IMPORT, toDir, toFile, realm, verbose);
System.setProperty("keycloak.migration.realmName", realm);
}
System.setProperty("keycloak.migration.strategy", override ? "OVERWRITE_EXISTING" : "IGNORE_EXISTING");
KeycloakMain.start(spec.commandLine());
} }
@Command(name = "start", @Command(name = "start",
@ -212,4 +182,25 @@ public class MainCommand {
System.setProperty("kc.show.config", filter); System.setProperty("kc.show.config", filter);
KeycloakMain.start(spec.commandLine()); KeycloakMain.start(spec.commandLine());
} }
private void runImportExport(String action, String toDir, String toFile, String realm, Boolean verbose) {
System.setProperty("keycloak.migration.action", action);
if (toDir != null) {
System.setProperty("keycloak.migration.provider", "dir");
System.setProperty("keycloak.migration.dir", toDir);
} else if (toFile != null) {
System.setProperty("keycloak.migration.provider", "singleFile");
System.setProperty("keycloak.migration.file", toFile);
} else {
error(spec.commandLine(), "Must specify either --dir or --file options.");
}
if (realm != null) {
System.setProperty("keycloak.migration.realmName", realm);
}
setProfile(Environment.IMPORT_EXPORT_MODE);
start(null, verbose);
}
} }

View file

@ -54,7 +54,8 @@ public final class PropertyMappers {
Boolean enabled = Boolean.valueOf(value); Boolean enabled = Boolean.valueOf(value);
ConfigValue proxy = context.proceed(MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX + "proxy"); ConfigValue proxy = context.proceed(MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX + "proxy");
if (Environment.isDevMode() || (proxy != null && "edge".equalsIgnoreCase(proxy.getValue()))) { if (Environment.isDevMode() || Environment.isImportExportMode()
|| (proxy != null && "edge".equalsIgnoreCase(proxy.getValue()))) {
enabled = true; enabled = true;
} }

View file

@ -74,6 +74,7 @@ import org.keycloak.services.ServicesLogger;
import org.keycloak.services.managers.ApplianceBootstrap; import org.keycloak.services.managers.ApplianceBootstrap;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.transaction.JtaTransactionManagerLookup; import org.keycloak.transaction.JtaTransactionManagerLookup;
import org.keycloak.util.Environment;
import org.keycloak.util.JsonSerialization; import org.keycloak.util.JsonSerialization;
/** /**
@ -144,20 +145,20 @@ public final class QuarkusJpaConnectionProviderFactory implements JpaConnectionP
emf = instance.get(); emf = instance.get();
KeycloakSession session = factory.create(); KeycloakSession session = factory.create();
boolean initSchema; boolean schemaChanged;
try (Connection connection = getConnection()) { try (Connection connection = getConnection()) {
createOperationalInfo(connection); createOperationalInfo(connection);
addSpecificNamedQueries(session, connection); addSpecificNamedQueries(session, connection);
initSchema = createOrUpdateSchema(getSchema(), connection, session); schemaChanged = createOrUpdateSchema(getSchema(), connection, session);
} catch (SQLException cause) { } catch (SQLException cause) {
throw new RuntimeException("Failed to update database.", cause); throw new RuntimeException("Failed to update database.", cause);
} finally { } finally {
session.close(); session.close();
} }
if (initSchema || ExportImportConfig.ACTION_EXPORT.equals(ExportImportConfig.getAction())) { if (schemaChanged || Environment.isImportExportMode()) {
runJobInTransaction(factory, this::initSchemaOrExport); runJobInTransaction(factory, this::initSchema);
} }
} }
@ -201,7 +202,7 @@ public final class QuarkusJpaConnectionProviderFactory implements JpaConnectionP
} }
} }
private void initSchemaOrExport(KeycloakSession session) { private void initSchema(KeycloakSession session) {
ExportImportManager exportImportManager = new ExportImportManager(session); ExportImportManager exportImportManager = new ExportImportManager(session);
/* /*

View file

@ -26,6 +26,8 @@ import org.keycloak.configuration.Configuration;
public final class Environment { public final class Environment {
public static final String IMPORT_EXPORT_MODE = "import_export";
public static Boolean isRebuild() { public static Boolean isRebuild() {
return Boolean.valueOf(System.getProperty("quarkus.launch.rebuild")); return Boolean.valueOf(System.getProperty("quarkus.launch.rebuild"));
} }
@ -90,6 +92,10 @@ public final class Environment {
return ProfileManager.getLaunchMode() == LaunchMode.DEVELOPMENT; return ProfileManager.getLaunchMode() == LaunchMode.DEVELOPMENT;
} }
public static boolean isImportExportMode() {
return IMPORT_EXPORT_MODE.equalsIgnoreCase(getProfile());
}
public static boolean isWindows() { public static boolean isWindows() {
return SystemUtils.IS_OS_WINDOWS; return SystemUtils.IS_OS_WINDOWS;
} }

View file

@ -19,6 +19,10 @@ spi.theme.folder.dir=${kc.home.dir:}/themes
%dev.spi.theme.cache-templates=false %dev.spi.theme.cache-templates=false
%dev.spi.theme.static-max-age=-1 %dev.spi.theme.static-max-age=-1
# The default configuration when running in import or export mode
%import_export.http.enabled=true
%import_export.cluster=local
# Logging configuration. INFO is the default level for most of the categories # Logging configuration. INFO is the default level for most of the categories
#quarkus.log.level = DEBUG #quarkus.log.level = DEBUG
quarkus.log.category."org.jboss.resteasy.resteasy_jaxrs.i18n".level=WARN quarkus.log.category."org.jboss.resteasy.resteasy_jaxrs.i18n".level=WARN