El que no repara, repite – Vox Populi

Dice la Ley de Murphy que “cuando algo va mal, seguro empeorará…” y aunque en muchos casos esto nos debería desanimar, como le dijo Cooper a su hija en Interstellar: “La Ley de Murphy no significa que vaya a ocurrir algo malo. Significa que lo que pueda pasar, pasará. Y es una oportunidad“.

Ayer, mientras instalaba una herramienta para el nuevo proyecto en el que estoy (convertir los xml a adoc), la máquina virtual que ocupo para el trabajo se quedo sin espacio:

...
remote: Compressing objects: 100% (655/655), done.
remote: Total 1196987 (delta 972), reused 1238 (delta 835), pack-reused 1195497
Receiving objects: 100% (1196987/1196987), 415.70 MiB | 13.85 MiB/s, done.
Resolving deltas: 100% (846883/846883), done.
fatal: sha1 file '.git/objects/pack/tmp_idx_V0yqDB' write error: No space left on device
fatal: index-pack failed

Cuando descargue la imagen .qcow2, como es mi costumbre, extendí el disco a 30Gb. Pero al revisar el disco mantenía su espacio original de 10Gb:

$ sudo df -h
Filesystem      Size  Used Avail Use% Mounted on
devtmpfs        1.8G     0  1.8G   0% /dev
tmpfs           1.9G     0  1.9G   0% /dev/shm
tmpfs           1.9G   17M  1.9G   1% /run
tmpfs           1.9G     0  1.9G   0% /sys/fs/cgroup
/dev/vda3       9.9G  9.9G   20K 100% /
/dev/vda2       100M  5.8M   95M   6% /boot/efi
tmpfs           374M     0  374M   0% /run/user/201

Al revisar el disco, me dí cuenta que la partición que extendí fue la /dev/vda1 en lugar de la /dev/vda3:

# fdisk -l
Disk /dev/vda: 30 GiB, 32212254720 bytes, 62914560 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: BED17CC9-3257-40EC-8579-AC7740CDF994

Device        Start      End  Sectors  Size Type
/dev/vda1      2048 41946623 41944576   20G BIOS boot
/dev/vda2  41946624 42151423   204800  100M EFI System
/dev/vda3  42151424 62911999 20760576  9.9G Linux filesystem

… y aquí empezó mi tormento…

Mi grandiosa idea fue: “Voy a formatear esa partición y le agrego el espacio al VG“. Afortunadamente, encontré que el filesystem no estaba montado en un LV sino directamente en la partición del disco, por lo que me fui por regenerar la partición y montarle algún directorio que ocupara mucho espacio. Por lo que me dí a la tarea de ubicar que directorios ocupaban más espacio con mi ya clásico bash-one-liner:

[root@vmgls02 /]# ls | xargs du -sk 2> /dev/null | sort -n | tail -5 | awk '{ print $2 }' | xargs du -sh
26M	etc
417M	boot
429M	var
4.1G	home
4.8G	usr

Elimine la partición y la regenere para formatearla como XFS y montarla en /mnt para crear un respaldo de /home:

[root@vmgls02 ~]# fdisk /dev/vda

Welcome to fdisk (util-linux 2.32.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Command (m for help): p
Disk /dev/vda: 30 GiB, 32212254720 bytes, 62914560 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: BED17CC9-3257-40EC-8579-AC7740CDF994

Device        Start      End  Sectors  Size Type
/dev/vda1      2048 41946623 41944576   20G BIOS boot
/dev/vda2  41946624 42151423   204800  100M EFI System
/dev/vda3  42151424 62911999 20760576  9.9G Linux filesystem

Command (m for help): t
Partition number (1-3, default 3): 1
Partition type (type L to list all types): 20

Changed type of partition 'BIOS boot' to 'Linux filesystem'.

Command (m for help): w
The partition table has been altered.
Syncing disks.

[root@vmgls02 ~]# partprobe
[root@vmgls02 ~]# mkfs.xfs /dev/vda1
meta-data=/dev/vda1              isize=512    agcount=4, agsize=1310768 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=1, rmapbt=0
         =                       reflink=1
data     =                       bsize=4096   blocks=5243072, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
Discarding blocks...Done.
[root@vmgls02 ~]# mount /dev/vda1 /mnt
[root@vmgls02 ~]# cd /home
[root@vmgls02 home]# tar czvf /mnt/bkp.tar.gz *
...
[root@vmgls02 home]# cd /mnt
[root@vmgls02 mnt]# tar xzvf bkp.tar.gz
...
[root@vmgls02 mnt]# cd
[root@vmgls02 ~]# umount /mnt

Lo monte en /home y realice una prueba con mi usuario mortal y como no encontré error, decidí desmontarlo, eliminar el contenido del directorio original (y con esto recuperar espacio) y editar el /etc/fstab para dejar permanente el cambio:

/etc/fstab
UUID=fe1e8b67-e41b-44b8-bcfe-e0ec966784ac / xfs defaults 0 0
/dev/vda1 /home xfs defaults 0 0
UUID=F537-0F4F /boot/efi vfat defaults,uid=0,gid=0,umask=077,shortname=winnt 0 2

Reinicié y ahí me dí cuenta del error, mi VM ya no booteo, al abrir la consola lo confirme:

$ sudo virsh console vmgls02
Connected to domain vmgls02
Escape character is ^] (Ctrl + ])

