summaryrefslogtreecommitdiffstats
path: root/installer/opengnsys_import.sh
blob: 0e7121eba732bf09f254255ec844b28b4a94b453 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
#!/bin/bash
#         importclient str_backupfile
#@file    importclient
#@brief   Importa los datos de OpenGnsys de un archivo de backup: dhcp, pxe, páginas de inicio y configuración de la consola.
#@param 1 str_backupfile fichero de backup (creado con exportclient)
#@exception 1 Error de formato
#@exception 2 Sólo ejecutable por usuario root
#@exception 3 Sin acceso al fichero de backup
#@exception 4 Sin acceso a la configuración de OpenGnsys
#@exception 5 Errores al importar o exportar de la bd auxiliar
#@exception 6 Errores al importar los archivos de actualización de la BD desde opengnsys.es
#@exception 7 El archivo de backup ha sido crearo con una versión incompatible de opengnsys_export. Usar 1.1.0-5594 o posterior.
#@note En las versiones de desarrollo (pre) no se modifica la estructura de la base de datos.
#@version 1.1.0 - Versión inicial.
#@author  Irina Gómez - ETSII Univ. Sevilla
#@date    2016-10-18
#@version 1.1.0 - Permite importar de versiones de OpenGnsys anteriores. Cambia la importación de la base de datos.
#@note    Incompatible con versiones de opengnsys_export.sh anteriores a esta fecha.
#@date    2018-02-14
#@version 1.1.1 - Importamos scripts Custom, PXE para UEFI y /etc/default/opengnsys.
#@date    2019-07-18
#*/ ##

# Variables globales.
PROG="$(basename $0)"

DATE=$(date +%Y%m%d)
BACKUPFILE=$1
TMPDIR=/tmp/opengnsys_export
OPENGNSYS="/opt/opengnsys"
MYCNF=$(mktemp /tmp/.my.cnf.XXXXX)
CATALOG="ogAdmBD"
AUXCATALOG="og_import"
MYSQLFILE="$TMPDIR/$CATALOG.sql"
MYSQLBCK="$OPENGNSYS/doc/$CATALOG.sql-$DATE"

LOG_FILE=$OPENGNSYS/log/${PROG%.sh}.log
BRANCH="master"
SVN_URL="https://github.com/opengnsys/OpenGnsys/branches/$BRANCH/admin/Database"
DEFAULT_MYSQL_ROOT_PASSWORD="passwordroot"      # Clave por defecto root de MySQL

# Si se solicita, mostrar ayuda.
if [ "$*" == "help" ]; then
    echo -e "$PROG: Importa los datos de OpenGnsys desde un archivo de backup:" \
           " dhcp, pxe, páginas de inicio y configuración de la consola.\n" \
           "    Formato: $PROG backup_file\n" \
           "    Ejemplo: $PROG backup.tgz"
    exit
fi

