Migracion

En el presente documento, se pretende explicar cómo llevar a cabo una migración de la versión 1.0 de andino a la versión 2.0 de andino.

Indice

1. Requisitos

Se requiere tener instalado:

  • jq >= 1.5
  • docker
  • docker-compose

Se asume que, en el servidor, hay 3 containers de docker corriendo:

  • app-ckan
  • pg-ckan
  • solr-ckan

Además, se debe conocer los usuarios y passwords de la base de datos (tanto de la usada por ckan como por el datastore).

2. Script de migración automático.

El repositorio cuenta con un script para correr la migración automáticamente. (el mismo se puede encontrar en install/migrate.sh, dentro del repositorio). Ciertas variables de entorno y tener instalado docker y docker-compose. Debe ser ejecutado con sudo o root.

Ejemplo:

export EMAIL=admin@example.com
export HOST=andino.midomionio.com.ar
export DB_USER=usuario
export DB_PASS=password
export STORE_USER=dsuser
export STORE_PASS=dspass
sudo -E ./migrate.sh

3. Migración manual

Para realizar la migración manual, debemos conocer las variables con las que se inicializó el portal. En este caso, serán las siguientes:

export EMAIL=admin@example.com
export HOST=andino.midomionio.com.ar
export DB_USER=usuario
export DB_PASS=password
export STORE_USER=dsuser
export STORE_PASS=dspass

3.1. Backup de la base de datos

Es necesario hacer un backup de la base de datos antes de empezar con la migración. La misma puede llevarse a cabo con el siguiente script:

#!/usr/bin/env bash
set -e;

old_db="pg-ckan"
database_backup="backup.gz"

echo "Creando backup de la base de datos."

backupdir=$(mktemp -d)

backupfile="$backupdir/$database_backup"
echo "Iniciando backup de $old_db"
echo "Usando directorio temporal: $backupdir"
docker exec $old_db pg_dumpall -c -U postgres | gzip > "$backupfile"
echo "Copiando backup a $PWD"

cp "$backupfile" $PWD
echo "Backup listo."

Este script dejará un archivo backup.gz en el directorio actual.

3.2. Backup de los archivos de la aplicación

Es necesario hacer un backup de los archivos de la aplicación: configuración y archivos subidos. El mismo puede llevarse a cabo con el siguiente script:

Nota: Requiere jq >= 1.5

#!/usr/bin/env bash
set -e;

old_andino="app-ckan"
app_backup="backup.tar.gz"

