Clonar 24 pendrives al mismo tiempo

· osiux's blog


.org | .md | .gmi | .html

Luego de reemplazar el firmware original de TPLink por OpenWRT 1 a 24 Routers MR-3020 2 para el proyecto Letras Viajeras 3, necesitabamos clonar 24 pendrives con exactamente lo mismo y no queríamos hacerlo de a uno.

Cómo clonar un pendrive a muchos pendrives #

Buscando un poco por la web, encontramos varias opciones, entre ellas:

  1. iniciar una máquina con CloneZilla 4 que tiene una utilidad para clonar USB.
  2. usar dd y tee con varios pendrives conectados a la misma máquina.
  3. usar dd, tee y netcat con varios pendrives en varias máquinas.
  4. crear un .torrent con el contenido, y descargar el torrent directamente en cada pendrive conectado a un router.
  5. que cada router descargue el contenido directamente en el USB usando wget y tar desde un parallel-ssh 5

1. CloneZilla #

No lo probamos porque no queríamos reiniciar :-P

2. dd + tee #

Un hack 6 de la vieja escuela, haciendo uso de dd y tee se puede de una manera muy simple clonar en varios dispositivos al mismo tiempo, la desventaja es que por lo general los distintos puertos USB comparten el mismo BUS y por ello puede ser más lento copiar más de 1 a la vez, pero bueno, sirve para un proceso desatendido.

Primero, un test, de que efectivamente funcione:

ls / | pv | tee >(dd of=a) >(dd of=b) | (dd of=c)

El resultado es el siguiente:

160B 0:00:00 [3,37kB/s] [  <=>                                                                                                        ]
0+1 registros leídos
0+1 registros escritos
160 bytes (160 B) copiados, 0,0398646 s, 4,0 kB/s
0+1 registros leídos
0+1 registros escritos
160 bytes (160 B) copiados, 0,0434177 s, 3,7 kB/s
0+1 registros leídos
0+1 registros escritos
160 bytes (160 B) copiados, 0,0465925 s, 3,4 kB/s

Se visualizan el total de bytes copiados 160 y la tasa de transferencia en cada caso: 4,0, 3,7 y 3.4 kB/s.

Comprobamos que los 3 archivos estén completos y sean idénticos:

ls -lh a b c

-rw-rw-r-- 1 osiris osiris 160 ago 12 12:46 a
-rw-rw-r-- 1 osiris osiris 160 ago 12 12:46 b
-rw-rw-r-- 1 osiris osiris 160 ago 12 12:46 c

md5sum a b c

0f422c457d50131124ba323a23f76f7e  a
0f422c457d50131124ba323a23f76f7e  b
0f422c457d50131124ba323a23f76f7e  c

Luego generamos un pendrive con el contenido a copiar, en nuestro caso, el mismo ocupa solo 1.4G de los 7.4 disponibles:

fdisk -l | grep sdc1

/dev/sdc1       7,4G   1,4G  6,0G  20% /mnt/sdc

La utilidad pv simplemente va contando los bytes que pasan, pero si indicamos el tamaño total a copiar, nos proporciona un ETA 7 que ayuda bastante a tener una idea real de cuanto tardará el proceso de copia. Para esto es necesario indicar la cantidad de bytes, esto lo podemos obtener usando fdisk:

B=$(fdisk -l /dev/sdc | grep sdc | head -1 | awk '{print $5}')

Entonces leemos el contenido del pendrive y creamos una imagen en disco, desde la cual copiaremos el resto de los pendrives.

dd if=/dev/sdc bs=1M | pv -s $B | dd of=pendrive.raw

La copia dura unos 9 minutos, en total se copian los 8GB a una tasa de transferencia de 14,3 MB/s

7,46GB 0:09:19 [13,7MB/s] [===============>] 100%

15646720+0 registros leídos
15646720+0 registros escritos
8011120640 bytes (8,0 GB) copiados, 559,49 s, 14,3 MB/s

Ahora partimos desde la imagen pendrive.raw y clonamos los dispositivos /dev/sdc y /dev/sdd usando lo siguiente:

time dd if=pendrive.raw | tee >(dd of=/dev/sdc) | (dd of=/dev/sdd)

El resultado, no fue favorable en termimos de tiempos, 38 minutos para clonar 2 pendrives! Esto varía de máquina en máquina, es cuestión de probar con diferentes puertos y usando un hub USB (algo que no hicimos).

time dd if=pendrive.raw | tee >(dd of=/dev/sdc) | (dd of=/dev/sdd)