# Comprobamos número de parámetros
if [ $# -ne 1 ]; then
    echo "$PROG: ERROR: Error de formato: $PROG backup_file"
    exit 1
fi

# Comprobar parámetros.
if [ "$USER" != "root" ]; then
        echo "$PROG: Error: solo ejecutable por root." >&2
        exit 2
fi

# Comprobamos acceso al fichero de backup
if ! [ -r $BACKUPFILE ]; then
    echo "$PROG: ERROR: Sin acceso al fichero de backup." | tee -a $FILESAL
    exit 3
fi

# Comprobamos  acceso a ficheros de configuración
if ! [ -r $OPENGNSYS/etc/ogAdmServer.cfg ]; then
    echo "$PROG: ERROR: Sin acceso a la configuración de OpenGnsys." | tee -a $FILESAL
    exit 4
fi

# Si existe el directorio auxiliar lo borramos
[ -d $TMPDIR ] && rm -rf $TMPDIR

####### Funciones ##############################################
# Al salir elimina archivos y base de datos temporal
function clean()
{
        mysql --defaults-extra-file=$MYCNF  -e "DROP DATABASE IF EXISTS $AUXCATALOG"
        rm -f $MYCNF
}

function getDateTime()
{
        date "+%Y%m%d-%H%M%S"
}

# Escribe a fichero y muestra por pantalla
function echoAndLog()
{
        echo "      $1"
        DATETIME=`getDateTime`
        echo "$DATETIME;$SSH_CLIENT;$1" >> $LOG_FILE
}

function errorAndLog()
{
        echo "      ERROR: $1"
        DATETIME=`getDateTime`
        echo "$DATETIME;$SSH_CLIENT;ERROR: $1" >> $LOG_FILE
}

function mysqlPassword()
{
    # Clave root de MySQL
    while : ; do
        echo -n -e "\\nEnter root password for MySQL (${DEFAULT_MYSQL_ROOT_PASSWORD}): ";
        read -r MYSQL_ROOT_PASSWORD
        if [ -n "${MYSQL_ROOT_PASSWORD//[a-zA-Z0-9]/}" ]; then # Comprobamos que sea un valor alfanumerico
                echo -e "\\aERROR: Must be alphanumeric, try again..."
        else
                # Si esta vacio ponemos el valor por defecto
                MYSQL_ROOT_PASSWORD="${MYSQL_ROOT_PASSWORD:-$DEFAULT_MYSQL_ROOT_PASSWORD}"
                break
        fi
    done
    cat << EOT > $MYCNF
[client]
user=root
password=$MYSQL_ROOT_PASSWORD
EOT
}

# Actualización incremental de la BD (versión actual a actual+1, hasta final-1 a final).
function updateSqlFile()
{
        local DBDIR="$TMPDIR/Database"
        local file FILES=""

        echoAndLog "${FUNCNAME}(): looking for database updates"
        pushd $DBDIR >/dev/null
        # Bucle de actualización incremental desde versión actual a la final.
        for file in $CATALOG-*-*.sql; do
                case "$file" in
                        $CATALOG-$OLDVERSION-$NEWVERSION.sql)
                                # Actualización única de versión inicial y final.
                                FILES="$FILES $file"
                                break
                                ;;
                        $CATALOG-*-postinst.sql)
                                # Ignorar fichero específico de post-instalación.
                                ;;
                        $CATALOG-$OLDVERSION-*.sql)
                                # Actualización de versión n a n+1.
                                FILES="$FILES $file"
                                OLDVERSION="$(echo $file | cut -f3 -d-)"
                                ;;
                        $CATALOG-*-$NEWVERSION.sql)
                                # Última actualización de versión final-1 a final.
                                if [ -n "$FILES" ]; then
                                        FILES="$FILES $file"
                                        break
                                fi
                                ;;
                esac
        done
        # Aplicar posible actualización propia para la versión final.
        file=$CATALOG-$NEWVERSION.sql
        if [ -n "$FILES" -o "$OLDVERSION" = "$NEWVERSION" ] && [ -r $file ]; then
                FILES="$FILES $file"
        fi

        popd >/dev/null
        if [ -n "$FILES" ]; then
                mysql --defaults-extra-file=$MYCNF  -e "CREATE DATABASE $AUXCATALOG" 
                [ $? != 0 ] && errorAndLog "${FUNCNAME}: Can't create database $AUXCATALOG" && exit 5
                mysql --defaults-extra-file=$MYCNF -D "$AUXCATALOG" < $MYSQLFILE &>/dev/null
                [ $? != 0 ] && errorAndLog "${FUNCNAME}: Can't import $MYSQLFILE in  $AUXCATALOG" && exit 5

                for file in $FILES; do
                        importSqlFile $DBDIR/$file
                done

                cp $MYSQLFILE $MYSQLFILE.backup
                mysqldump --defaults-extra-file=$MYCNF --opt $AUXCATALOG > $MYSQLFILE
                [ $? != 0 ] && errorAndLog "${FUNCNAME}: Can't export  $AUXCATALOG in  $MYSQLFILE" && exit 5

                mysql --defaults-extra-file=$MYCNF  -e "DROP DATABASE $AUXCATALOG" 
                echoAndLog "${FUNCNAME}(): sqlfile update"
        else
                echoAndLog "${FUNCNAME}(): sqlfile unchanged"
        fi
}


# Actualizar la base datos
function importSqlFile()
{
        local sqlfile="$1"

        if [ ! -r $sqlfile ]; then
                errorAndLog "${FUNCNAME}(): Unable to read $sqlfile!!"
                exit 5
        fi

        echoAndLog "${FUNCNAME}(): importing SQL file..."
        # Ejecutar actualización y borrar fichero de credenciales.
        mysql --defaults-extra-file=$MYCNF --default-character-set=utf8 -D "$AUXCATALOG" < $sqlfile
        if [ $? -ne 0 ]; then
                errorAndLog "${FUNCNAME}(): error importing ${sqlfile##*/} in temporal database"
                exit 5
        fi
        echoAndLog "${FUNCNAME}(): file ${sqlfile##*/} imported to temporal database"
        return 0
}