La imagen qcow2 requiere de una partición, al inicio del disco, de 1Mb para poder arrancar. La misma que acababa de eliminar.

Mi error realmente empezó desde que cree la VM, no comprobe que la partición a extender fuera la correcta y esto me llevo a caer en más equivocaciones.

Era momento de reparar y aprender…


Solución

Para evitar el riesgo de perder la información del trabajo, que reside en la VM, opte por descargar una imagen nueva de RHEL (además de que recientemente se actualizó), modificarla correctamente y copiarle la información del disco dañado.

Empece por modificar la imagen:

$ mv rhel-8.4-x86_64-kvm.qcow2 vmgls02.1.qcow2
$ qemu-img info vmgls02.1.qcow2
image: vmgls02.1.qcow2
file format: qcow2
virtual size: 10 GiB (10737418240 bytes)
disk size: 0.996 GiB
cluster_size: 65536
Format specific information:
    compat: 0.10
    compression type: zlib
    refcount bits: 16
$ qemu-img resize vmgls02.1.qcow2 +40G
Image resized.
$ cp vmgls02.1.qcow2 vmgls02.1-orig.qcow2
$ virt-filesystems --long -h --all -a vmgls02.1.qcow2
Name       Type        VFS      Label  MBR  Size  Parent
/dev/sda1  filesystem  unknown  -      -    1.0M  -
/dev/sda2  filesystem  vfat     -      -    100M  -
/dev/sda3  filesystem  xfs      root   -    9.9G  -
/dev/sda1  partition   -        -      -    1.0M  /dev/sda
/dev/sda2  partition   -        -      -    100M  /dev/sda
/dev/sda3  partition   -        -      -    9.9G  /dev/sda
/dev/sda   device      -        -      -    50G   -
$ virt-resize --expand /dev/sda3 vmgls02.1-orig.qcow2 vmgls02.1.qcow2
[   0.0] Examining vmgls02.1-orig.qcow2
**********
Summary of changes:
/dev/sda1: This partition will be left alone.
/dev/sda2: This partition will be left alone.
/dev/sda3: This partition will be resized from 9.9G to 49.9G.  The 
filesystem xfs on /dev/sda3 will be expanded using the ‘xfs_growfs’ 
method.
**********
[   2.6] Setting up initial partition table on vmgls02.1.qcow2
[  13.7] Copying /dev/sda1
[  13.8] Copying /dev/sda2
[  13.9] Copying /dev/sda3
 100% ⟦▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒⟧ 00:00
[  21.5] Expanding /dev/sda3 using the ‘xfs_growfs’ method

Resize operation completed with no errors.  Before deleting the old disk, 
carefully check that the resized disk boots and works correctly.
$ qemu-img info vmgls02.1.qcow2
image: vmgls02.1.qcow2
file format: qcow2
virtual size: 50 GiB (53687091200 bytes)
disk size: 2.21 GiB
cluster_size: 65536
Format specific information:
    compat: 0.10
    compression type: zlib
    refcount bits: 16
$ virt-filesystems --long -h --all -a vmgls02.1.qcow2
Name       Type        VFS      Label  MBR  Size  Parent
/dev/sda1  filesystem  unknown  -      -    1.0M  -
/dev/sda2  filesystem  vfat     -      -    100M  -
/dev/sda3  filesystem  xfs      root   -    50G   -
/dev/sda1  partition   -        -      -    1.0M  /dev/sda
/dev/sda2  partition   -        -      -    100M  /dev/sda
/dev/sda3  partition   -        -      -    50G   /dev/sda
/dev/sda   device      -        -      -    50G   -

