-- Leo's gemini proxy
-- Connecting to gmi.osiux.com:1965...
-- Connected
-- Sending request
-- Meta line: 20 text/gemini;lang=es_AR
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
[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.
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]
No lo probamos porque no queríamos reiniciar `:-P`
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
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*.
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*.
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
[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
[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
[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
[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. :-)
`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
-- Response ended
-- Page fetched on Fri May 17 02:34:45 2024