##################################################################
# Al salir borramos MYCNF y la db tamporal
trap "clean" 1 2 3 6 9 14 15 EXIT

# Descomprimimos backup
tar -xvzf $BACKUPFILE --directory /tmp &>/dev/null

# Comprueba que opengnsys_export sea compatible
grep "CREATE TABLE.*usuarios" $MYSQLFILE &>/dev/null
if [ $? -ne 0 ]; then
    errorAndLog "Backup file created with old version opengnsys_export. Use version 1.1.0-5594 or later."
    exit 7
fi

# Comprobamos si es la misma versión
[ -f $TMPDIR/VERSION.txt ] && OLDVERSION=$(awk '{print $2}' $TMPDIR/VERSION.txt)
[ -f $TMPDIR/VERSION.json ] && OLDVERSION=$(jq -r '.version' $TMPDIR/VERSION.json)
NEWVERSION=$(jq -r '.version' $OPENGNSYS/doc/VERSION.json)
# FALTA: Comprobar que la versión OLD es menor que la NEW
if [ $OLDVERSION != $NEWVERSION ] ; then
    echo "La versión del servidor no coincide con la del backup."
    jq -r '[.project, .version, .codename] | join(" ")' $OPENGNSYS/doc/VERSION.json $TMPDIR/VERSION.json 2>/dev/null \
	    || cat $TMPDIR/VERSION.txt
    read -p "¿Quiere continuar? (y/n): " ANSWER
    if [ "${ANSWER^^}" != "Y" ]; then
        echo "Operación cancelada."
        exit 0
    fi
    # Nos bajamos los archivos de actualización de la base de datos
    svn checkout "$SVN_URL" $TMPDIR/Database
    [ $? -ne 0 ] && errorAndLog "$PROG: Error getting code from $SVN_URL" && exit 6
    
    # Solicitamos la clave de mysql.
    mysqlPassword
    DIFFVERSION=TRUE
fi

# MYSQL
echo "   * Importamos informacion mysql."
source $OPENGNSYS/etc/ogAdmServer.cfg
# Crear fichero temporal de acceso a la BD
if [ ! -r $MYCNF ]; then
    chmod 600 $MYCNF
    trap "rm -f $MYCNF" 1 2 3 6 9 15
    cat << EOT > $MYCNF
[client]
user=$USUARIO
password=$PASSWORD
EOT
fi

# Si la versión es diferente usamos una tabla auxiliar para actualizar el .sql
[ "$DIFFVERSION" == TRUE ] &&  updateSqlFile

# Eliminamos las tablas que no importamos: repositorios, entorno
#     definimos usuario creador de los "triggers
#     y añadimos los usuarios, sólo si no existen.
sed -i -e '/Table structure.* `repositorios`/,/Table structure/d' \
       -e '/Table structure.* `entornos`/,/Table structure/d' \
       -e "s/\(DEFINER=\`\)[^\`]*\(\`.* TRIGGER\)/\1$USUARIO\2/" \
       -e '/Table structure.*`usuarios`/,/CHARSET/d' \
       -e '/usuarios/s/IGNORE//g' \
       -e '/usuarios/s/^INSERT /\nALTER TABLE usuarios ADD UNIQUE (usuario);\n\nINSERT IGNORE /g' $MYSQLFILE

# Copia de seguridad del estado de la base de datos
mysqldump --defaults-extra-file=$MYCNF --opt $CATALOG > $MYSQLBCK
chmod 400 $MYSQLBCK
# Importamos los datos nuevos
mysql --defaults-extra-file=$MYCNF -D "$CATALOG" < $MYSQLFILE &>/dev/null
[ $? -ne 0 ] && echo "ERROR: Error al importar la información de la base de datos."

# Copiamos los archivos a su sitio correcto
# default/opengnsys
echo "   * Guardamos la configuración de /etc/default."
mv /etc/default/opengnsys /etc/default/opengnsys-$DATE
cp $TMPDIR/default/opengnsys /etc/default/opengnsys

