diff --git a/README.md b/README.md index c3c58929c..62a593bdb 100644 --- a/README.md +++ b/README.md @@ -259,6 +259,28 @@ You can do it via this Ansible playbook (make sure to edit the `` **Note**: `` is just a plain username (like `john`), not your full `@:` identifier. +### Upgrading Postgres + +If you're not using an external Postgres server, this playbook initially installs Postgres for you. + +Once installed like that, this playbook attempts to preserve the Postgres version it starts with. +This is because newer Postgres versions cannot start with data generated by an older Postgres version. +An upgrade must be performed. + +This playbook can upgrade your existing Postgres setup with the following command: + + ansible-playbook -i inventory/hosts setup.yml --tags=upgrade-postgres + +**The old Postgres data directory is backed up** (by renaming to `/matrix/postgres-auto-upgrade-backup`). +It stays around forever, until you **manually decide to delete it**. + +As part of the upgrade, the database is dumped to `/tmp`, upgraded and then restored from that dump. +To use a different directory, pass some extra flags to the command above, like this: `--extra-vars="postgres_dump_dir=/directory/to/dump/here"` + +**ONLY one database is migrated** (the one specified in `matrix_postgres_db_name`, named `homeserver` by default). +If you've created other databases in that database instance (something this playbook never does and never advises), data will be lost. + + ## Uninstalling **Note**: If you have some trouble with your installation configuration, you can just re-run the playbook and it will try to set things up again. You don't need to uninstall and install fresh. diff --git a/roles/matrix-server/tasks/main.yml b/roles/matrix-server/tasks/main.yml index 0e54396a4..2df3b60d4 100644 --- a/roles/matrix-server/tasks/main.yml +++ b/roles/matrix-server/tasks/main.yml @@ -13,6 +13,10 @@ - setup-main - setup-ssl +- include: tasks/upgrade_postgres.yml + tags: + - upgrade-postgres + - include: tasks/setup_postgres.yml tags: - setup-main diff --git a/roles/matrix-server/tasks/setup_postgres.yml b/roles/matrix-server/tasks/setup_postgres.yml index a231b902f..92f125e02 100644 --- a/roles/matrix-server/tasks/setup_postgres.yml +++ b/roles/matrix-server/tasks/setup_postgres.yml @@ -33,6 +33,10 @@ docker_postgres_image_to_use: "{{ docker_postgres_image_v9 }}" when: "pg_version.startswith('9.')" +- debug: + msg: "NOTE: Your setup is on an old Postgres version ({{ docker_postgres_image_to_use }}), while {{ docker_postgres_image_latest }} is supported. You can upgrade using --tags=upgrade-postgres" + when: "docker_postgres_image_to_use != docker_postgres_image_latest" + # Even if we don't run the internal server, we still need this for running the CLI - name: Ensure postgres Docker image is pulled docker_image: diff --git a/roles/matrix-server/tasks/upgrade_postgres.yml b/roles/matrix-server/tasks/upgrade_postgres.yml new file mode 100644 index 000000000..db6d75acb --- /dev/null +++ b/roles/matrix-server/tasks/upgrade_postgres.yml @@ -0,0 +1,123 @@ +--- + +- name: Set default postgres_dump_dir, if not provided + set_fact: + postgres_dump_dir: "/tmp" + when: "postgres_dump_dir|default('') == ''" + +- name: Set postgres_dump_name, if not provided + set_fact: + postgres_dump_name: "matrix-postgres.out" + when: "postgres_dump_name|default('') == ''" + +- set_fact: + postgres_auto_upgrade_backup_data_path: "{{ matrix_postgres_data_path }}-auto-upgrade-backup" + +- name: Fail, if trying to upgrade external Postgres database + fail: + msg: "Your configuration indicates that you're using an external Postgres database. Refusing to try and upgrade that." + when: "matrix_postgres_use_external" + +- name: Check Postgres auto-upgrade backup data directory + stat: + path: "{{ postgres_auto_upgrade_backup_data_path }}" + register: result_auto_upgrade_path + +- name: Abort, if existing Postgres auto-upgrade data path detected + fail: + msg: "Detected that a left-over {{ postgres_auto_upgrade_backup_data_path }} exists. You should rename it to {{ matrix_postgres_data_path }} if the previous upgrade went wrong, or delete it if it went well." + when: "result_auto_upgrade_path.stat.exists" + +- name: Determine existing Postgres version (check PG_VERSION file) + stat: + path: "{{ matrix_postgres_data_path }}/PG_VERSION" + register: result_pg_version_stat + +- name: Abort, if no existing Postgres version detected + fail: msg="Could not find existing Postgres installation" + when: "not result_pg_version_stat.stat.exists" + +- name: Determine existing Postgres version (read PG_VERSION file) + slurp: + src: "{{ matrix_postgres_data_path }}/PG_VERSION" + register: result_pg_version + +- name: Determine existing Postgres version (default to empty) + set_fact: + pg_version: "" + +- name: Determine existing Postgres version (make sense of PG_VERSION file) + set_fact: + pg_version: "{{ result_pg_version['content']|b64decode|replace('\n', '') }}" + +- name: Determine Postgres version to use (default to latest) + set_fact: + docker_postgres_image_to_use: "{{ docker_postgres_image_latest }}" + +- name: Determine Postgres version to use (use 9.x, if detected) + set_fact: + docker_postgres_image_to_use: "{{ docker_postgres_image_v9 }}" + when: "pg_version.startswith('9.')" + +- name: Abort, if already at latest Postgres version + fail: msg="You are already running the latest Postgres version supported. Nothing to do" + when: "docker_postgres_image_to_use == docker_postgres_image_latest" + +- name: Ensure matrix-synapse is stopped + service: name=matrix-synapse state=stopped + +- name: Ensure matrix-postgres is started + service: name=matrix-postgres state=started daemon_reload=yes + +- name: Wait a bit, so that Postgres can start + wait_for: + timeout: 5 + delegate_to: 127.0.0.1 + become: false + +- name: Perform Postgres database dump + command: | + /usr/bin/docker run --rm --name matrix-postgres-dump \ + --link matrix-postgres:postgres \ + --env-file=/matrix/environment-variables/env-postgres-pgsql-docker \ + -v {{ postgres_dump_dir }}:/out \ + {{ docker_postgres_image_to_use }} pg_dump -h postgres {{ matrix_postgres_db_name }} -f /out/{{ postgres_dump_name }} + +- name: Ensure matrix-postgres is stopped + service: name=matrix-postgres state=stopped + +- name: Rename existing Postgres data directory + command: "mv {{ matrix_postgres_data_path }} {{ postgres_auto_upgrade_backup_data_path }}" + +- debug: + msg: "NOTE: Your Postgres data directory has been moved from `{{ matrix_postgres_data_path }}` to `{{ postgres_auto_upgrade_backup_data_path }}`. In the event of failure, you can move it back and run the playbook with --tags=setup-postgres to restore operation." + +- include: tasks/setup_postgres.yml + +- name: Ensure matrix-postgres autoruns and is restarted + service: name=matrix-postgres enabled=yes state=restarted daemon_reload=yes + +- name: Wait a bit, so that Postgres can start + wait_for: + timeout: 5 + delegate_to: 127.0.0.1 + become: false + +- name: Perform Postgres database import + command: | + /usr/bin/docker run --rm --name matrix-postgres-import \ + --link matrix-postgres:postgres \ + --env-file=/matrix/environment-variables/env-postgres-pgsql-docker \ + -v {{ postgres_dump_dir }}:/in:ro \ + {{ docker_postgres_image_to_use }} psql -h postgres -f /in/{{ postgres_dump_name }} + +- name: Delete Postgres database dump file + file: + path: "{{ postgres_dump_dir }}/{{ postgres_dump_name }}" + state: absent + +- name: Ensure matrix-synapse is started + service: name=matrix-synapse state=started daemon_reload=yes + +- debug: + msg: "NOTE: Your old Postgres data directory is preserved at `{{ postgres_auto_upgrade_backup_data_path }}`. You might want to get rid of it once you've confirmed that all is well."