mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-15 22:13:08 +00:00
Auto-verify pgcrypto installed and up-to-date. Provide tips/hints via 'database info' command.
This commit is contained in:
@@ -73,6 +73,11 @@ public class DatabaseUtils
|
|||||||
public static final String DBMS_ORACLE="oracle";
|
public static final String DBMS_ORACLE="oracle";
|
||||||
public static final String DBMS_H2="h2";
|
public static final String DBMS_H2="h2";
|
||||||
|
|
||||||
|
// PostgreSQL pgcrypto extention name, and required versions of Postgres & pgcrypto
|
||||||
|
public static final String PGCRYPTO="pgcrypto";
|
||||||
|
public static final Double PGCRYPTO_VERSION=1.1;
|
||||||
|
public static final Double POSTGRES_VERSION=9.4;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Commandline tools for managing database changes, etc.
|
* Commandline tools for managing database changes, etc.
|
||||||
* @param argv
|
* @param argv
|
||||||
@@ -122,17 +127,28 @@ public class DatabaseUtils
|
|||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(argv[0].equalsIgnoreCase("info"))
|
else if(argv[0].equalsIgnoreCase("info") || argv[0].equalsIgnoreCase("status"))
|
||||||
{
|
{
|
||||||
try(Connection connection = dataSource.getConnection())
|
try(Connection connection = dataSource.getConnection())
|
||||||
{
|
{
|
||||||
// Get basic Database info
|
// Get basic Database info
|
||||||
DatabaseMetaData meta = connection.getMetaData();
|
DatabaseMetaData meta = connection.getMetaData();
|
||||||
System.out.println("\nDatabase URL: " + meta.getURL());
|
String dbType = getDbType(connection);
|
||||||
|
System.out.println("\nDatabase Type: " + dbType);
|
||||||
|
System.out.println("Database URL: " + meta.getURL());
|
||||||
System.out.println("Database Schema: " + getSchemaName(connection));
|
System.out.println("Database Schema: " + getSchemaName(connection));
|
||||||
System.out.println("Database Software: " + meta.getDatabaseProductName() + " version " + meta.getDatabaseProductVersion());
|
System.out.println("Database Software: " + meta.getDatabaseProductName() + " version " + meta.getDatabaseProductVersion());
|
||||||
System.out.println("Database Driver: " + meta.getDriverName() + " version " + meta.getDriverVersion());
|
System.out.println("Database Driver: " + meta.getDriverName() + " version " + meta.getDriverVersion());
|
||||||
|
|
||||||
|
// For Postgres, report whether pgcrypto is installed
|
||||||
|
// (If it isn't, we'll also write out warnings...see below)
|
||||||
|
if(dbType.equals(DBMS_POSTGRES))
|
||||||
|
{
|
||||||
|
boolean pgcryptoUpToDate = DatabaseUtils.isPgcryptoUpToDate();
|
||||||
|
Double pgcryptoVersion = getPgcryptoInstalledVersion(connection);
|
||||||
|
System.out.println("PostgreSQL '" + PGCRYPTO + "' extension installed/up-to-date? " + pgcryptoUpToDate + " " + ((pgcryptoVersion!=null) ? "(version=" + pgcryptoVersion + ")" : "(not installed)"));
|
||||||
|
}
|
||||||
|
|
||||||
// Get info table from Flyway
|
// Get info table from Flyway
|
||||||
System.out.println("\n" + MigrationInfoDumper.dumpToAsciiTable(flyway.info().all()));
|
System.out.println("\n" + MigrationInfoDumper.dumpToAsciiTable(flyway.info().all()));
|
||||||
|
|
||||||
@@ -151,6 +167,56 @@ public class DatabaseUtils
|
|||||||
System.out.println("\nIf you'd like to upgrade now, simply run 'dspace database migrate'.");
|
System.out.println("\nIf you'd like to upgrade now, simply run 'dspace database migrate'.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For PostgreSQL databases, we need to check for the 'pgcrypto' extension.
|
||||||
|
// If it is NOT properly installed, we'll need to warn the user, as DSpace will be unable to proceed.
|
||||||
|
if(dbType.equals(DBMS_POSTGRES))
|
||||||
|
{
|
||||||
|
// Get version of pgcrypto available in this postgres instance
|
||||||
|
Double pgcryptoAvailable = getPgcryptoAvailableVersion(connection);
|
||||||
|
|
||||||
|
// Generic requirements message
|
||||||
|
String requirementsMsg = "\n** DSpace REQUIRES PostgreSQL >= " + POSTGRES_VERSION + " AND " + PGCRYPTO + " extension >= " + PGCRYPTO_VERSION + " **\n";
|
||||||
|
|
||||||
|
// Check if installed in PostgreSQL & a supported version
|
||||||
|
if(pgcryptoAvailable!=null && pgcryptoAvailable.compareTo(PGCRYPTO_VERSION)>=0)
|
||||||
|
{
|
||||||
|
// We now know it's available in this Postgres. Let's see if it is installed in this database.
|
||||||
|
Double pgcryptoInstalled = getPgcryptoInstalledVersion(connection);
|
||||||
|
|
||||||
|
// Check if installed in database, but outdated version
|
||||||
|
if(pgcryptoInstalled!=null && pgcryptoInstalled.compareTo(PGCRYPTO_VERSION)<0)
|
||||||
|
{
|
||||||
|
System.out.println("\nWARNING: PostgreSQL '" + PGCRYPTO + "' extension is OUTDATED (installed version=" + pgcryptoInstalled + ", available version = " + pgcryptoAvailable + ").");
|
||||||
|
System.out.println(requirementsMsg);
|
||||||
|
System.out.println("To update it, please connect to your DSpace database as a 'superuser' and manually run the following command: ");
|
||||||
|
System.out.println("\n ALTER EXTENSION " + PGCRYPTO + " UPDATE TO '" + pgcryptoAvailable + "';\n");
|
||||||
|
}
|
||||||
|
else if(pgcryptoInstalled==null) // If it's not installed in database
|
||||||
|
{
|
||||||
|
System.out.println("\nWARNING: PostgreSQL '" + PGCRYPTO + "' extension is NOT INSTALLED on this database.");
|
||||||
|
System.out.println(requirementsMsg);
|
||||||
|
System.out.println("To install it, please connect to your DSpace database as a 'superuser' and manually run the following command: ");
|
||||||
|
System.out.println("\n CREATE EXTENSION " + PGCRYPTO + ";\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check if installed in Postgres, but an unsupported version
|
||||||
|
else if(pgcryptoAvailable!=null && pgcryptoAvailable.compareTo(PGCRYPTO_VERSION)<0)
|
||||||
|
{
|
||||||
|
System.out.println("\nWARNING: UNSUPPORTED version of PostgreSQL '" + PGCRYPTO + "' extension found (version=" + pgcryptoAvailable + ").");
|
||||||
|
System.out.println(requirementsMsg);
|
||||||
|
System.out.println("Make sure you are running a supported version of PostgreSQL, and then install " + PGCRYPTO + " version >= " + PGCRYPTO_VERSION);
|
||||||
|
System.out.println("The '" + PGCRYPTO + "' extension is often provided in the 'postgresql-contrib' package for your operating system.");
|
||||||
|
}
|
||||||
|
else if(pgcryptoAvailable==null) // If it's not installed in Postgres
|
||||||
|
{
|
||||||
|
System.out.println("\nWARNING: PostgreSQL '" + PGCRYPTO + "' extension is NOT AVAILABLE. Please install it into this PostgreSQL instance.");
|
||||||
|
System.out.println(requirementsMsg);
|
||||||
|
System.out.println("The '" + PGCRYPTO + "' extension is often provided in the 'postgresql-contrib' package for your operating system.");
|
||||||
|
System.out.println("Once the extension is installed globally, please connect to your DSpace database as a 'superuser' and manually run the following command: ");
|
||||||
|
System.out.println("\n CREATE EXTENSION " + PGCRYPTO + ";\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (SQLException e)
|
catch (SQLException e)
|
||||||
{
|
{
|
||||||
@@ -192,7 +258,7 @@ public class DatabaseUtils
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
System.out.println("Migrating database to latest version... (Check logs for details)");
|
System.out.println("Migrating database to latest version... (Check dspace logs for details)");
|
||||||
updateDatabase(dataSource, connection);
|
updateDatabase(dataSource, connection);
|
||||||
}
|
}
|
||||||
System.out.println("Done.");
|
System.out.println("Done.");
|
||||||
@@ -210,7 +276,7 @@ public class DatabaseUtils
|
|||||||
try (Connection connection = dataSource.getConnection();)
|
try (Connection connection = dataSource.getConnection();)
|
||||||
{
|
{
|
||||||
System.out.println("\nDatabase URL: " + connection.getMetaData().getURL());
|
System.out.println("\nDatabase URL: " + connection.getMetaData().getURL());
|
||||||
System.out.println("Attempting to repair any previously failed migrations via FlywayDB... (Check logs for details)");
|
System.out.println("Attempting to repair any previously failed migrations via FlywayDB... (Check dspace logs for details)");
|
||||||
flyway.repair();
|
flyway.repair();
|
||||||
System.out.println("Done.");
|
System.out.println("Done.");
|
||||||
}
|
}
|
||||||
@@ -240,7 +306,7 @@ public class DatabaseUtils
|
|||||||
|
|
||||||
if (choiceString.equalsIgnoreCase("y"))
|
if (choiceString.equalsIgnoreCase("y"))
|
||||||
{
|
{
|
||||||
System.out.println("Scrubbing database clean... (Check logs for details)");
|
System.out.println("Scrubbing database clean... (Check dspace logs for details)");
|
||||||
cleanDatabase(flyway, dataSource);
|
cleanDatabase(flyway, dataSource);
|
||||||
System.out.println("Done.");
|
System.out.println("Done.");
|
||||||
}
|
}
|
||||||
@@ -256,10 +322,11 @@ public class DatabaseUtils
|
|||||||
{
|
{
|
||||||
System.out.println("\nUsage: database [action]");
|
System.out.println("\nUsage: database [action]");
|
||||||
System.out.println("Valid actions: 'test', 'info', 'migrate', 'repair' or 'clean'");
|
System.out.println("Valid actions: 'test', 'info', 'migrate', 'repair' or 'clean'");
|
||||||
System.out.println(" - info = Describe basic info about database, including migrations run");
|
System.out.println(" - test = Performs a test connection to database to validate connection settings");
|
||||||
System.out.println(" - migrate = Migrate the Database to the latest version");
|
System.out.println(" - info / status = Describe basic info/status about database, including validating the compatibility of this database");
|
||||||
System.out.println(" - repair = Attempt to repair any previously failed database migrations");
|
System.out.println(" - migrate = Migrate the database to the latest version");
|
||||||
System.out.println(" - clean = DESTROY all data and tables in Database (WARNING there is no going back!)");
|
System.out.println(" - repair = Attempt to repair any previously failed database migrations (via Flyway repair)");
|
||||||
|
System.out.println(" - clean = DESTROY all data and tables in database (WARNING there is no going back!)");
|
||||||
System.out.println("");
|
System.out.println("");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1228,4 +1295,102 @@ public class DatabaseUtils
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get version of pgcrypto extension available. The extension is "available"
|
||||||
|
* if it's been installed via operating system tools/packages. It also
|
||||||
|
* MUST be installed in the DSpace database (see getPgcryptoInstalled()).
|
||||||
|
* <P>
|
||||||
|
* The pgcrypto extension is required for Postgres databases
|
||||||
|
* * @param current database connection
|
||||||
|
* @return version number or null if not available
|
||||||
|
*/
|
||||||
|
private static Double getPgcryptoAvailableVersion(Connection connection)
|
||||||
|
{
|
||||||
|
Double version = null;
|
||||||
|
|
||||||
|
String checkPgCryptoAvailable = "SELECT default_version AS version FROM pg_available_extensions WHERE name=?";
|
||||||
|
|
||||||
|
// Run the query to obtain the version of 'pgcrypto' available
|
||||||
|
try (PreparedStatement statement = connection.prepareStatement(checkPgCryptoAvailable))
|
||||||
|
{
|
||||||
|
statement.setString(1,PGCRYPTO);
|
||||||
|
try(ResultSet results = statement.executeQuery())
|
||||||
|
{
|
||||||
|
if(results.next())
|
||||||
|
{
|
||||||
|
version = results.getDouble("version");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(SQLException e)
|
||||||
|
{
|
||||||
|
throw new FlywayException("Unable to determine whether 'pgcrypto' extension is available.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get version of pgcrypto extension installed in the DSpace database.
|
||||||
|
* <P>
|
||||||
|
* The pgcrypto extension is required for Postgres databases to support
|
||||||
|
* UUIDs.
|
||||||
|
* @param current database connection
|
||||||
|
* @return version number or null if not installed
|
||||||
|
*/
|
||||||
|
private static Double getPgcryptoInstalledVersion(Connection connection)
|
||||||
|
{
|
||||||
|
Double version = null;
|
||||||
|
|
||||||
|
String checkPgCryptoInstalled = "SELECT extversion AS version FROM pg_extension WHERE extname=?";
|
||||||
|
|
||||||
|
// Run the query to obtain the version of 'pgcrypto' installed on this database
|
||||||
|
try (PreparedStatement statement = connection.prepareStatement(checkPgCryptoInstalled))
|
||||||
|
{
|
||||||
|
statement.setString(1,PGCRYPTO);
|
||||||
|
try(ResultSet results = statement.executeQuery())
|
||||||
|
{
|
||||||
|
if(results.next())
|
||||||
|
{
|
||||||
|
version = results.getDouble("version");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(SQLException e)
|
||||||
|
{
|
||||||
|
throw new FlywayException("Unable to determine whether 'pgcrypto' extension is available.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the pgcrypto extension is BOTH installed AND up-to-date.
|
||||||
|
* <P>
|
||||||
|
* This requirement is only needed for PostgreSQL databases.
|
||||||
|
* @return true if everything is installed & up-to-date. False otherwise.
|
||||||
|
*/
|
||||||
|
public static boolean isPgcryptoUpToDate()
|
||||||
|
{
|
||||||
|
// Get our configured dataSource
|
||||||
|
DataSource dataSource = getDataSource();
|
||||||
|
|
||||||
|
try(Connection connection = dataSource.getConnection())
|
||||||
|
{
|
||||||
|
Double pgcryptoInstalled = getPgcryptoInstalledVersion(connection);
|
||||||
|
|
||||||
|
// Check if installed & up-to-date in this DSpace database
|
||||||
|
if(pgcryptoInstalled!=null && pgcryptoInstalled.compareTo(PGCRYPTO_VERSION)>=0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch(SQLException e)
|
||||||
|
{
|
||||||
|
throw new FlywayException("Unable to determine whether 'pgcrypto' extension is up-to-date.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,147 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are subject to the license and copyright
|
||||||
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||||
|
* tree and available online at
|
||||||
|
*
|
||||||
|
* http://www.dspace.org/license/
|
||||||
|
*/
|
||||||
|
package org.dspace.storage.rdbms;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
import org.flywaydb.core.api.FlywayException;
|
||||||
|
import org.flywaydb.core.api.MigrationInfo;
|
||||||
|
import org.flywaydb.core.api.callback.FlywayCallback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a FlywayCallback class which automatically verifies that "pgcrypto"
|
||||||
|
* is at the proper version before running any database migrations.
|
||||||
|
* <P>
|
||||||
|
* When running PostgreSQL, pgcrypto is REQUIRED by DSpace as it allows UUIDs
|
||||||
|
* to be generated.
|
||||||
|
* <P>
|
||||||
|
* During a database "clean", this also de-registers "pgcrypto" proir to the
|
||||||
|
* full database clean.
|
||||||
|
*
|
||||||
|
* @author Tim Donohue
|
||||||
|
*/
|
||||||
|
public class PostgreSQLCryptoChecker implements FlywayCallback
|
||||||
|
{
|
||||||
|
private Logger log = Logger.getLogger(PostgreSQLCryptoChecker.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for pgcrypto (if needed). Throws an exception if pgcrypto is
|
||||||
|
* not installed or needs an upgrade.
|
||||||
|
* @param connection database connection
|
||||||
|
*/
|
||||||
|
public void checkPgCrypto(Connection connection)
|
||||||
|
{
|
||||||
|
String dbType;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
dbType = DatabaseUtils.getDbType(connection);
|
||||||
|
}
|
||||||
|
catch(SQLException se)
|
||||||
|
{
|
||||||
|
throw new FlywayException("Unable to determine database type.", se);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ONLY Check if this is a PostgreSQL database
|
||||||
|
if(dbType!=null && dbType.equals(DatabaseUtils.DBMS_POSTGRES))
|
||||||
|
{
|
||||||
|
// If this is a PostgreSQL database, then a supported version
|
||||||
|
// of the 'pgcrypto' extension MUST be installed to continue.
|
||||||
|
|
||||||
|
// Check if pgcrypto is both installed & a supported version
|
||||||
|
if(!DatabaseUtils.isPgcryptoUpToDate())
|
||||||
|
{
|
||||||
|
throw new FlywayException("This PostgreSQL Database is INCOMPATIBLE with DSpace. The upgrade will NOT proceed. " +
|
||||||
|
"A supported version (>=" + DatabaseUtils.PGCRYPTO_VERSION + ") of the '" + DatabaseUtils.PGCRYPTO + "' extension must be installed! " +
|
||||||
|
"Please run 'dspace database info' for additional info/tips.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeClean(Connection connection) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterClean(Connection connection) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeMigrate(Connection connection) {
|
||||||
|
// Before migrating database, check for pgcrypto
|
||||||
|
checkPgCrypto(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterMigrate(Connection connection) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeEachMigrate(Connection connection, MigrationInfo migrationInfo) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterEachMigrate(Connection connection, MigrationInfo migrationInfo) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeValidate(Connection connection) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterValidate(Connection connection) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeInit(Connection connection) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterInit(Connection connection) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeBaseline(Connection connection) {
|
||||||
|
// Before initializing database, check for pgcrypto
|
||||||
|
checkPgCrypto(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterBaseline(Connection connection) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeRepair(Connection connection) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterRepair(Connection connection) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeInfo(Connection connection) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterInfo(Connection connection) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@@ -35,8 +35,10 @@
|
|||||||
|
|
||||||
<bean name="org.dspace.core.DBConnection" class="org.dspace.core.HibernateDBConnection" lazy-init="true"/>
|
<bean name="org.dspace.core.DBConnection" class="org.dspace.core.HibernateDBConnection" lazy-init="true"/>
|
||||||
|
|
||||||
|
<!-- Register all our Flyway callback classes (which run before/after database migrations) -->
|
||||||
<bean class="org.dspace.storage.rdbms.DatabaseLegacyReindexer"/>
|
<bean class="org.dspace.storage.rdbms.DatabaseLegacyReindexer"/>
|
||||||
<bean class="org.dspace.storage.rdbms.DatabaseRegistryUpdater"/>
|
<bean class="org.dspace.storage.rdbms.DatabaseRegistryUpdater"/>
|
||||||
<bean class="org.dspace.storage.rdbms.GroupServiceInitializer"/>
|
<bean class="org.dspace.storage.rdbms.GroupServiceInitializer"/>
|
||||||
|
<bean class="org.dspace.storage.rdbms.PostgreSQLCryptoChecker"/>
|
||||||
<bean class="org.dspace.storage.rdbms.SiteServiceInitializer"/>
|
<bean class="org.dspace.storage.rdbms.SiteServiceInitializer"/>
|
||||||
</beans>
|
</beans>
|
||||||
|
Reference in New Issue
Block a user