[Nextcloud/Postgresql] How to migrate Nextcloud to new Postgresql (vm-charms)

I’ve been working on the process to migrate the Nexcloud charm from the old (to be deprecated) Postgresql charm to the new.

This this is a fairly sensitive operation since we use Nextcloud with Dwellir, so I thought to share my (positive) experience getting to a point where we can migrate to the new ops Postgresql.

Note! This process will not fit everyone. Especially if you have very large databases which may not be easily migrated using a simple pg_dump. You would then need to figure out how to best migrate your data as part of a migration process. Our Nextcloud has a small database, which makes this process work well.

Overview

First, read this document by @taurus: Charmed PostgreSQL How-to - Migrate from Legacy (overview) which by the time of writing was very much a DRAFT. But contained enough information to get going.

The Nextcloud charm use the new “ops” lib interface “postgresql_client” (database) and keeps the metadata.yaml reference to the old interface name (db). The migration method described here involves Nextcloud having two relations to Postgresql before the first/old one is removed.

charm.py

from charms.data_platform_libs.v0.data_interfaces import (DatabaseCreatedEvent, DatabaseRequires)

metadata.yaml

requires:
  db:
    interface: pgsql

  database:
    interface: postgresql_client
    limit: 1

The migration process, takes you from the old version of the “old Nextcloud” (released as v1.0.0) + old Postresql (12) -> into the “new Nextcloud (rev23+)” + “new Postgresql (14)” . It will work on new revisions too.

Practice

Checkout, build, deploy the old version of the Nextcloud charm together with old Postgresql.

Practice the migration gives you confidence and saves heartache doing it on your live instance.

You need to get the old code for Nextcloud (deprecated as of 2023-june) to practice the real migration.

git clone https://github.com/nextcloud-charmers/nextcloud-charms/
git checkout v1.0.0
cd operator-nextcloud
charmcraft pack
juju add-model old-nextcloud
juju deploy postgresql –channel stable/290 –series focal
juju deploy nextcloud-old.charm
juju relate nextcloud:db postgresql:db

Backup Nextcloud config.php

Make sure to make a copy the /var/www/nextcloud/config/config.php as you can always revert if something goes sideways along the way.

Dump database old Postgresql

Extract a database dump of the nextcloud database. It will be restored in to a new instance of Postgresql later. Remember to place Nextcloud into maintenance mode to avoid any database changes while we perform the work.

juju run-action nextcloud/leader maintenance enable=true
juju ssh postgresql/0
sudo -u postgres pg_dump -Fc -d nextcloud > nextcloud-database-backup-file.db

(The option “-Fc” is needed to be able to restore with pg_restore)

Deploy a new Postresql database & test import

Test that you can import the database into a fresh install of Postgresql.

juju add-model test-importing-database
juju deploy postgresql
juju run-action postgresql/leader get-password –wait
juju scp nextcloud-database-backup-file.db postgresql/0:
juju ssh postgresql/0
createdb --host=10.51.45.221 --username=operator --password testdb
pg_restore --username=operator --password -d testdb nextcloud-database-backup-file.db

This should now work without errors and that means you have tested your backup/restore.

Upgrade the Nextcloud charm

Upgrade the Nextcloud charm, available in charmhub on the edge channel.

juju upgrade-charm nextcloud --switch "ch:nextcloud" –channel=edge

Nextcloud becomes operational with the new relation (database) interface now available.

Deploy a new postgresql instance in the same model as your Nextcloud

Deploy the new postgresql charm under a different name (since it will be conflicting with your old postgresql).

juju deploy postgresql postgresql-ops --series jammy

Relate new Postgresql with Nextcloud

Now relate Nextcloud with the new postgresq-ops application. This is safe and will not cause any issues, because the Nextcloud charm will only request the creation of a new database for us which we will extract the needed credentials from and modify the primary config.php manually.

juju relate nextcloud:database postgresql:database

Get the login information form the new database relation.

Extract the connection information I needed to connect to the new instance.

juju show-unit nextcloud/0 | grep -E "database|endpoints:|password"

Restore Nextcloud database into the new instance.

We can import the exported database into the new one which has been created for us by Juju.

pg_restore --no-owner --clean --host=10.51.45.221 --username="relation-6" --password -d nextcloud nextcloud-database-backup-file.db

Use the password from the output of the above juju show-unit command.

Update config.php

Use the information about the new db instance (host,port,username and password.) to edit the configuration file on the nextcloud/leader unit: /var/www/nextcloud/config/config.php

<?php
$CONFIG = array (
  'passwordsalt' => 'rSGbWXO179oaGDFMP/9HxGv2aoraq9',
  'secret' => '88IswSZ2nkY9xc6I8QEvwBhdt/hmtq56MuYnlyey5kxtsXWM',
  'trusted_domains' => 
  array (
    0 => 'localhost',
    2 => '10.51.45.74',
  ),
  'datadirectory' => '/var/www/nextcloud/data/',
  'dbtype' => 'pgsql',
  'version' => '23.0.0.10',
  'overwrite.cli.url' => '',
  'dbname' => 'nextcloud',
  'dbhost' => '10.51.45.221',
  'dbport' => '5432',
  'dbtableprefix' => 'oc_',
  'dbuser' => 'relation-6',
  'dbpassword' => 'dgJ3d9slL6iHirJi',
  'installed' => true,
  'instanceid' => 'ocq6dltb3pbg',
  'htaccess.RewriteBase' => '\'/\'',
  'overwriteprotocol' => 'http',
  'default_phone_region' => 'SE',
);

