Grouper database migration utility
Overview
The Grouper database migration utility copies a Grouper registry from one database to another. It runs as a GrouperShell (gsh) command that reads from a source database connection and writes to a target connection, creating the tables, then the data, then the indexes, foreign keys, and views. The source and target may be different database vendors (for example Oracle to MySQL), but both sides must be the same Grouper version.
Introduced in Grouper v2.5.24+ (2020). The utility (edu.internet2.middleware.grouper.ddl.GrouperDdlDataMigration) is present and essentially unchanged in the currently supported releases, confirmed in v4 and v6 (also present in v7).
This utility is not a core feature of Grouper. It is experimental and does not always work — your mileage may vary. Its performance is acceptable but not as good as software built for data migration (for example Talend or another ETL tool). For large migrations, or high-pressure production migrations, use a dedicated ETL tool instead. The manual ETL approach is: create the tables in the target with the Grouper scripts (without foreign keys, indexes, or views); set the source read-only (at the database level, or via grouper.properties for web services); migrate the data; set the source back to read/write; then add the indexes, foreign keys, and views from Grouper.
Required privileges: this is a server-side administrative operation, not a Grouper UI or web-service action. Running it requires shell access to a Grouper install, the ability to edit grouper.hibernate.properties and grouper-loader.properties, and a root gsh session. It reads and writes whole registries, so the operator is effectively a full registry administrator.
Make the source database read-only before you migrate. If the source changes mid-migration, foreign keys in the target can be left inconsistent.
Performance measurements
These are sample observations; actual times depend on data size, network bandwidth and latency in both directions (reading is generally a no-op since it happens concurrently with writing and is faster), and the target database's speed at applying indexes.
126K groups, 500K memberships: about 25 minutes, Oracle to Oracle.
10K groups, 200K memberships: about 1.5 hours, Oracle to AWS Aurora.
The same dataset Oracle to MySQL took 10 hours, but most of that was applying indexes (so a different tool would not have done better).
Using this utility
You need two database connections. One can be the standard Grouper connection (named grouper); configure the other (the target, or both) in grouper-loader.properties using the db.<name>.* external-connection keys.
You may want to set this temporarily in grouper.hibernate.properties to batch inserts:
hibernate.jdbc.batch_size = 1000Configure the additional database connection (here named mysqlDb) in grouper-loader.properties:
db.mysqlDb.user = grouper_v2_5
db.mysqlDb.pass = *********
db.mysqlDb.url = jdbc:mysql://localhost:3306/grouper_v2_5?useSSL=falseThe target database should have no Grouper tables. If Grouper tables already exist, that is fine — the utility assumes there was a failed migration, that all tables are present, and that there are no indexes, constraints, or views in the target; it picks back up on tables that have no rows in the target. If the migration failed on a particular table, delete all partial rows from that table in the target and restart.
Run this gsh command:
// note: make sure the source is readonly or your foreign keys will be hosed
import edu.internet2.middleware.grouper.ddl.GrouperDdlDataMigration;
new GrouperDdlDataMigration().assignDatabaseFrom("grouper").assignDatabaseTo("mysqlDb").migrateDatabase();The migration runs in five steps, logged as it goes: STEP1 checks whether Grouper tables already exist in the target; STEP2 creates the tables; STEP3 analyzes the tables and columns; STEP4 syncs the row data table by table; STEP5 creates the indexes, foreign keys, and views. Indexes are therefore added after the data is migrated.
Sample output is shown below (trimmed). Note these are not realistic performance numbers — a real run should be faster. The excerpt is from a 2020 development run on v2.5.0; paths and version strings will differ on your install.