-- Leo's gemini proxy

-- Connecting to gmi.osiux.com:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/gemini;lang=es_AR

Clonar 24 pendrives al mismo tiempo


AUTHOR: Osiris Alejandro Gómez

EMAIL: osiux@osiux.com

DATE: 2014-08-12 18:33


#+ATTR_HTML: :width 640 :height 487 :title Clonar pendrives - routers

[IMG]

[1]


Luego de reemplazar el *firmware* original de *TPLink* por *OpenWRT* ^1[2] a 24 Routers MR-3020 ^2[3] para el proyecto **Letras Viajeras** ^3[4], necesitábamos 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[5] 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[6]


1. *CloneZilla*


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


2. `dd` + `tee`


Un *hack* ^6[7] 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)

`ls /` listamos el contenido de la raíz


<!-- -->


`| pv` agregamos un *pipe view* para tener un indicador de progreso


`| tee` esto nos permite redireccionar a la salida estándar y al mismo tiempo enviar la salida a un archivo.


`>(dd of=a)` enviamos la salida al archivo `a`


`>(dd of=b)` enviamos la salida al archivo `b`


`>| (dd of=c)` última salida al archivo `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[8] 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 términos 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.


Así 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 realice 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[9]. 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:


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

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


#+ATTR_HTML: :width 640 :height 480 :title Clonar pendrives - wicd

[IMG]

[10]


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


#+ATTR_HTML: :width 640 :height 480 :title Clonar pendrives - parallel-ssh

[IMG]

[11]


Para facilitar, la descarga del contenido a copiar en el *pendrive*, realizamos un *script* llamado `deploy.sh` ^9[12], el cual ubicamos en un servidor `nginx` ^10[13] 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*:


#+ATTR_HTML: :width 640 :height 480 :title Clonar pendrives - md5

[IMG]

[14]


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:


#+ATTR_HTML: :width 640 :height 480 :title Clonar pendrives - iftop

[IMG]

[15]


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[16]


ChangeLog


`2023-05-27 09:12`[17] agregar DESCRIPTION, KEYWORDS, actualizar tags OpenGraph y corregir sintaxis en *Clonar 24 pendrives al mismo tiempo*

`2022-11-13 20:39`[18] agregar y actualizar tags OpenGraph

`2019-04-18 00:21`[19] Agregar hora en header date

`2019-04-18 00:01`[20] Corregir identación header #+INCLUDE:

`2015-07-03 04:31`[21] @ 00:05 hs - elimino #+OPTIONS: de todos los archivos excepto header.gmi

`2015-07-03 03:59`[22] @ 01:00 hs - reemplazo :alt por :title y cambios menores

`2014-08-13 21:56`[23] 00:02 hs - corrijo typos

`2014-08-12 18:32`[24] @ 00:05 hs - Corrijo nombre archivo clonar pendrives


1: file:img/clonar-pendrives/letras-viajeras-routers.jpg

2: http://openwrt.gmi

3: http://www.tp-link.com/en/products/details/?model=TL-MR3020

4: https://github.com/gcoop-libre/letras_viajeras

5: http://www.clonezilla.gmi/

6: https://code.google.com/p/parallel-ssh/

7: https://superuser.com/questions/145516/cloning-single-disk-drive-to-multiple-drives-simultaneously

8: https://es.wikipedia.gmi/wiki/Tiempo_estimado_de_llegada

9: https://github.com/gcoop-libre/letras_viajeras/blob/master/config_ap/root/autoconfig.sh

10: file:img/clonar-pendrives/letras-viajeras-wicd.jpg

11: file:img/clonar-pendrives/letras-viajeras-pssh.jpg

12: https://github.com/gcoop-libre/letras_viajeras/blob/master/config_ap/root/deploy.sh

13: http://nginx.gmi/

14: file:img/clonar-pendrives/letras-viajeras-md5.jpg

15: file:img/clonar-pendrives/letras-viajeras-iftop.jpg

16: mailto:blog@osiux.com?subject=Comentario

17: https://gitlab.com/osiux/osiux.gitlab.io/-/commit/8069eb05d7e251de740b5e0495d5536554c1033b

18: https://gitlab.com/osiux/osiux.gitlab.io/-/commit/bf3a61526ad2a73cecb77a18995f1d63494e3664

19: https://gitlab.com/osiux/osiux.gitlab.io/-/commit/e46ec52748a7ecc60f09c3b95e363e92eaa0bebc

20: https://gitlab.com/osiux/osiux.gitlab.io/-/commit/5c8643b83930c6269569c76602608bd33f93008b

21: https://gitlab.com/osiux/osiux.gitlab.io/-/commit/bbc3bbc728f2a3eeb4fe2e0a012ee5d8d613e3ef

22: https://gitlab.com/osiux/osiux.gitlab.io/-/commit/a2abb3b333c91e0d3c15ea9e93a21589bd4d86f7

23: https://gitlab.com/osiux/osiux.gitlab.io/-/commit/c0a48d3b51c58846025c55ab75a06e3de0cd77b8

24: https://gitlab.com/osiux/osiux.gitlab.io/-/commit/7cd142b9b96ff7f4dc1f5418a4e5b2acaef42481

-- Response ended

-- Page fetched on Fri May 17 02:34:45 2024