KEYCLOAK-3141 Fix DB2 and some other DB issues

This commit is contained in:
mposolda 2016-06-22 17:05:29 +02:00
parent e2082ce29f
commit f7a2ad021e
4 changed files with 89 additions and 58 deletions

View file

@ -48,32 +48,35 @@ public class LiquibaseDBLockProvider implements DBLockProvider {
private CustomLockService lockService;
private Connection dbConnection;
private boolean initialized = false;
private int maxAttempts = DEFAULT_MAX_ATTEMPTS;
public LiquibaseDBLockProvider(LiquibaseDBLockProviderFactory factory, KeycloakSession session) {
this.factory = factory;
this.session = session;
init();
}
private void init() {
LiquibaseConnectionProvider liquibaseProvider = session.getProvider(LiquibaseConnectionProvider.class);
JpaConnectionProviderFactory jpaProviderFactory = (JpaConnectionProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(JpaConnectionProvider.class);
private void lazyInit() {
if (!initialized) {
LiquibaseConnectionProvider liquibaseProvider = session.getProvider(LiquibaseConnectionProvider.class);
JpaConnectionProviderFactory jpaProviderFactory = (JpaConnectionProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(JpaConnectionProvider.class);
this.dbConnection = jpaProviderFactory.getConnection();
String defaultSchema = jpaProviderFactory.getSchema();
this.dbConnection = jpaProviderFactory.getConnection();
String defaultSchema = jpaProviderFactory.getSchema();
try {
Liquibase liquibase = liquibaseProvider.getLiquibase(dbConnection, defaultSchema);
try {
Liquibase liquibase = liquibaseProvider.getLiquibase(dbConnection, defaultSchema);
this.lockService = new CustomLockService();
lockService.setChangeLogLockWaitTime(factory.getLockWaitTimeoutMillis());
lockService.setDatabase(liquibase.getDatabase());
} catch (LiquibaseException exception) {
safeRollbackConnection();
safeCloseConnection();
throw new IllegalStateException(exception);
this.lockService = new CustomLockService();
lockService.setChangeLogLockWaitTime(factory.getLockWaitTimeoutMillis());
lockService.setDatabase(liquibase.getDatabase());
initialized = true;
} catch (LiquibaseException exception) {
safeRollbackConnection();
safeCloseConnection();
throw new IllegalStateException(exception);
}
}
}
@ -82,12 +85,15 @@ public class LiquibaseDBLockProvider implements DBLockProvider {
safeCloseConnection();
this.dbConnection = null;
this.lockService = null;
init();
initialized = false;
lazyInit();
}
@Override
public void waitForLock() {
lazyInit();
while (maxAttempts > 0) {
try {
lockService.waitForLock();
@ -110,6 +116,8 @@ public class LiquibaseDBLockProvider implements DBLockProvider {
@Override
public void releaseLock() {
lazyInit();
lockService.releaseLock();
lockService.reset();
factory.setHasLock(false);
@ -128,6 +136,8 @@ public class LiquibaseDBLockProvider implements DBLockProvider {
@Override
public void destroyLockInfo() {
lazyInit();
try {
this.lockService.destroy();
dbConnection.commit();
@ -154,7 +164,7 @@ public class LiquibaseDBLockProvider implements DBLockProvider {
}
private void safeCloseConnection() {
// Close after creating EntityManagerFactory to prevent in-mem databases from closing
// Close to prevent in-mem databases from closing
if (dbConnection != null) {
try {
dbConnection.close();

View file

@ -32,4 +32,6 @@
<include file="META-INF/jpa-changelog-1.9.0.xml"/>
<include file="META-INF/db2-jpa-changelog-1.9.1.xml"/>
<include file="META-INF/jpa-changelog-1.9.2.xml"/>
<include file="META-INF/jpa-changelog-authz-master.xml"/>
</databaseChangeLog>

View file

@ -27,6 +27,7 @@ import org.keycloak.migration.MigrationModelManager;
import org.keycloak.models.*;
import org.keycloak.models.dblock.DBLockProvider;
import org.keycloak.models.dblock.DBLockManager;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.PostMigrationEvent;
import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.RealmRepresentation;
@ -91,53 +92,28 @@ public class KeycloakApplication extends Application {
singletons.add(new ObjectMapperResolver(Boolean.parseBoolean(System.getProperty("keycloak.jsonPrettyPrint", "false"))));
ExportImportManager exportImportManager;
ExportImportManager[] exportImportManager = new ExportImportManager[1];
DBLockManager dbLockManager = new DBLockManager(sessionFactory.create());
dbLockManager.checkForcedUnlock();
DBLockProvider dbLock = dbLockManager.getDBLock();
dbLock.waitForLock();
try {
migrateModel();
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
KeycloakSession session = sessionFactory.create();
try {
session.getTransaction().begin();
ApplianceBootstrap applianceBootstrap = new ApplianceBootstrap(session);
exportImportManager = new ExportImportManager(session);
boolean createMasterRealm = applianceBootstrap.isNewInstall();
if (exportImportManager.isRunImport() && exportImportManager.isImportMasterIncluded()) {
createMasterRealm = false;
@Override
public void run(KeycloakSession lockSession) {
DBLockManager dbLockManager = new DBLockManager(lockSession);
dbLockManager.checkForcedUnlock();
DBLockProvider dbLock = dbLockManager.getDBLock();
dbLock.waitForLock();
try {
exportImportManager[0] = migrateAndBootstrap();
} finally {
dbLock.releaseLock();
}
if (createMasterRealm) {
applianceBootstrap.createMasterRealm(contextPath);
}
session.getTransaction().commit();
} catch (RuntimeException re) {
if (session.getTransaction().isActive()) {
session.getTransaction().rollback();
}
throw re;
} finally {
session.close();
}
if (exportImportManager.isRunImport()) {
exportImportManager.runImport();
} else {
importRealms();
}
});
importAddUser();
} finally {
dbLock.releaseLock();
}
if (exportImportManager.isRunExport()) {
exportImportManager.runExport();
if (exportImportManager[0].isRunExport()) {
exportImportManager[0].runExport();
}
boolean bootstrapAdminUser = false;
@ -158,6 +134,49 @@ public class KeycloakApplication extends Application {
setupScheduledTasks(sessionFactory);
}
// Migrate model, bootstrap master realm, import realms and create admin user. This is done with acquired dbLock
protected ExportImportManager migrateAndBootstrap() {
ExportImportManager exportImportManager;
migrateModel();
KeycloakSession session = sessionFactory.create();
try {
session.getTransaction().begin();
ApplianceBootstrap applianceBootstrap = new ApplianceBootstrap(session);
exportImportManager = new ExportImportManager(session);
boolean createMasterRealm = applianceBootstrap.isNewInstall();
if (exportImportManager.isRunImport() && exportImportManager.isImportMasterIncluded()) {
createMasterRealm = false;
}
if (createMasterRealm) {
applianceBootstrap.createMasterRealm(contextPath);
}
session.getTransaction().commit();
} catch (RuntimeException re) {
if (session.getTransaction().isActive()) {
session.getTransaction().rollback();
}
throw re;
} finally {
session.close();
}
if (exportImportManager.isRunImport()) {
exportImportManager.runImport();
} else {
importRealms();
}
importAddUser();
return exportImportManager;
}
protected void migrateModel() {
KeycloakSession session = sessionFactory.create();
try {

View file

@ -49,7 +49,7 @@ log4j.logger.org.keycloak.connections.jpa.updater.liquibase=${keycloak.liquibase
# Enable to view database updates
# log4j.logger.org.keycloak.connections.mongo.updater.DefaultMongoUpdaterProvider=debug
# log4j.logger.org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory=debug
log4j.logger.org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory=${keycloak.liquibase.logging.level}
# log4j.logger.org.keycloak.migration.MigrationModelManager=debug
# Enable to view hibernate statistics