/* * Copyright (c) 2021 ETH Zürich, Educational Development and Technology (LET) * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package ch.ethz.seb.sebserver.webservice; import org.flywaydb.core.Flyway; import org.flywaydb.core.api.MigrationInfo; import org.flywaydb.core.api.MigrationInfoService; import org.flywaydb.core.api.output.ValidateResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.flyway.FlywayMigrationStrategy; import org.springframework.stereotype.Component; import ch.ethz.seb.sebserver.SEBServerInit; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.WebserviceInfoDAO; @Component @WebServiceProfile public class SEBServerMigrationStrategy implements FlywayMigrationStrategy { private static final Logger log = LoggerFactory.getLogger(SEBServerMigrationStrategy.class); private final boolean cleanDBOnStartup; private final WebserviceInfo webserviceInfo; private final WebserviceInfoDAO webserviceInfoDAO; private Flyway flyway; private final boolean migrationApplied = false; public SEBServerMigrationStrategy( final WebserviceInfo webserviceInfo, final WebserviceInfoDAO webserviceInfoDAO, @Value("${sebserver.webservice.clean-db-on-startup:false}") final boolean cleanDBOnStartup) { this.webserviceInfo = webserviceInfo; this.webserviceInfoDAO = webserviceInfoDAO; this.cleanDBOnStartup = cleanDBOnStartup; } @Override public void migrate(final Flyway flyway) { this.flyway = flyway; } public void applyMigration() { final String webserviceUUID = this.webserviceInfo.getWebserviceUUID(); if (this.migrationApplied) { log.warn("Migration already applied for this webservice: {}", webserviceUUID); return; } try { SEBServerInit.INIT_LOGGER.info("----> ** Migration check START **"); SEBServerInit.INIT_LOGGER.info("----> Check database status"); final MigrationInfoService info = this.flyway.info(); if (SEBServerInit.INIT_LOGGER.isDebugEnabled()) { SEBServerInit.INIT_LOGGER.debug("----> ** Migration Info **"); SEBServerInit.INIT_LOGGER.debug("----> {}", info); } final MigrationInfo[] pendingMigrations = info.pending(); if (pendingMigrations != null && pendingMigrations.length > 0) { SEBServerInit.INIT_LOGGER.info("----> Found pending migrations: {}", pendingMigrations.length); // If we are in a distributed setup only apply migration task if this is the master service // or if there was no data base initialization yet at all. if (this.webserviceInfo.isDistributed() && this.webserviceInfoDAO.isInitialized()) { SEBServerInit.INIT_LOGGER.info("----> This is distributed setup, check master..."); if (this.webserviceInfoDAO.isInitialized()) { final boolean isMaster = this.webserviceInfoDAO.isMaster(webserviceUUID); if (!isMaster) { SEBServerInit.INIT_LOGGER.info( "----> Skip migration task since this is not a master instance: {}", this.webserviceInfo.getWebserviceUUID()); } else { doMigration(); } } } else { doMigration(); } } else { SEBServerInit.INIT_LOGGER.info("----> "); SEBServerInit.INIT_LOGGER.info("----> No pending migrations found. Last migration --> {} --> {}", info.current().getVersion(), info.current().getDescription()); } SEBServerInit.INIT_LOGGER.info("----> ** Migration check END **"); } catch (final Exception e) { log.error("Failed to apply migration task: ", e); } } private void doMigration() { SEBServerInit.INIT_LOGGER.info("----> *********************************************************"); SEBServerInit.INIT_LOGGER.info("----> **** Start Migration ************************************"); if (this.cleanDBOnStartup) { SEBServerInit.INIT_LOGGER .info("----> !!! Cleanup database as it was set on sebserver.webservice.clean-db-on-startup !!!"); this.flyway.clean(); } // repair checksum mismatch if needed final ValidateResult validateWithResult = this.flyway.validateWithResult(); if (!validateWithResult.validationSuccessful && validateWithResult.getAllErrorMessages().contains("checksum mismatch")) { SEBServerInit.INIT_LOGGER.info("----> Migration validation checksum mismatch error detected: "); SEBServerInit.INIT_LOGGER.info("----> {}", validateWithResult.getAllErrorMessages()); SEBServerInit.INIT_LOGGER.info("----> Try to run repair task..."); this.flyway.repair(); } this.flyway.migrate(); final MigrationInfoService info = this.flyway.info(); SEBServerInit.INIT_LOGGER.info("----> Migration finished, new current version is: {} --> {}", info.current().getVersion(), info.current().getDescription()); SEBServerInit.INIT_LOGGER.info("----> **** End Migration **************************************"); SEBServerInit.INIT_LOGGER.info("----> *********************************************************"); } }