How to restore a deleted Open-Xchange context?

Published on Wednesday, 21 January 2015

How to restore, or recover, an accidentally deleted OX context. If you've accidentally deleted an Open-Xchange context (contextid), then that is bad... Here is how to recover a deleted OX context and filestore... Assuming you make backups of course.


Open-Xchange context restore: How to restore a deleted OX context?

Open-Xchange provides a Context Restore Bundle (documentation) and the utility contextrestore. The contextrestore utility is basically a command line tool which parses your database backups for information on the deleted context. When every piece of context and filestore information is found, contextrestore recreates the deleted OX context. There is a caveat though: you MUST NOT delete the last context from within a database schema.

The contextrestore --help information is as follows:

/opt/open-xchange/sbin/restorecontext --help
Usage: restorecontext
 -h,--help                                         Prints a help text
    --environment                                  Show info about commandline environment
    --nonl                                         Remove all newlines (\n) from output
 -c,--contextid <contextid>                      * The id of the context
 -A,--adminuser <adminuser>                      ? Admin username
 -P,--adminpass <adminpass>                      ? Admin password
 -f,--filename <filename>                        * Comma-separated list of filenames with full path
 -n,--dry-run                                      Activate this option if do not want to apply the changes to the database
 -d,--configdb <configdb>                          (Optional) The name of the ConfigDB schema. If not set, ConfigDB name is determined by "writeUrl" property in file configdb.properties

Entries marked with an asterisk (*) are mandatory.
Entries marked with an question mark (?) are mandatory depending on your
configuration.
Entries marked with a pipe (|) are mandatory for one another which means that
at least one of them must be set.

This is pretty much it... If your Open-Xchange MySQL database backups are created badly (missing --hex-blob option for example), restoring a deleted Open-Xchange context, using restorecontext (documentation), may fail with:

No values found for the filestore in the database

The complete error is:

 No values found for the filestore in the database
        at com.openexchange.admin.contextrestore.storage.mysqlStorage.OXContextRestoreMySQLStorage.restorectx(OXContextRestoreMySQLStorage.java:159)
        at com.openexchange.admin.contextrestore.rmi.impl.OXContextRestore.restore(OXContextRestore.java:775)
        at sun.reflect.GeneratedMethodAccessor133.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:322)
        at sun.rmi.transport.Transport$1.run(Transport.java:177)
        at sun.rmi.transport.Transport$1.run(Transport.java:174)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.rmi.transport.Transport.serviceCall(Transport.java:173)
        at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:556)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:811)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:670)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:745)
        at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:275)
        at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:252)
        at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:161)
        at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:194)
        at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:148)
        at com.sun.proxy.$Proxy0.restore(Unknown Source)
        at com.openexchange.admin.contextrestore.console.Restore.start(Restore.java:117)
        at com.openexchange.admin.contextrestore.console.Restore.main(Restore.java:81)

Which could give a better indication of what went wrong in my opinion. Following the documentation, the command I tried was:

/opt/open-xchange/sbin/restorecontext -c <c-id> -A <OX admin> -P <MY_PASS> -f /tmp/mysql_oxconfig.sql,/tmp/mysql_ox-server.local_1.sql,/tmp/mysql_ox-server.local_2.sql,/tmp/mysql_ox-server.local_3.sql,/tmp/mysql_ox-server.local_4.sql,/tmp/mysql_ox-server.local_5.sql

Since these were all the database backup files with a reference to the deleted context.

Protip: how to find the relevant Open-Xchange MySQL database backup files?

When you backup the individual Open-Xchange MySQL databases to into separated files, you can use grep on your Open-Xchange MySQL database backup files to locate all relevant database files. Grep through the files for the domain name and contextid.

cd /path/to/backupfiles/
grep -lr "example.net" *.sql
grep -lr '<c-id>,' *.sql

this should give only a few results. It's easier to just make one huge backup file, with the mysqldump parameter --all-databases. Then you don't have to grep through the files and you can use the one backup file as source file for restoring the OX context.

Wondering how to restore a single MySQL table from a full mysqldump backup file?

Solution to restore a deleted Open-Xchange context

This is how I solved the above Context Restore error and restored the deleted context. First you need to import all relevant MySQL database backup files into a new MySQL database server. Scp the files if necessary.

mysql -u root -p < mysql_oxconfig.sql
mysql -u root -p < mysql_ox-server.local_1.sql
mysql -u root -p < mysql_ox-server.local_2.sql
mysql -u root -p < mysql_ox-server.local_3.sql
mysql -u root -p < mysql_ox-server.local_4.sql
mysql -u root -p < mysql_ox-server.local_5.sql

Now you have to create a new backup file using the exact mysqldump command Open-Xchange recommends:

mysqldump
  --all-databases
  --single-transaction
  --hex-blob > /tmp/my_backupfile.sql

As you may notice, it's easier to recover a context when you use the above mysqldump command in your Open-Xchange backup process.

Transfer back the file to your OX server and use this one, large, Open-Xchange MySQL database backup file for the Context Restore proces:

/opt/open-xchange/sbin/restorecontext -c <c-id> -A <OX admin> -P <MY_PASS> -f /tmp/my_backupfile.sql

It'll output the filestore context path when succeeded: file:/path/to/your/open-xchange/filestores/[sub-dir]/<c-id>_ctx_store

Of course, replace <c-id> with the contextid in question.