15646720+0 registros leídos
15646720+0 registros escritos
8011120640 bytes (8,0 GB) copiados, 2313,62 s, 3,5 MB/s
15646720+0 registros leídos
15646720+0 registros escritos
8011120640 bytes (8,0 GB) copiados, 2321,35 s, 3,5 MB/s
15646720+0 registros leídos
15646720+0 registros escritos
8011120640 bytes (8,0 GB) copiados, 2326,16 s, 3,4 MB/s

real38m46.174s
user0m57.744s
sys6m4.339s

3. dd + tee + netcat #

Esta opción sonaba muy interesante, porque podíamos usar varias máquinas y podríamos clonar todos los pendrives al mismo tiempo, pero al ser en cascada, en cada host había que especificar la IP del siguiente y eso involucraba realizar un paso manual en cada compu.

La ventaja de este método es que se reduce el cuello de botella de utilizar un mismo BUS USB.

4. crear un .torrent y distribuirlo #

Esto motivó realmente conectar todos los pendrives al mismo tiempo, y ahí el surgieron 2 temas, el primero la alimentación de energía, intentamos comprar zapatillas (adaptador de múltiples tomacorrientes), pero los transformadores del MR3020 tienen una disposición que impiden enchufar un toma al lado de otro, por tener las patas en sentido horizontal. En una zapatilla de 8 tomas, sólo entraban 4, y en otra de 5 sólo se aprovechaban 2 tomas, ya que el cable USB también molestaba.

Optamos por conectar el resto de los routers a 1 hub USB de 10 puertos y otros a varias notebooks, todos conectados a la LAN, adicionando 2 switchs de 8 puertos cada uno.

Ahora bien, como el contenido podría sufrir varias modificaciones, habría que regenerar un .torrent por cada cambio, y además instalar un cliente como rtorrent pero decidimos, no tocar la imagen de OpenWRT ya que el MR3020 tiene poco espacio.

Asi que queda pendiente realizar esta prueba, seguramente la ventaja estaría en que cada router podría leer los datos de otros routers al mismo tiempo por compartir el mismo torrent.

5. wget + tar + parallel-ssh #

Aprovechando que wget y tar vienen en OpenWRT, realizamos un script para que realize el deploy en cada router. Para esto utilizamos parallel-ssh que facilita enormemente la administración de todos los routers al mismo tiempo, incluso permite aplicar cambios parciales, detectando los routers que fallan ya sea por estar desconectados o con algún error en particular (algunos no levantaban el pendrive correctamente).

Lo primero es crear un archivo con el listado de hostnames, en este caso ya nos habíamos asegurado de que cada router tenga un hostname distinto basado en su macaddress mediante un script 8. Capturamos los hostnames desde el servidor DHCP a un archivo ~/.ssh/letras:

grep C04A /tmp/dnsmasq.leases | awk '{print $4}' | sort -u | tee ~/.ssh/letras

Luego es muy simple ejecutar un comando en todos los equipos, definimos un alias para simplificar aún más:

1alias multiletras='parallel-ssh -i -h ~/.ssh/letras'

Confirmamos que estén conectados todos los routers, mediante wicd se pueden ver los SSIDs:

Ahora si, tirando un uptime en todos los equipos, rápidamente vemos los routers en que se pudo ejecutar el comando y su resultado:

Para facilitar, la descarga del contenido a copiar en el pendrive, realizamos un script llamado deploy.sh 9, el cual ubicamos en un servidor nginx 10 junto a todos los archivos comprimidos en letras-viajeras.tar.gz

El proceso de copia en todos los routers se reduce a ejecutar lo siguiente:

multiletras 'wget -q -O - http://192.168.10.180/deploy.sh | /bin/sh'

Es decir, primero se conecta a cada router, se descargar el archivo deploy.sh y luego se ejecuta, este script luego se encarga de hacer unas mínimas comprobaciones necesarias, como verificar que esté correctamente montando en modo escritura el pendrive, descargar el .tar.gz, verificar el MD5 de los archivos testigo, capturar algunos errores y en caso de estar corriendo wget o tar, no ejecutarse nuevamente.

Ni bien ejecutamos el deploy vemos el resultado por cada router:

Y si monitoreamos el tráfico de red, podemos apreciar que todos los routers descargan al mismo tiempo el contenido a copiar en cada pendrive, cada conexión descarga entre 6Mb y 13Mb, es un cuello de botella el ancho de banda, pero por muy poco tiempo y teniendo una LAN de 1Gbit no debería haber problemas:

La mayor ventaja, es poder repetir el proceso una y otra vez, siempre con la última versión disponible de deploy.sh, siendo el límite de routers la cantidad de bocas de red, reduciendo el tiempo total de copia a solo unos minutos por ejecutarlas en paralelo y asegurando que quedan todas exactamente iguales. :-)

Comentarios #