Esta imagen nueva la agregue, junto con la dañada, a otra VM de pruebas que tengo, las tres con rhel8.4 para que no hubiera errores de compatibilidad. El disco dañado se etiqueto como /dev/vdb y el nuevo como /dev/vdc. La correspondencia de particiones era similar:

  • Partición 1 → BIOS boot (1M)
  • Partición 2 → EFI System (100M)
  • Partición 3 → Linux filesystem

La partición 1, de la imagen nueva no se alteraría, entonces se copió la partición 2 del disco dañado al nuevo:

[root@rhel8 ~]# dd if=/dev/vdb2 bs=1M of=/dev/vdc2

La copia de la información, se haría de 2 formas:

  1. La partición / se copiaría del dispositivo dañado (/dev/vdb3) al disco nuevo (/dev/vdc3), se expandiría para ocupar el espacio adicionado, y
  2. El filesystem /home del disco dañado se montaría en la VM de pruebas y se restauraría en /dev/vdc3
[root@rhel8 ~]# dd if=/dev/vdb3 bs=1M of=/dev/vdc3
[root@rhel8 ~]# mkdir /rootbkp

Debido a que /dev/vdc3 es un clon de /dev/vdb3, incluído el uuid, monte la partición sin usarlo y lo extendí:

[root@rhel8 ~]# mount -t xfs -o nouuid /dev/vdc3 /rootbkp
[root@rhel8 ~]# xfs_growfs /dev/vdc3

Monte la partición “dañada” en /mnt y realice el respaldo del filesystem en /rootbkp, para restaurarlo finalmente:

[root@rhel8 ~]# mount -t xfs -o nouuid /dev/vdb1 /mnt
[root@rhel8 ~]# cd /mnt && tar czvf /rootbkp/home/bkp.tar.gz *
[root@rhel8 mnt]# cd /rootbkp && tar xzvf bkp.tar.gz

Desmonte ambas particiones y apague la VM de pruebas:

[root@rhel8 ~]# umount /mnt
[root@rhel8 ~]# umount /rootbkp
[root@rhel8 ~]# poweroff

Renombre las imágenes y encendí la VM:

$ sudo mv /var/lib/libvirt/images/vmgls02.qcow2 /var/lib/libvirt/images/vmgls02.qcow2.damaged
$ sudo mv /var/lib/libvirt/images/vmgls02.1.qcow2 /var/lib/libvirt/images/vmgls02.qcow2
$ sudo virsh start vmgls02

Pero al iniciar, nuevamente no booteaba la VM, por la consola no me daba ninguna salida. Entonces abrí virt-manager para saber si había algún mensaje de error en el arranque:

Descargue la imagen BOOT ISO de rhel8.4 y arranque la VM en modo rescue:

Sin embargo, al seleccionar la opción 1, me mando error en el archivo /etc/fstab (Claro! Se me paso editarlo) y no podía montar correctamente el sistema. Monte manualmente y edite el archivo:

/etc/fstab 
UUID=fe1e8b67-e41b-44b8-bcfe-e0ec966784ac / xfs defaults        0 0
#/dev/vda1 /home  xfs   defaults  0 0
UUID=F537-0F4F /boot/efi vfat defaults,uid=0,gid=0,umask=077,shortname=winnt 0 2

Reinicie y volví a arrancar en modo rescue. Ahora ya podía montar correctamente el sistema y reinstalar GRUB2:

sh-4.2# chroot /mnt/sysroot/
sh-4.2# /sbin/grub2-install install_device

Después de reiniciar, procedí a validar los cambios de la imagen:

$ sudo fdisk -l
Disk /dev/vda: 50 GiB, 53687091200 bytes, 104857600 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: D209C89E-EA5E-4FBD-B161-B461CCE297E0

Device      Start       End   Sectors  Size Type
/dev/vda1    2048      4095      2048    1M BIOS boot
/dev/vda2    4096    208895    204800  100M EFI System
/dev/vda3  208896 104857566 104648671 49.9G Linux filesystem
$ df -h
Filesystem      Size  Used Avail Use% Mounted on
devtmpfs        1.8G     0  1.8G   0% /dev
tmpfs           1.9G     0  1.9G   0% /dev/shm
tmpfs           1.9G   17M  1.9G   1% /run
tmpfs           1.9G     0  1.9G   0% /sys/fs/cgroup
/dev/vda3        50G   11G   40G  22% /
/dev/vda2       100M  5.8M   95M   6% /boot/efi
tmpfs           374M     0  374M   0% /run/user/201

Unos reinicios de salud después, pude por fin continuar con mi trabajo pendiente (casi 3 horas después).

Algunas otras notas que consulte y me ayudaron durante todo el proceso, sobre todo para ir dándome una idea para encontrar la mejor solución:

Espero les sirva…