# DHCP
echo "   * Componemos la configuración del dhcp."
for DHCPCFGDIR in /etc/dhcp /etc/dhcp3; do
    if [ -r $DHCPCFGDIR/dhcpd.conf ]; then
        # Tomamos las variables globales de la configuración actual y las declaraciones host del backup
        # Inicio declaraciones host
        OLDHOSTINI=$(grep -n -m1 -e "^[[:blank:]]*host" -e "^#[[:blank:]]*host" $TMPDIR/dhcpd.conf|cut -d: -f1)
        let BEFOREHOST=$(grep -n -m1 -e "^[[:blank:]]*host" -e "^#[[:blank:]]*host" $DHCPCFGDIR/dhcpd.conf| cut -d: -f1)-1
        # Copia de seguridad de la configuración anterior
        cp $DHCPCFGDIR/dhcpd.conf $DHCPCFGDIR/dhcpd.conf-LAST
        mv $DHCPCFGDIR/dhcpd.conf $DHCPCFGDIR/dhcpd.conf-$DATE
        # Nuevo fichero
        sed ${BEFOREHOST}q $DHCPCFGDIR/dhcpd.conf-LAST > $DHCPCFGDIR/dhcpd.conf
        sed -n -e "$OLDHOSTINI,\$p" $TMPDIR/dhcpd.conf >> $DHCPCFGDIR/dhcpd.conf
        break
    fi
done

# TFTP
echo "   * Guardamos los ficheros PXE de los clientes."
for BOOTLOADER in menu.lst grub; do
    if [ -d $TMPDIR/$BOOTLOADER ]; then
        mkdir $OPENGNSYS/tftpboot/$BOOTLOADER-$DATE
        mv $OPENGNSYS/tftpboot/$BOOTLOADER/{01-*,templates,examples} $OPENGNSYS/tftpboot/$BOOTLOADER-$DATE 2>/dev/null
        cp -r $TMPDIR/$BOOTLOADER/{01-*,templates,examples}  $OPENGNSYS/tftpboot/$BOOTLOADER 2>/dev/null
        chown -R www-data:www-data $OPENGNSYS/tftpboot/$BOOTLOADER
    fi
done

if [ -f $OPENGNSYS/tftpboot/menu.lst/templates/01 ]; then
    echo "   * Cambio del nombre de las plantillas PXE para compatibilidad con UEFI."
    BIOSPXEDIR="$OPENGNSYS/tftpboot/menu.lst/templates"
    mv $BIOSPXEDIR/01 $BIOSPXEDIR/10
    sed -i "s/\bMBR\b/1hd/" $BIOSPXEDIR/10

    # Cambiamos el valor en la base de datos. Si no lo hacemos desaparecen de las columnas del NetBootAvanzado.
    mysql --defaults-extra-file=$MYCNF -D "$CATALOG" -e "update ordenadores set arranque='10' where arranque='01';" &>/dev/null
    [ $? -ne 0 ] && echo "ERROR: Error al modificar nombre de las plantilla '10' en la base de datos."
fi

# Configuración de los clientes
echo "   * Guardamos la configuración de los clientes."
mv $OPENGNSYS/client/etc/engine.cfg $OPENGNSYS/client/etc/engine.cfg-$DATE
cp $TMPDIR/engine.cfg $OPENGNSYS/client/etc/engine.cfg

# Páginas de inicio
echo "   * Guardamos las páginas de inicio."
mv $OPENGNSYS/www/menus $OPENGNSYS/www/menus-$DATE
cp -r $TMPDIR/menus $OPENGNSYS/www

# Script personalizados
echo "   * Guardamos los scripts personalizados."
if ls $OPENGNSYS/client/scripts/*Custom &>/dev/null; then
    mkdir $OPENGNSYS/client/scripts/Custom-$DATE
    mv $OPENGNSYS/client/scripts/*Custom $OPENGNSYS/client/scripts/Custom-$DATE
fi
cp -r $TMPDIR/*Custom $OPENGNSYS/client/scripts 

echo -e "Se ha terminado de importar los datos del backup. \n\nSe han realizado copias de seguridad de los archivos antiguos:" 
echo    "  - /etc/default/opengnsys-$DATE"
echo    "  - $DHCPCFGDIR/dhcpd.conf-$DATE"
echo    "  - $OPENGNSYS/tftpboot/menu.lst-$DATE"
echo    "  - $OPENGNSYS/tftpboot/grub-$DATE"
echo    "  - $OPENGNSYS/client/etc/engine.cfg-$DATE"
echo    "  - $OPENGNSYS/client/scripts/Custom-$DATE"
echo    "  - $OPENGNSYS/www/menus-$DATE"
echo -e "  - $MYSQLBCK \n"

echo "Hay que revisar la configuración del dhcp. En la consola es necesario configurar los valores de las ips de repositorios, servidores ntp, etc y lanzar el \"netBoot Avanzado\" a todas las aulas"

echo "Es necesario probar todos los procedimientos y en caso de error borrarlos y generarlos de nuevo."