Check Nextcloud works.

After the change, check that your instance works as normal (first disable maintenance mode).

juju run-action nextcloud/leader maintenance enable=false
http://nextcloud.instance.com

If all is OK - great! If not, just recover the old config.php you backed up initially.

Break relation to old Nextcloud

Remove the old relation.

juju remove-relation nextcloud:db postgresql:db

Nextcloud will now detect your manual changes and report it in the status output. This is all fine as this is a means to let you know that a config has happened outside of Juju. We can remedy this by a simple config change that will re-sync the config from disk.

Invoke a random config-change event by altering some non critical config variable:

juju config nextcloud php_upload_max_filesize="128M"

Remove the old Postgresql application

Remove the old relation concludes the migration process.

juju remove-application  postgresql

Extra material: Interacting with Postgresql

The below is useful if you need to validate your database etc.

  • Old Postgresql charm: sudo -u postgres psql

  • New Postgresql:

sudo apt install postgresql-client
juju run-action postgresql/leader get-password –wait
psql --host=10.4.210.100 --username=operator --password postgres
1 Like

Please define proper track and revision separately. Also, It is recommended to quote as:

```shell
juju deploy postgresql --channel latest/stable --revision 290 --series focal
\``` 

Otherwise command is corrupted due to wrong :

ERROR unrecognized args: ["stable/290" "–series" "focal"]

The entire section is:

git clone https://github.com/nextcloud-charmers/nextcloud-charms/
cd nextcloud-charms && git checkout v1.0.0
cd operator-nextcloud
charmcraft pack
juju add-model old-nextcloud
juju deploy postgresql --channel latest/stable --revision=290 --series focal
juju deploy ./nextcloud_ubuntu-20.04-amd64_ubuntu-18.04-amd64.charm
juju relate nextcloud:db postgresql:db

Sure, it is way more dirty comparing to your version. Let’s keep this in comments for newbies.

BTW, it didn’t work for me:

unit-nextcloud-0: 11:29:55 INFO juju.worker.uniter awaiting error resolution for "install" hook
unit-nextcloud-0: 11:29:55 WARNING unit.nextcloud/0.install Traceback (most recent call last):
unit-nextcloud-0: 11:29:55 WARNING unit.nextcloud/0.install   File "./src/charm.py", line 23, in <module>
unit-nextcloud-0: 11:29:55 WARNING unit.nextcloud/0.install     import utils
unit-nextcloud-0: 11:29:55 WARNING unit.nextcloud/0.install   File "/var/lib/juju/agents/unit-nextcloud-0/charm/src/utils.py", line 9, in <module>
unit-nextcloud-0: 11:29:55 WARNING unit.nextcloud/0.install     import jinja2
unit-nextcloud-0: 11:29:55 WARNING unit.nextcloud/0.install   File "/var/lib/juju/agents/unit-nextcloud-0/charm/venv/jinja2/__init__.py", line 12, in <module>
unit-nextcloud-0: 11:29:55 WARNING unit.nextcloud/0.install     from .environment import Environment
unit-nextcloud-0: 11:29:55 WARNING unit.nextcloud/0.install   File "/var/lib/juju/agents/unit-nextcloud-0/charm/venv/jinja2/environment.py", line 25, in <module>
unit-nextcloud-0: 11:29:55 WARNING unit.nextcloud/0.install     from .defaults import BLOCK_END_STRING
unit-nextcloud-0: 11:29:55 WARNING unit.nextcloud/0.install   File "/var/lib/juju/agents/unit-nextcloud-0/charm/venv/jinja2/defaults.py", line 3, in <module>
unit-nextcloud-0: 11:29:55 WARNING unit.nextcloud/0.install     from .filters import FILTERS as DEFAULT_FILTERS  # noqa: F401
unit-nextcloud-0: 11:29:55 WARNING unit.nextcloud/0.install   File "/var/lib/juju/agents/unit-nextcloud-0/charm/venv/jinja2/filters.py", line 13, in <module>
unit-nextcloud-0: 11:29:55 WARNING unit.nextcloud/0.install     from markupsafe import soft_unicode
unit-nextcloud-0: 11:29:55 WARNING unit.nextcloud/0.install ImportError: cannot import name 'soft_unicode' from 'markupsafe' (/var/lib/juju/agents/unit-nextcloud-0/charm/venv/markupsafe/__init__.py)
unit-nextcloud-0: 11:29:55 ERROR juju.worker.uniter.operation hook "install" (via hook dispatching script: dispatch) failed: exit status 1
unit-nextcloud-0: 11:29:55 INFO juju.worker.uniter awaiting error resolution for "install" hook

Something else:

The hint can be:

juju scp nextcloud/leader /var/www/nextcloud/config/config.php ~/nextcloud.config.php.backup

Regarding:

This is not necessary. The psql client is available as charmed-postgresql.psql (the part of charmed-postgresql SNAP) and new charm revisions create a snap alias.

As for today use:

juju run-action postgresql/leader get-password –wait
charmed-postgresql.psql --host=10.4.210.100 --username=operator --password postgres

In general it is Superb! We would not recommend to use parallel relation to two databases (but it is application specific). JFYI, there is a charm to import DB Charmhub | Deploy PostgreSQL Data Injector Charm using Charmhub - The Open Operator Collection (it is currently released for K8s only, but it is workloadless. I will document it in my manual).

Thank you for this contribution!

1 Like