echo "Creando backup de los archivos de configuración."
backupdir=$(mktemp -d)
today=`date +%Y-%m-%d.%H:%M:%S`
appbackupdir="$backupdir/application/"
mkdir $appbackupdir
echo "Iniciando backup de los volumenes en $old_andino"
echo "Usando directorio temporal: $backupdir"
docker inspect --format '{{json .Mounts}}' $old_andino  | jq -r '.[]|[.Name, .Source, .Destination] | @tsv' |
while IFS=$'\t' read -r name source destination; do
    echo "Guardando archivos de $destination"
    if ls $source/* 1> /dev/null 2>&1; then
        echo "Nombre del volumen: $name."
        echo "Directorio en el Host: $source"
        echo "Destino: $destination"
        dest="$appbackupdir$name"
        mkdir -p $dest
        echo "$destination" > "$dest/destination.txt"

        tar -C "$source" -zcvf "$dest/backup_$today.tar.gz" $(ls $source)
        echo "List backup de $destination"
    else
        echo "Ningún archivo para $destination";
    fi
done
echo "Generando backup en $app_backup"
tar -C "$appbackupdir../" -zcvf $app_backup "application/"
echo "Backup listo."

Este script dejará un archivo backup.tar.gz en el directorio actual. El mismo, una vez descomprimido, contendrá la siguiente estructura (por ejemplo):

- application/
    ├── 61ee6cc7dc974476fe3300cc4325d913ed2f949494419b11a5c7c897fa919106
       ├── backup_2017-05-19.10:56:09.tar.gz
       └── destination.txt
    └── b1bf820976c3220e54136e4db229a67a9d9292896ad8d91623030e3b7171f210
        ├── backup_2017-05-19.10:56:09.tar.gz
        └── destination.txt

Cada sub-directorio contiene el ID del volumen en docker usado; los números varian de volumen en volumen. Dentro de cada sub-directorio se encuentra un archivo .tar.gz junto con un archivo destination.txt. * El archivo destination.txt indica dónde corresponde la información dentro del container. * El archivo .tar.gz contiene una carpeta _data con los archivos.

4. Instalación

4.1. Detener la aplicación

Debemos detener la aplicación para lograr que se liberen los puertos usados. Por ejemplo, el puerto 80.

docker stop solr-ckan pg-ckan app-ckan

4.2. Instalar la aplicación

Ver la documentación Aquí

Nota: Actualizar la versión de docker y docker-compose de ser necesario.

Ahora, es necesario restaurar tanto la base de datos como los archivos de la aplicación.

5. Restores

5.1. Restaurar los archivos

Descomprimir el archivo backup.tar.gz. En cada subdirectorio encontraremos el archivo destination.txt; el contenido de este archivo nos ayudará a saber donde debemos copiar los archivos. Con el siguiete comando, podremos saber qué volúmenes hay montados en el nuevo esquema y dónde debemos copiar los archivos dentro del backup_*.tar.gz

Correr docker inspect andino -f '{{ json .Mounts }}' | jq:

El comando mostrará, por ejemplo, lo siquiente:

[
{
    "Type": "volume",
    "Name": "a1d87160a04e270302582849c9ce5c6dbb44719a94b702158aeaf23835f7862f",
    "Source": "/var/lib/docker/volumes/a1d87160a04e270302582849c9ce5c6dbb44719a94b702158aeaf23835f7862f/_data",
    "Destination": "/etc/ckan/default",
    "Driver": "local",
    "Mode": "",
    "RW": true,
    "Propagation": ""
},
{
    "Type": "volume",
    "Name": "7ab721966628bf692a3d451567c9a01b419ba5189b88ef05484de315c73f6275",
    "Source": "/var/lib/docker/volumes/7ab721966628bf692a3d451567c9a01b419ba5189b88ef05484de315c73f6275/_data",
    "Destination": "/usr/lib/ckan/default/src/ckanext-gobar-theme/ckanext/gobar_theme/public/user_images",
    "Driver": "local",
    "Mode": "",
    "RW": true,
    "Propagation": ""
},

...

Como podemos ver, hay una entrada "Destination" que coincidirá con el contenido del archivo destination.txt en cada directorio. Debemos asegurarnos de no copiar el archivo production.ini, ya que el mismo cambio bastante de versión en versión.

El restore puede ser llevado a cabo con el siguiente script:

#!/usr/bin/env bash
set -e;

echo "Iniciando recuperación de Archivos."
install_dir="/etc/portal";
container="andino"
app_backup="backup.tar.gz"

containers=$(docker ps -q)
if [ -z "$containers" ]; then
    echo "No se encontró ningun contenedor corriendo."
else
    docker stop $containers
fi

restoredir=$(mktemp -d)
echo "Usando directorio temporal $restoredir"
tar zxvf $app_backup -C $restoredir

docker inspect --format '{{json .Mounts}}' $container  | jq -r '.[]|[.Name, .Source, .Destination] | @tsv' |
while IFS=$'\t' read -r name source destination; do
    for directory in $restoredir/application/*; do
        dest=$(cat "$directory/destination.txt")
        if [ "$dest" == "$destination" ]; then
            echo "Recuperando archivos para $destination"
            tar zxvf "$directory/$(ls "$directory" | grep backup)" -C "$source"
        fi
    done
done
echo "Restauración lista."
echo "Reiniciando servicios."
cd $install_dir;
docker-compose -f latest.yml restart;
cd -;

5.2. Restaurar la base de datos

Para restaurar la base de datos, se puede usar el siguiente script contra el archivo previamente generado (backup.gz):

#!/usr/bin/env bash
set -e;

install_dir="/etc/portal";
database_backup="backup.gz"
container="andino-db"

echo "Iniciando restauración de la base de datos."
containers=$(docker ps -q)

if [ -z "$containers" ]; then
    echo "No se encontró ningun contenedor corriendo."
else
    docker stop $containers
fi
docker restart $container
sleep 10;

restoredir=$(mktemp -d);
echo "Usando directorio temporal $restoredir"

restorefile="$restoredir/dump.sql";

gzip -dkc < $database_backup > "$restorefile";
echo "Borrando base de datos actual."
docker exec $container psql -U postgres -c "DROP DATABASE IF EXISTS ckan;"
docker exec $container psql -U postgres -c "DROP DATABASE IF EXISTS datastore_default;"
echo "Restaurando la base de datos desde: $restorefile"
cat "$restorefile" | docker exec -i $container psql -U postgres
echo "Recuperando credenciales de los usuarios"
docker exec  $container psql -U postgres -c "ALTER USER $DB_USER WITH PASSWORD '$DB_PASS';"
docker exec  $container psql -U postgres -c "ALTER USER $STORE_USER WITH PASSWORD '$STORE_PASS';"

echo "Restauración lista."
echo "Reiniciando servicios."
cd $install_dir;
docker-compose -f latest.yml restart;
cd -;

5.3. Regenerar el índice de búsquedas

Para regenerar el índice de búsquedas, debemos ir al directorio donde se instaló la aplicación y correr el siguiente comando:

docker-compose -f latest.yml exec portal /etc/ckan_init.d/run_rebuild_search.sh