Ajustar al manual del M1000e, añadir diagramas y docs de operación

Especificaciones tomadas del manual del propietario del gabinete
PowerEdge M1000e (Dell, modelo BMX01, rev. A06, oct. 2019), que corrige
el spec sheet comercial usado hasta ahora.

Hardware:

- Peso máximo 200,5 kg, no 179. Profundidad 75,5 cm
- Seis fuentes y nueve ventiladores obligatorios, se usen 3 blades o 16.
  Toda bahía vacía necesita relleno
- Conector CEI/IEC C20 a 16 A. La fuente de 3.000 W exige 200-240 V
- Irrupción de 55 A por fuente durante 10 ms: un magnetotérmico de curva
  C salta, hace falta curva D
- Temperatura de funcionamiento continuo 10-35 °C
- ECM obligatorio con blades M630 de 120 W o más, o por encima de 30 °C

Red:

- Fabric A (ranuras A1/A2) es la Ethernet integrada de cada blade, así
  que no hacen falta tarjetas intermedias. Fabrics B y C sí las
  exigirían y no se usan
- Pendiente saber si en A1/A2 hay un switch o un módulo de paso a
  través: cambia el montaje de red por completo

Costes recalculados: el suelo fijo del chasis sube de 350 a ~500 W al
contar los nueve ventiladores, los módulos de I/O y las pérdidas de las
seis fuentes. 360 €/mes a 24/7, 59 €/mes por ventanas. Que las fuentes y
los ventiladores sean obligatorios convierte en hecho documentado lo que
antes era estimación: los pilotos parciales en el chasis son el peor
caso posible.

Documentación:

- assets/ con cuatro diagramas SVG propios: arquitectura, chasis, stack
  de software y modos de red
- docs/usabilidad.md: órdenes, flujos de trabajo, problemas conocidos y
  ergonomía del hardware
- Diagramas ASCII del panel frontal, el posterior y la topología de
  fabrics en hardware_m1000e.md
- Eliminada la parte de charla y divulgación, fuera del alcance del repo
This commit is contained in:
s1to 2026-08-08 19:58:25 +02:00
parent 74bfbe9437
commit 7caa240c2e
17 changed files with 1012 additions and 423 deletions

View file

@ -1,30 +1,22 @@
# La capa de identidad: verificación, reputación de IP y atestación # La capa de identidad: verificación, reputación de IP y atestación
El documento central del proyecto. Explica **por qué la identidad, y no el cómputo, es el único Por qué la identidad, y no el cómputo, es el cuello de botella de una granja, y cómo se integran
cuello de botella real** de una granja — y cómo las tres capas que la componen se integran entre las capas que la componen.
sí para derrotarla.
> **Alcance.** Esto describe cómo funcionan los mecanismos y por qué las granjas pierden contra Alcance: esto describe cómo funcionan los mecanismos y por qué las granjas pierden contra ellos.
> ellos. No es un manual operativo de alta masiva de cuentas: no hay proveedores de SIM, ni No es un manual operativo de alta masiva de cuentas — no hay proveedores de SIM, ni técnicas de
> técnicas de evasión de fingerprint, ni calendarios de maduración. Esa parte es fraude de evasión de fingerprint, ni calendarios de maduración. Esa parte es fraude de identidad a escala y
> identidad a escala y está bajo persecución activa en la UE — ver [legal_ue.md](legal_ue.md). está bajo persecución activa en la UE; ver [legal_ue.md](legal_ue.md).
> Lo que sigue sirve para investigar, para defender y para dar la charla; para lo otro, no.
--- Una plataforma no pregunta quién eres. Comprueba tres cosas —si controlas un número, desde dónde
llegas y qué dispositivo eres— y luego una cuarta: en qué te pareces a las otras cuentas. Las tres
## 0 · La tesis en una frase primeras se atacan con dinero. La cuarta no, y es la que hunde el negocio.
Una plataforma no te pregunta *quién eres*. Te pregunta tres cosas a la vez —
**¿controlas un número?**, **¿desde dónde llegas?**, **¿qué dispositivo eres?** — y luego,
la que de verdad mata: **¿en qué te pareces a los otros 44?**
Las tres primeras se pueden atacar con dinero. La cuarta no, y es la que hunde el negocio.
--- ---
## 1 · Verificación telefónica ## 1 · Verificación telefónica
### Qué se está comprobando de verdad ### Qué se comprueba
El OTP por SMS no verifica tu identidad. Verifica que **controlas un número en el momento del El OTP por SMS no verifica tu identidad. Verifica que **controlas un número en el momento del
alta**. Es una prueba de posesión, no de identidad. Pero detrás del número hay una cadena que sí alta**. Es una prueba de posesión, no de identidad. Pero detrás del número hay una cadena que sí
@ -49,8 +41,8 @@ evitable. Eso es lo que se revende como *número como servicio*.
### La eSIM: por qué NO es la respuesta ### La eSIM: por qué NO es la respuesta
Es la pregunta que más se repite y la respuesta es contraintuitiva. **La eSIM es peor para una La eSIM es peor para una granja que la SIM física. Para ver por qué hay que mirar el
granja que la SIM física**, y hay que entender el aprovisionamiento para ver por qué. aprovisionamiento.
Una eSIM no es un fichero que se copia. Es un **perfil** que se descarga a un chip concreto: Una eSIM no es un fichero que se copia. Es un **perfil** que se descarga a un chip concreto:
@ -76,7 +68,7 @@ Tres consecuencias que lo descartan:
Resumen: la eSIM cambia un consumible anónimo y barato por un identificador de hardware trazable Resumen: la eSIM cambia un consumible anónimo y barato por un identificador de hardware trazable
con contrato detrás. **Por eso el mercado sigue con plástico** — no por inercia, por diseño. con contrato detrás. **Por eso el mercado sigue con plástico** — no por inercia, por diseño.
### Y aquí está el problema de fondo para un rack ### El problema para un rack
Un contenedor redroid **no tiene banda base**. No hay módem, no hay IMEI legítimo, no puede Un contenedor redroid **no tiene banda base**. No hay módem, no hay IMEI legítimo, no puede
recibir un SMS. Nunca. Así que el número y el dispositivo están **necesariamente desacoplados**: recibir un SMS. Nunca. Así que el número y el dispositivo están **necesariamente desacoplados**:
@ -99,7 +91,7 @@ el dinero de comprarlas deja rastro. Detalle en [legal_ue.md](legal_ue.md).
## 2 · Reputación de IP ## 2 · Reputación de IP
La segunda pregunta: *¿desde dónde llegas?* La segunda pregunta: desde dónde llegas.
### Las tres clases de dirección ### Las tres clases de dirección
@ -125,14 +117,12 @@ bloqueo por daño colateral**.
### De dónde salen los proxies residenciales ### De dónde salen los proxies residenciales
Aquí está la parte turbia del sector, y es material de charla. La mayoría del inventario La mayoría del inventario residencial no viene de servidores: viene de SDKs embebidos en apps y
residencial no viene de servidores: viene de **SDKs embebidos en apps gratuitas y VPNs VPNs gratuitas, que convierten el móvil del usuario en nodo de salida a cambio de que la app sea
"gratuitas"**, que convierten el móvil del usuario en un nodo de salida a cambio de que la app sea
gratis. El consentimiento suele estar enterrado en unos términos que nadie lee. gratis. El consentimiento suele estar enterrado en unos términos que nadie lee.
Es decir: cuando alguien compra tráfico residencial, muy probablemente está saliendo por la Cuando alguien compra tráfico residencial, muy probablemente está saliendo por la conexión de una
conexión de una persona que no lo sabe. Eso ha generado litigios y es uno de los ángulos persona que no lo sabe. Eso ha generado litigios.
periodísticos más fértiles del tema.
### Qué mira la plataforma, más allá de la clase ### Qué mira la plataforma, más allá de la clase
@ -148,13 +138,13 @@ MaxMind, IPQualityScore, Spur, IPinfo — que vende exactamente esto:
- **Huella de transporte**: JA3/JA4 (el fingerprint del handshake TLS), orden de cabeceras HTTP, - **Huella de transporte**: JA3/JA4 (el fingerprint del handshake TLS), orden de cabeceras HTTP,
versión de la librería de red. Identifica al cliente por debajo de la aplicación versión de la librería de red. Identifica al cliente por debajo de la aplicación
Ese último punto es el que sorprende: **no hace falta mirar la app para saber que no es la app.** Con eso último no hace falta mirar la app para saber que no es la app.
--- ---
## 3 · Atestación de dispositivo ## 3 · Atestación de dispositivo
La tercera pregunta: *¿qué dispositivo eres?* Y es donde la partida se decidió del todo. La tercera pregunta: qué dispositivo eres. Es donde se decidió la partida.
### De SafetyNet a Play Integrity ### De SafetyNet a Play Integrity
@ -170,7 +160,7 @@ y la sustituyó por la **Play Integrity API**, que devuelve tres veredictos esca
### Qué significa "respaldada por hardware" ### Qué significa "respaldada por hardware"
Aquí está la clave técnica del proyecto entero, y merece entenderla bien. Es la clave técnica del proyecto entero.
Un Android certificado sale de fábrica con una **clave privada de atestación grabada en su elemento Un Android certificado sale de fábrica con una **clave privada de atestación grabada en su elemento
seguro** — el TEE, o StrongBox si hay chip dedicado. Esa clave nunca sale del hardware. Cuando la seguro** — el TEE, o StrongBox si hay chip dedicado. Esa clave nunca sale del hardware. Cuando la
@ -192,7 +182,7 @@ real, sin sensor de luz que varíe.
### Por qué esto ya no es una carrera armamentística ### Por qué esto ya no es una carrera armamentística
Este es el punto que hay que subrayar, porque cambia la naturaleza del problema: Esto cambia la naturaleza del problema:
> La detección de emulador dejó de ser **estadística** y pasó a ser **criptográfica**. > La detección de emulador dejó de ser **estadística** y pasó a ser **criptográfica**.
@ -201,10 +191,8 @@ esquivar. Ahora es verificar una firma contra una raíz de confianza. **O tienes
tienes.** No hay evasión posible, solo robo de claves de dispositivos reales, que es otro delito y tienes.** No hay evasión posible, solo robo de claves de dispositivos reales, que es otro delito y
otro mercado. otro mercado.
Y ahí está la explicación de la pregunta que abrió toda esta investigación: **por qué GenFarmer te Explica también por qué GenFarmer vende cajas con teléfonos físicos de 400 $ en vez de software
vende cajas con teléfonos físicos de 400 $ en vez de venderte software para tu servidor.** No es para tu servidor: lo que venden no es cómputo, es el único sitio donde vive la clave.
que no sepan hacer software. Es que lo que venden no es cómputo, es **el único sitio donde vive la
clave**.
--- ---
@ -230,7 +218,7 @@ Las aristas que unen el grafo:
- **Temporal**: cohortes de registro. 45 cuentas dadas de alta el mismo martes por la tarde ya son - **Temporal**: cohortes de registro. 45 cuentas dadas de alta el mismo martes por la tarde ya son
un grupo, aunque todo lo demás esté impecable un grupo, aunque todo lo demás esté impecable
### La trampa matemática ### El problema de escala
Fabricar **una** cuenta indistinguible de la de una persona real es caro pero factible. Fabricar **una** cuenta indistinguible de la de una persona real es caro pero factible.
@ -252,23 +240,15 @@ proxies de los móviles de terceros. Que es exactamente **lo que persiguen y por
## 5 · Qué significa para este proyecto ## 5 · Qué significa para este proyecto
Sin rodeos, y es la conclusión que ordena todo el repositorio: El rack no sirve para las plataformas sociales, y no por falta de potencia: no tiene la clave.
**El rack no sirve para las plataformas sociales, y no por falta de potencia.** No tiene la clave.
Ninguna cantidad de blades, RAM o ancho de banda produce una clave de atestación grabada en Ninguna cantidad de blades, RAM o ancho de banda produce una clave de atestación grabada en
fábrica. La detección no es un umbral que se pueda esquivar, es una firma que no se puede fábrica. La detección no es un umbral que se pueda esquivar, es una firma que no se puede
falsificar. falsificar.
**El rack sí sirve, y muy bien, como laboratorio de QA propio.** Probar `oasis_mobile` en una Sí sirve como laboratorio de QA propio. Probar `oasis_mobile` en una matriz de versiones de
matriz de versiones de Android, y el escenario multi-dispositivo de los dos APKs que se tienen que Android, y el escenario multi-dispositivo de los dos APKs que se tienen que ver entre sí, es
ver entre sí, es exactamente para lo que 45 Android en red interna son inmejorables. Ahí no hay exactamente para lo que 45 Android en red interna son buenos. Ahí no hay atestación que superar:
ninguna atestación que superar: es tu app en tus dispositivos. es tu app en tus dispositivos.
**Y para la charla, esto es la tesis.** Ver [../03_charla/](../03_charla/):
> La granja de bots perdió la guerra técnica el día que la atestación pasó de estadística a
> criptográfica. Lo que queda no es un problema de cómputo, es un problema de identidad — y quien
> controla las SIMs controla el mercado. Por eso ahí es exactamente donde pega la policía.
--- ---

View file

@ -21,7 +21,7 @@
versiones nuevas de Android. versiones nuevas de Android.
- Encima: **Appium/UIAutomator2** para conducir, **scrcpy** para ver, **ADB sobre TCP** para todo. - Encima: **Appium/UIAutomator2** para conducir, **scrcpy** para ver, **ADB sobre TCP** para todo.
## El jarro de agua fría ## Lo que un rack no resuelve
Ese rack **no sirve** para el caso TikTok/Instagram, y esa es exactamente la razón por la que Ese rack **no sirve** para el caso TikTok/Instagram, y esa es exactamente la razón por la que
GenFarmer vende cajas con teléfonos físicos de $400 en vez de vender software para tu servidor. GenFarmer vende cajas con teléfonos físicos de $400 en vez de vender software para tu servidor.

View file

@ -11,7 +11,7 @@ kernel de una máquina Debian.
| | Para qué | | | Para qué |
|---|---| |---|---|
| **[ansible/](ansible/)** | **La granja de verdad**: los 16 blades del M1000e, provisionados y controlados desde un sitio. Es lo que hay que usar. | | [ansible/](ansible/) | Los 16 blades del M1000e, provisionados y controlados desde un sitio. Es la vía principal. |
| Este documento | Un solo nodo, a mano. Sirve para entender las piezas y para trastear en el sobremesa. | | Este documento | Un solo nodo, a mano. Sirve para entender las piezas y para trastear en el sobremesa. |
El hardware está descrito en [hardware_m1000e.md](hardware_m1000e.md). El hardware está descrito en [hardware_m1000e.md](hardware_m1000e.md).

View file

@ -9,6 +9,8 @@ del blade. Es la única forma sensata de hacer esto con el hardware que hay.
## La arquitectura ## La arquitectura
![Arquitectura de la granja](../../assets/arquitectura.svg)
``` ```
Dell PowerEdge M1000e — 16 blades Dell PowerEdge M1000e — 16 blades
@ -45,6 +47,13 @@ sudo apt install ansible
- Salida a internet, o un mirror local de `download.docker.com` y `deb.debian.org` - Salida a internet, o un mirror local de `download.docker.com` y `deb.debian.org`
- Kernel con `binder_linux.ko` (el estándar de Debian lo trae) - Kernel con `binder_linux.ko` (el estándar de Debian lo trae)
**Chasis** — un módulo de I/O en **A1** como mínimo. La Fabric A es la Ethernet integrada (LOM) de
cada blade, así que **no hacen falta tarjetas intermedias**; las Fabrics B y C sí las exigirían y
no se usan aquí. Si en A1/A2 hay un módulo **switch**, la conmutación entre blades es interna al
chasis, que es lo que necesita `macvlan`. Si hay un módulo de **paso a través**, salen 16 RJ-45 al
exterior y la conmutación depende de un switch externo. Ver
[hardware_m1000e.md](../hardware_m1000e.md).
**Ejecuta siempre desde este directorio** (`ansible/`) — `ansible.cfg` y las rutas de roles son **Ejecuta siempre desde este directorio** (`ansible/`) — `ansible.cfg` y las rutas de roles son
relativas a él. relativas a él.
@ -121,6 +130,8 @@ Se controla con `redroid_network_mode` en `group_vars/all.yml`.
Cada Android detrás de NAT de Docker; adb en `<ip_blade>:<puerto>`, empezando en 5555. Cada Android detrás de NAT de Docker; adb en `<ip_blade>:<puerto>`, empezando en 5555.
Funciona en cualquier sitio sin saber nada de la LAN. Es el modo con el que empezar. Funciona en cualquier sitio sin saber nada de la LAN. Es el modo con el que empezar.
![Los dos modos de red](../../assets/red-modos.svg)
### `macvlan` — el que quieres para `oasis_mobile` ### `macvlan` — el que quieres para `oasis_mobile`
Cada Android coge una **IP real de la LAN** a través del switch FlexIO del chasis. Los dos APKs Cada Android coge una **IP real de la LAN** a través del switch FlexIO del chasis. Los dos APKs

View file

@ -1,61 +1,235 @@
# El hardware: Dell PowerEdge M1000e # El hardware: Dell PowerEdge M1000e
Identificado el 2026-08-08. Fuente: `~/Downloads/poweredge-m1000e-spec-sheet.pdf` > **Fuente**: *Gabinete Dell PowerEdge M1000e — Manual del propietario*, modelo reglamentario
(spec sheet oficial Dell EMC, 6 de diciembre de 2016). > **BMX01**, rev. A06, octubre 2019 (© 2014-2019 Dell Inc.), más el spec sheet de dic. 2016.
> Los datos de esta página vienen del manual oficial y **sustituyen a las estimaciones previas**.
No es un servidor suelto: es un **chasis de blades**. Cada blade es una máquina independiente No es un servidor suelto: es un **chasis de blades**. Cada blade es una máquina independiente con
con su CPU y su RAM. su CPU y su RAM. Los ventiladores, las fuentes, la CMC y los módulos de I/O son **recursos
compartidos** de todos los blades.
## Especificaciones del chasis ---
## Panel frontal — los blades
```
┌──────────────────────────────────────────────────────────────────────────┐
│ │
│ ┌────┐┌────┐┌────┐┌────┐┌────┐┌────┐┌────┐┌────┐ ┌───────┐ │
│ │ 1 ││ 2 ││ 3 ││ 4 ││ 5 ││ 6 ││ 7 ││ 8 │ │ LCD │ │
│ │ ││ ││ ││ ││ ││ ││ ││ │ │ panel │ │
│ └────┘└────┘└────┘└────┘└────┘└────┘└────┘└────┘ │ ctrl │ │
│ ┌────┐┌────┐┌────┐┌────┐┌────┐┌────┐┌────┐┌────┐ │ │ │
│ │ 9 ││ 10 ││ 11 ││ 12 ││ 13 ││ 14 ││ 15 ││ 16 │ │ 2×USB │ │
│ │ ││ ││ ││ ││ ││ ││ ││ │ │ VGA │ │
│ └────┘└────┘└────┘└────┘└────┘└────┘└────┘└────┘ └───────┘ │
│ │
└──────────────────────────────────────────────────────────────────────────┘
16 blades de media altura — 8 arriba y 8 abajo
```
El chasis admite **16 blades de media altura**, u 8 de altura completa, u 8 fundas de cuarto de
altura, o una combinación.
> **Todos los compartimentos deben ir ocupados en todo momento**, con un blade o con un módulo de
> relleno. No es una recomendación estética: sin relleno, el aire se escapa por el hueco y la
> refrigeración del resto se degrada.
---
## Panel posterior — la infraestructura compartida
```
┌──────────────────────────────────────────────────────────────────────────┐
│ ┌───┐┌───┐┌───┐┌───┐┌───┐┌───┐┌───┐┌───┐┌───┐ │
│ │ V ││ V ││ V ││ V ││ V ││ V ││ V ││ V ││ V │ 9 módulos de ventilador │
│ └───┘└───┘└───┘└───┘└───┘└───┘└───┘└───┘└───┘ (los 9, obligatorios) │
│ │
│ ┌──────────────┐ ┌─────────┐ ┌──────────────┐ │
│ │ A1 B1 C1 │ │ CMC 1 │ │ C2 B2 A2 │ 6 módulos de I/O │
│ │ │ │ iKVM │ │ │ + 2 CMC │
│ │ (izquierda) │ │ CMC 2 │ │ (derecha) │ + iKVM opcional │
│ └──────────────┘ └─────────┘ └──────────────┘ │
│ │
│ ┌────┐┌────┐┌────┐┌────┐┌────┐┌────┐ │
│ │PSU ││PSU ││PSU ││PSU ││PSU ││PSU │ 6 fuentes de alimentación │
│ └────┘└────┘└────┘└────┘└────┘└────┘ (las 6, obligatorias) │
└──────────────────────────────────────────────────────────────────────────┘
```
Dos exigencias del manual que cambian el planteamiento del proyecto:
> **«El sistema requiere seis fuentes de alimentación para su funcionamiento habitual.»**
> **«Los nueve módulos de ventilador deben instalarse en todo momento para garantizar un
> enfriamiento adecuado.»**
No se puede arrancar este chasis a medias. Seis fuentes, nueve ventiladores y todas las bahías
tapadas, se usen 3 blades o 16. Es el motivo técnico de por qué **los pilotos parciales en el
chasis son mal negocio** — ver [../docs/costes.md](../docs/costes.md).
---
## Fabrics: cómo se conecta un blade a la red
Esta es la parte del manual que más afecta al diseño del laboratorio. El M1000e tiene **tres
fabrics redundantes**, y no todas sirven para lo mismo:
```
blade-NN FABRICS exterior
┌──────────────┐
│ │ ┌──────────────────┐
│ LOM NIC1 ──┼───────────►│ A1 (switch) │──────────────► LAN
│ (integrado) │ ├──────────────────┤ (uplink)
│ NIC2 ──┼───────────►│ A2 (switch) │──────────────► LAN
│ │ └──────────────────┘ (redundante)
│ │ FABRIC A — Ethernet
│ │
│ mezz B ─────┼───────────► B1 / B2 140 Gb/s: FC, InfiniBand, 10 GbE
│ mezz C ─────┼───────────► C1 / C2 140 Gb/s: ídem
└──────────────┘ requieren tarjeta intermedia en el blade
```
**Para este proyecto solo importa la Fabric A**, y es una buena noticia:
- Fabric A es la **Ethernet integrada de cada blade** (la LOM). No hace falta comprar ni instalar
tarjetas intermedias.
- Soporta KR (10 Gbps estándar).
- Sus ranuras son **A1 y A2**. Con un módulo en A1 basta para arrancar; A1 + A2 da redundancia.
- Las Fabrics B y C **necesitan tarjeta intermedia en cada blade**. Si el chasis no las trae, no se
usan — y para 45 Android por adb no hacen ninguna falta.
**Lo que hay que verificar en el chasis real**: qué módulo hay en A1/A2. Un módulo de switch
(PowerConnect M6220 / M6348, Force10 MXL, M8024-k…) da conmutación interna entre blades, que es
justo lo que necesita el modo `macvlan`. Un **módulo de paso a través** en cambio saca 16 puertos
RJ-45 al exterior, uno por blade, y entonces la conmutación depende de un switch externo.
> Los módulos pensados para Fabric B o C **no entran físicamente** en A1/A2 — el manual dice que
> están codificados por color en la placa frontal para evitarlo.
---
## Especificaciones oficiales
### Físicas
| | | | | |
|---|---| |---|---|
| Factor de forma | Modular 10U — 44,0 alto × 44,7 ancho × 75,4 cm fondo | | Altura | 44,0 cm (17,3") — **10U** |
| Capacidad | **16 blades de media altura** (8 arriba + 8 abajo) · u 8 de altura completa · o 32 de cuarto | | Anchura | 44,7 cm (17,6") |
| Alimentación | Hasta 6 fuentes de 3.000 W / 2.700 W (config 3+3, 2+2, 2+1…) | | Profundidad | 75,5 cm (29,7") |
| Refrigeración | 9 módulos de ventiladores redundantes | | **Peso máximo** | **200,5 kg** (442 lb) |
| Gestión | CMC (Chassis Management Controller) + iDRAC por blade; web SSL, SSH/Telnet, LDAP/AD | | Peso vacío | 44,6 kg (98,1 lb) |
| Red interna | Hasta 6 módulos I/O FlexIO — los blades se ven entre sí a 1/10 GbE |
| Peso | 44 kg vacío · 179 kg cargado | > El peso máximo corregido son **200,5 kg**, no los 179 kg del spec sheet comercial. El manual
> manda: el rack y el suelo tienen que ir sobrados.
### Alimentación
| | Fuente de 2.700 W | Fuente de 3.000 W |
|---|---|---|
| Conector | **CEI/IEC C20** | IEC 320 |
| Tensión de entrada | 100240 V CA, **16 A** | **200240 V CA**, 16 A |
| Frecuencia | 50/60 Hz | 50/60 Hz |
| Disipación propia | 353 W (1.205 BTU/h) máx. | 1.200 BTU/h máx. |
| **Corriente de irrupción** | **55 A durante ≤10 ms, por fuente** | ídem |
Tres consecuencias prácticas:
1. **La fuente de 3.000 W exige 200240 V.** España a 230 V vale; una instalación a 110 V no.
2. **Seis entradas C19/C20.** Hace falta una PDU adecuada — los C13 domésticos no valen.
3. **La corriente de irrupción es el detalle que se olvida**: 55 A por fuente durante 10 ms. Con
seis fuentes arrancando a la vez, un magnetotérmico de curva C salta. Hace falta **curva D**, o
arranque escalonado de las fuentes.
### Ambientales — el requisito que muerde en verano
| | |
|---|---|
| **Funcionamiento continuo** | **10 °C a 35 °C**, humedad relativa 1080 % |
| Ampliado, <10 % de las horas anuales | 5 °C a 40 °C |
| Ampliado, <1 % de las horas anuales | 5 °C a 45 °C |
| Almacenamiento | 40 °C a 65 °C |
| Derating por altitud | 1 °C cada 300 m por encima de 900 m |
**35 °C es el techo continuo.** Una habitación en Madrid en agosto, con 2,6 kW de calor dentro y
sin climatización, se pone por encima de eso sin dificultad. El rango ampliado cubre menos del
10 % de las horas del año: no es una solución, es un margen para incidencias.
### Modo de refrigeración mejorado (ECM)
La CMC permite activar **ECM**, que exige los nueve ventiladores de tercera generación. El manual
lo declara **obligatorio** en tres casos:
- Blades **M630 con procesadores de 120 W o más**
- Blades **M630 en entornos por encima de 30 °C**
- Cualquier configuración con aire fresco
ECM significa más caudal, y por tanto **más consumo y más ruido**. Si los blades resultan ser M630
y el sitio pasa de 30 °C, hay que contarlo.
### Gestión — CMC
| | |
|---|---|
| Módulos | CMC 1 (principal) + CMC 2 (secundaria, a prueba de fallos) |
| Puertos | Dos RJ-45 10/100/1000: **Gb** a la red de gestión, **STK** para encadenar chasis contiguos |
| Serie | 9 patas DTE, compatible 16550 |
| Vídeo | VGA 15 patas |
| Batería | CR2032 |
| Interfaces | Web (SSL), **RACADM** por CLI, SSH/Telnet |
La CMC **reasigna energía entre módulos según la demanda** y expone presupuesto de alimentación y
política de redundancia en *Chassis → Power Management → Configuración*. Es también donde se lee el
**consumo real**, que es lo que sustituye a las estimaciones de [../docs/costes.md](../docs/costes.md).
---
## Configuración de esta máquina ## Configuración de esta máquina
Según lo que recuerda el usuario: | | |
|---|---|
| Blades | 16, 8 arriba y 8 abajo |
| RAM por blade | 8 GB → 128 GB totales, **repartidos, no agrupados** |
| Modelo de blade | **desconocido** — M610 / M620 / M630. Lo resuelve `preflight.yml` leyendo DMI |
| Módulo en A1/A2 | **desconocido** — switch o paso a través. Determina si `macvlan` funciona sin switch externo |
| Estado del CMC | **desconocido** |
- **16 blades**, 8 arriba y 8 abajo El manual menciona explícitamente compatibilidad con **M610x**, **M630** y **M710HD**, así que el
- **8 GB de RAM por blade** → 128 GB totales, pero **repartidos, no agrupados** abanico de blades posibles es amplio y la generación no se puede inferir del chasis.
- Modelo de blade: **desconocido** (M610 / M620 / M630 — pendiente de confirmar en el frontal)
- Estado / ubicación / accesibilidad de red: **pendiente** ---
## Qué implica para el device lab ## Qué implica para el device lab
### A favor ### A favor
- 16 máquinas independientes con **red interna de chasis**. Mejor topología que un solo host para - 16 máquinas independientes con **conmutación interna por Fabric A**, sin comprar tarjetas
el escenario de `oasis_mobile` con **dos APKs que se tienen que ver entre sí**: el switch FlexIO intermedias. Es la topología ideal para el escenario de `oasis_mobile` con **dos APKs que se
los pone en la misma L2 sin montar nada. tienen que ver entre sí**: quedan en la misma L2 sin montar nada.
- Con 8 GB por blade menos Debian + Docker (~11,5 GB), salen **~3 instancias redroid por blade** - Con 8 GB por blade menos Debian y Docker, **~3 instancias redroid por blade → ~45 en total**.
**~48 instancias totales**. Casi el triple que el sobremesa (1220).
### En contra ### En contra
- **Consumo: 1,52,5 kW en marcha.** A precio doméstico en España, del orden de **160350 €/mes** - **Seis fuentes y nueve ventiladores obligatorios**, se usen 3 blades o 16. El coste fijo no baja
si está 24/7. Este es el factor que decide la viabilidad, no los cores. al usar menos.
- **Ruido**: no es máquina de casa. Necesita sala con extracción. - **Consumo 2,63,6 kW**, del orden de 360 €/mes a 24/7.
- **Sin GPU** en los blades → `redroid_gpu_mode=guest` (render por software). Vale para test - **Techo térmico de 35 °C** continuos.
funcional, no para nada gráfico. - **Sin GPU** en los blades → `redroid_gpu_mode=guest`, render por software.
- **16 provisiones separadas**: cada blade necesita su Debian + Docker + módulo binder. A partir de - **16 provisiones separadas** — de ahí el Ansible.
4-5 blades esto pide Ansible o netboot, no hacerlo a mano.
### La palanca real ### La palanca sigue siendo la misma
El cuello de botella son **los 8 GB por blade, no la CPU**. Si los blades son M620 (DDR3 ECC), El cuello de botella son **los 8 GB por blade, no la CPU**. Ampliar a 32 GB sube de ~3 a
ampliar a 32 GB por blade cuesta poco en segunda mano y sube de ~3 a **~14 instancias por blade**. ~14 instancias por blade: de 45 a 210 Android por el mismo recibo de la luz.
Eso multiplica por 4-5 la capacidad del proyecto entero por menos de lo que cuesta un mes de luz.
---
## Pendiente de averiguar ## Pendiente de averiguar
- [ ] **Modelo de blade** (serigrafiado en el frontal) → determina CPU, generación y tipo de RAM - [ ] **Modelo de blade**`ansible-playbook playbooks/preflight.yml`
- [ ] ¿Está encendido y accesible el CMC en red? Si responde, da el inventario completo - [ ] **Qué módulo hay en A1/A2** (switch o paso a través) → determina si `macvlan` necesita switch externo
- [ ] Ubicación física y quién asume el coste eléctrico - [ ] ¿Están las 6 fuentes y los 9 ventiladores? ¿Y los rellenos en las bahías vacías?
- [ ] Con eso: decidir si se levantan los 16 blades o solo 2-3 como piloto - [ ] ¿Responde el CMC? Da inventario completo y **consumo real**
- [ ] ¿Hay ventiladores de 3.ª generación, por si hace falta ECM?
- [ ] Ubicación: potencia, PDU con 6 tomas C19, magnetotérmico de curva D y temperatura bajo 35 °C

View file

@ -1,44 +0,0 @@
# Charla: la economía de las granjas de bots
Vía 2. Ángulo defensivo/periodístico, no operativo. Hay demanda real de esto y encaja con
HackMadrid, los hacklabs y **Hackmeeting València (912 oct 2026)**.
## Tesis
La granja de bots perdió la guerra técnica y la ganó la económica. La detección de emulador es
determinista desde 2025 (Play Integrity con atestación por hardware), así que el negocio se vio
forzado a volver al hardware físico, caro y lento. Lo que queda no es un problema de cómputo sino
de identidad: **quien controla las SIMs controla el mercado** — y por eso ahí es donde pega la
policía.
## Guion propuesto
1. **Las tres cosas que llamamos "phone farm"** — reward farming / device lab / account farming.
Desmontar la confusión de entrada.
2. **El catálogo real** — GenFarmer y PhoneFarmBox como material de clase: qué venden, a qué
precio, qué revela su marketing (Zalo, Telegram-only, "300+ dispositivos").
3. **Por qué no puedes hacerlo con un servidor** — atestación por hardware, sensores, baseband.
El momento en que el cómputo dejó de ser el cuello de botella.
4. **La capa SIM** — el eslabón débil, con KYC en origen y rastro de dinero.
5. **SIMCARTEL** — 1.200 SIM-boxes, 40.000 SIMs, 49 millones de cuentas falsas, 7 detenidos.
El caso que cierra el argumento.
6. **Qué significa para quien defiende** — cómo se ve una granja desde el otro lado y qué señales
deja.
## Material
El sustrato de los puntos 3, 4 y 5 está entero en
**[../01_investigacion/capa_identidad.md](../01_investigacion/capa_identidad.md)** — verificación
telefónica, por qué la eSIM no vale, reputación de IP, atestación por hardware y la correlación
entre cuentas. Es el documento del que sale la tesis.
El resto en [../01_investigacion/](../01_investigacion/); las fuentes citables en
[../01_investigacion/fuentes.md](../01_investigacion/fuentes.md).
## Pendiente
- [ ] Decidir formato y duración
- [ ] Contactar HackMadrid / CFP de Hackmeeting València
- [ ] Buscar cifras actualizadas de 2026 (los datos son de oct 2025)
- [ ] ¿Demo en vivo? El device lab de [../02_device_lab/](../02_device_lab/) sirve para enseñar
cómo se detecta un emulador

156
GUIA.md
View file

@ -1,137 +1,91 @@
# Guía de trabajo # Guía de trabajo
Cómo seguir con esto. Estado real, qué está verificado y qué no, y por dónde continuar. ## Estado
---
## Estado a 2026-08-08
| Parte | Estado | | Parte | Estado |
|---|---| |---|---|
| Investigación | **Cerrada.** Cinco documentos en `01_investigacion/` | | Investigación | Cerrada, en `01_investigacion/` |
| Automatización Ansible | **Escrita, sin ejecutar** contra hardware | | Automatización Ansible | Escrita, sin ejecutar contra hardware |
| Documentación de requisitos, costes y seguridad | **Cerrada** | | Requisitos, costes y seguridad | Cerrados |
| Hardware | **Sin acceso.** Modelo de blade sin confirmar | | Hardware | Sin acceso. Modelo de blade sin confirmar |
| Decisión de qué vía se ejecuta | **Pendiente** |
### Qué está verificado ### Verificado
- Los 18 ficheros YAML parsean correctamente - Los 19 ficheros YAML parsean
- La plantilla de `docker-compose` renderiza YAML válido en **los dos modos de red**, con puertos - La plantilla de `docker-compose` renderiza YAML válido en los dos modos de red, con puertos e
e IPs bien asignados IPs bien asignados
- `fleet.sh` pasa `bash -n` una vez renderizado, sin Jinja pendiente - `fleet.sh` pasa `bash -n` una vez renderizado
- El M1000e está identificado por su spec sheet oficial (Dell EMC, dic 2016) - Los 4 diagramas SVG parsean y renderizan sin desbordes
- Las especificaciones del chasis vienen del manual del propietario (Dell, BMX01, rev. A06,
oct. 2019), no de estimaciones
### Qué NO está verificado ### Sin verificar
Y conviene tenerlo claro antes de fiarse de nada: - Nada se ha ejecutado contra hardware real
- Que las imágenes x86_64 de Android arranquen en la generación de CPU de estos blades. Es el
- **Nada se ha ejecutado contra hardware real.** Ni un blade, ni el sobremesa riesgo si resultan ser M610 (Xeon 20092011)
- Que las imágenes x86_64 de Android arranquen en la generación de CPU de estos blades — - El comportamiento de `macvlan` sobre los módulos de I/O concretos del chasis
el riesgo real si resultan ser **M610** (Xeon 20092011) - Que 3 instancias por blade sean cómodas con 8 GB en carga real
- El comportamiento de `macvlan` sobre los switches FlexIO concretos del chasis - Las cifras de consumo son estimaciones. El CMC da el dato real
- Que 3 instancias por blade sean cómodas con 8 GB en carga real, no solo en el papel
- **Las cifras de consumo son estimaciones.** El CMC da el dato real; media hora ahí sustituye
todo `docs/costes.md` por medidas
---
## Las tres vías
Ninguna elegida todavía.
### 1 · Device lab en el rack
Infra legal y reutilizable. Primer uso real: probar `oasis_mobile` a escala, incluido el escenario
de **dos APKs que se tienen que ver entre sí**. La automatización ya está escrita.
**Bloqueante**: sitio con 2,63,6 kW, extracción y tolerancia a 7085 dB. Ver
[docs/requisitos.md](docs/requisitos.md).
### 2 · Charla sobre la economía de los bots
Ángulo defensivo y periodístico, con demanda real. HackMadrid, hacklabs, **Hackmeeting València
(912 oct 2026)**. El material está entero en `01_investigacion/`; el guion en
[03_charla/](03_charla/).
**Es la vía con menos fricción**: no necesita encender nada.
### 3 · Reward farming
Ingreso pasivo, legal-gris. Márgenes malos en 2026. Documentado por completitud, no recomendado.
---
## Preguntas abiertas ## Preguntas abiertas
Por orden de lo que más desbloquea: 1. **Modelo de blade**: M610 / M620 / M630. Determina CPU, generación y tipo de RAM.
`ansible-playbook playbooks/preflight.yml`
2. **Qué módulo hay en A1/A2**: un switch conmuta entre blades dentro del chasis, que es lo que
necesita `macvlan`; un módulo de paso a través saca 16 RJ-45 y deja la conmutación a un switch
externo. Cambia el montaje de red por completo
3. **¿Responde el CMC?** Da el inventario completo y el consumo real
4. **Dónde va el chasis y quién paga la luz.** El sitio tiene que estar por debajo de 35 °C todo
el año
5. **Utilización prevista.** Por debajo del ~12 %, la nube sale más barata que tenerlo 24/7
1. **¿Qué modelo de blade hay en el chasis?** M610 / M620 / M630. Determina CPU, generación y tipo ## Siguientes pasos
de RAM — y si el proyecto es viable. → `ansible-playbook playbooks/preflight.yml`
2. **¿Responde el CMC en red?** Si sí, da el inventario completo y el **consumo real**
3. **¿Dónde va el chasis y quién asume la factura?** Es lo que decide, más que ninguna
consideración técnica
4. **¿Cuánta utilización real va a tener?** Por debajo del ~11 % la nube sale más barata que
tenerlo 24/7. Ver [docs/costes.md](docs/costes.md)
--- ### Sin hardware
## Siguientes pasos concretos - [ ] Lanzar el piloto de un nodo en un sobremesa. El bloque está comentado en
`02_device_lab/ansible/inventory/hosts.yml.example`
- [ ] Confirmar que redroid arranca, que `fleet` habla con los contenedores y que un APK de
`oasis_mobile` se instala en toda la flota
### Sin tocar el hardware (se puede hacer hoy) ### Con acceso al chasis
- [ ] Lanzar el **piloto de un nodo** en un sobremesa: valida el pipeline entero por ~20 €/mes. - [ ] Cambiar credenciales de fábrica del CMC y de los 16 iDRAC (`root`/`calvin`) — S2
El bloque está comentado en `02_device_lab/ansible/inventory/hosts.yml.example` - [ ] VLAN aislada para la granja y otra para gestión — S1 y S3
- [ ] Con eso, confirmar que redroid arranca, que `fleet` habla con los contenedores y que un APK - [ ] `preflight.yml` sobre los 16 blades
de `oasis_mobile` se instala en toda la flota
- [ ] Preparar la charla — el material ya está
### Cuando haya acceso al chasis
- [ ] Credenciales de fábrica del **CMC y de los 16 iDRAC** (`root`/`calvin`) —
[docs/seguridad.md](docs/seguridad.md) S2
- [ ] VLAN aislada para la granja y **otra** para gestión — S1 y S3
- [ ] `preflight.yml` sobre los 16 blades → informe en `ansible/reports/`
- [ ] Medir consumo real en el CMC y corregir `docs/costes.md` - [ ] Medir consumo real en el CMC y corregir `docs/costes.md`
- [ ] Decidir sobre la ampliación de RAM: es lo único que cambia la economía del proyecto - [ ] Decidir la ampliación de RAM: es lo único que cambia la economía (8,0 € → 1,8 € por
(7,6 € → 1,7 € por dispositivo/mes) dispositivo y mes)
### Mejoras pendientes en el código ### Pendiente en el código
- [ ] Fijar la imagen de redroid **por digest** en vez de por tag mutable — S6 - [ ] Fijar la imagen de redroid por digest en vez de por tag mutable — S6
- [ ] Cortafuegos (nftables) en los blades: 5555+ solo desde el coordinador — S1 - [ ] nftables en los blades: 5555+ solo desde el coordinador — S1
- [ ] `ansible-vault` para secretos — S7 - [ ] `ansible-vault` para secretos — S7
- [ ] Rol de GADS, cuando la flota pase de una decena de dispositivos. No está automatizado a - [ ] Script de encendido y apagado por ventanas contra el CMC vía RACADM
propósito: montar un despliegue de Node sin poder probarlo es complejidad sin verificar - [ ] Rol de GADS cuando la flota pase de una decena de dispositivos
- [ ] Provisión de Debian por PXE, para no instalar 16 blades a mano - [ ] Provisión de Debian por PXE, para no instalar 16 blades a mano
---
## Convenciones ## Convenciones
**Documentación en castellano.** Es un repo de trabajo, no un producto. Documentación en castellano.
**Todo lo verificable, verificado, y lo demás dicho.** Si algo no se ha ejecutado, el documento lo Lo verificable se verifica y lo demás se dice. Si algo no se ha ejecutado, el documento lo indica.
dice. Las estimaciones van etiquetadas como estimaciones y con sus supuestos a la vista. Si Las estimaciones van con sus supuestos a la vista.
encuentras una afirmación sin respaldo, es un fallo — corrígela o márcala.
**Los hallazgos de seguridad se numeran** (S1…S11 en [docs/seguridad.md](docs/seguridad.md)) y se Los hallazgos de seguridad se numeran (S1…S11 en [docs/seguridad.md](docs/seguridad.md)) y se
referencian por número desde el resto del repositorio. referencian por número.
**Nada operativo de alta masiva de cuentas.** Ni proveedores de SIM, ni evasión de fingerprint, ni Nada de operativa de alta masiva de cuentas: está bajo persecución activa en la UE y no funciona
maduración. No es una postura moral: es que está bajo persecución activa en la UE y **no funciona**
con este hardware, por lo que explica con este hardware, por lo que explica
[01_investigacion/capa_identidad.md](01_investigacion/capa_identidad.md). [01_investigacion/capa_identidad.md](01_investigacion/capa_identidad.md).
--- ## Fuera del repositorio
## Qué NO se sube al repositorio
Está en `.gitignore`, pero conviene saber por qué:
| | | | | |
|---|---| |---|---|
| `inventory/hosts.yml` | IPs reales de los blades y posibles credenciales. Solo va el `.example` | | `inventory/hosts.yml` | IPs reales y posibles credenciales. Solo se versiona el `.example` |
| `ansible/reports/` | Informes de preflight con el inventario real del hardware | | `ansible/reports/` | Informes de preflight con el inventario real |
| `*.apk` | Binarios | | `*.apk` | Binarios |
| `vault.yml`, `*.vault` | Secretos de ansible-vault | | `vault.yml`, `*.vault` | Secretos de ansible-vault |

177
README.md
View file

@ -1,151 +1,114 @@
# Rebelión en la granja # Rebelión en la granja
Investigación y laboratorio sobre **granjas de dispositivos**: qué son realmente, quién las Laboratorio de dispositivos Android sobre un chasis de blades Dell PowerEdge M1000e, más la
fabrica, qué se puede montar con hardware propio y qué no, y por qué la partida técnica ya está investigación sobre granjas de dispositivos que llevó a montarlo así.
decidida.
Incluye la automatización completa para levantar un **laboratorio de dispositivos Android** sobre Sin móviles físicos: cada dispositivo es un contenedor
un chasis de blades Debian — legal, reutilizable y sin un solo móvil físico. [redroid](https://github.com/remote-android/redroid-doc) — Android real sobre el kernel del blade.
Arrancado el 2026-08-07 a raíz de dos webs del sector: ## Arquitectura
[phonefarmbox.com](https://www.phonefarmbox.com/) y [genfarmer.com](https://genfarmer.com/).
--- ![Arquitectura de la granja](assets/arquitectura.svg)
## La conclusión, por delante
> **El cuello de botella nunca fue el cómputo. Fue la identidad.**
>
> Desde que la atestación de dispositivo pasó de ser estadística a ser **criptográfica**, un
> servidor no puede hacerse pasar por un teléfono: le falta una clave grabada en fábrica que
> ningún software produce. Por eso el mercado vende cajas con teléfonos físicos de 400 $ en lugar
> de software para tu rack.
>
> Lo que queda es un problema de SIMs, de reputación de IP y de correlación entre cuentas. Y ahí es
> exactamente donde pega la policía.
El desarrollo está en **[01_investigacion/capa_identidad.md](01_investigacion/capa_identidad.md)**,
que es el documento central del repositorio.
---
## Qué hay aquí
### 📄 [docs/](docs/) — léelo antes de encender nada
| | |
|---|---|
| [requisitos.md](docs/requisitos.md) | Eléctrico, físico, hardware, red, tiempo. Con checklist de bloqueantes |
| [costes.md](docs/costes.md) | La luz es el coste real: ~340 €/mes 24/7, ~56 €/mes por ventanas |
| [seguridad.md](docs/seguridad.md) | 11 hallazgos, uno crítico. Incluye los que introduce este propio código |
### 🔍 [01_investigacion/](01_investigacion/) — el análisis
| | |
|---|---|
| [capa_identidad.md](01_investigacion/capa_identidad.md) | **El documento central.** Verificación telefónica, por qué la eSIM no vale, reputación de IP, atestación por hardware y la correlación entre cuentas |
| [mercado_y_players.md](01_investigacion/mercado_y_players.md) | Los tres negocios bajo el mismo nombre, quién juega en Europa, TikTok vs Instagram |
| [stack_tecnico.md](01_investigacion/stack_tecnico.md) | redroid, Cuttlefish, Waydroid, GADS — y por qué el rack no resuelve el caso social |
| [legal_ue.md](01_investigacion/legal_ue.md) | DSA, Operación SIMCARTEL, riesgo penal en España |
| [fuentes.md](01_investigacion/fuentes.md) | Enlaces |
### 🔧 [02_device_lab/](02_device_lab/) — el laboratorio
| | |
|---|---|
| [ansible/](02_device_lab/ansible/) | **La automatización completa**: preflight, despliegue de los 16 blades y control de flota |
| [hardware_m1000e.md](02_device_lab/hardware_m1000e.md) | El chasis, sus límites y la palanca (RAM) |
| [README.md](02_device_lab/README.md) | Montaje de un solo nodo, a mano, para entender las piezas |
### 🎤 [03_charla/](03_charla/) — divulgación
Guion de 6 puntos para HackMadrid / Hackmeeting València.
---
## Especificaciones
### Arquitectura
``` ```
Dell PowerEdge M1000e — chasis de blades, 16 slots (8 arriba + 8 abajo) Dell PowerEdge M1000e — 16 blades (8 arriba + 8 abajo)
├── blade-01 ................ COORDINADOR ├── blade-01 ................ coordinador: adb + fleet
│ └── adb + fleet único punto de control de toda la flota
└── blade-02 .. blade-16 .... NODOS DE CARGA (15) └── blade-02 .. blade-16 .... nodos de carga
└── Debian 12 pelado └── Debian 12
└── Docker └── Docker
└── N × redroid Android 13 en contenedor └── N × redroid
8 GB/blade → 3 instancias → ~45 Android 8 GB/blade → 3 instancias → 45 Android
32 GB/blade → 14 instancias → ~210 Android 32 GB/blade → 14 instancias → 210 Android
``` ```
**No hay móviles físicos.** Cada "dispositivo" es un contenedor Debian va directo sobre el hierro. Sin Proxmox, sin VMs, sin LXC anidado: con 8 GB por blade cada
[redroid](https://github.com/remote-android/redroid-doc): Android real sobre el kernel del blade. capa de hipervisor se come una instancia entera.
Debian va **directo sobre el hierro**. Sin Proxmox, sin VMs, sin LXC anidado — con 8 GB por blade, ## Hardware
cada capa de hipervisor se come una instancia Android entera.
### Stack ![Dell PowerEdge M1000e](assets/chasis.svg)
Datos del manual del propietario del M1000e (Dell, modelo BMX01, rev. A06, oct. 2019). Dos
exigencias del manual condicionan el proyecto entero: las seis fuentes y los nueve ventiladores son
obligatorios, se usen 3 blades o 16. No se puede arrancar el chasis a medias.
Detalle en [02_device_lab/hardware_m1000e.md](02_device_lab/hardware_m1000e.md).
## Software
![Stack de software](assets/stack-software.svg)
| Capa | Tecnología | | Capa | Tecnología |
|---|---| |---|---|
| Hardware | Dell PowerEdge M1000e, 16 blades, 8 GB/blade |
| SO | Debian 12 bookworm | | SO | Debian 12 bookworm |
| Kernel | `binder_linux` con devices `binder,hwbinder,vndbinder` (Debian no trae binderfs) | | Kernel | `binder_linux` con devices `binder,hwbinder,vndbinder` (Debian no trae binderfs) |
| Contenedores | Docker CE + Compose v2 | | Contenedores | Docker CE + Compose v2 |
| Android | redroid 13 (memfd, sin ashmem) | | Android | redroid 13 |
| Orquestación | Ansible — solo `ansible.builtin`, sin colecciones externas | | Orquestación | Ansible, solo `ansible.builtin` |
| Control | adb sobre TCP + `fleet` | | Control | adb sobre TCP + `fleet` |
| Red | `portmap` (NAT) o `macvlan` (IP real de LAN por el switch FlexIO) | | Red | `portmap` (NAT) o `macvlan` (IP real de LAN por Fabric A) |
### Números ## Red
![Los dos modos de red](assets/red-modos.svg)
## Números
| | | | | |
|---|---| |---|---|
| Capacidad | ~45 Android (~210 con la RAM ampliada) | | Capacidad | 45 Android; 210 con la RAM ampliada |
| Consumo | 2,63,6 kW · 7085 dB · 179 kg · 10U | | Chasis | 10U · 44,0 × 44,7 × 75,5 cm · 200,5 kg cargado |
| Coste 24/7 | ~340 €/mes (~4.100 €/año) | | Consumo | 2,63,6 kW · 7085 dB · 6 fuentes C20 · 9 ventiladores |
| Coste por ventanas de 4 h/día | ~56 €/mes | | Térmico | 1035 °C en continuo |
| Coste por dispositivo | 7,6 €/mes → **1,7 €/mes** con la RAM ampliada | | Coste 24/7 | ~360 €/mes |
| Coste por ventanas de 4 h/día | ~59 €/mes |
| Coste por dispositivo | 8,0 €/mes; 1,8 €/mes con la RAM ampliada |
--- ## Arranque
## Arranque rápido
```bash ```bash
git clone https://gitea.laenre.net/hacklab/REBELION_EN_LA_GRANJA.git git clone https://gitea.laenre.net/hacklab/REBELION_EN_LA_GRANJA.git
cd REBELION_EN_LA_GRANJA/02_device_lab/ansible cd REBELION_EN_LA_GRANJA/02_device_lab/ansible
sudo apt install ansible sudo apt install ansible
cp inventory/hosts.yml.example inventory/hosts.yml # pon las IPs reales cp inventory/hosts.yml.example inventory/hosts.yml # poner las IPs reales
ansible-playbook playbooks/preflight.yml # SOLO LECTURA — no toca nada ansible-playbook playbooks/preflight.yml # solo lectura, no toca nada
ansible-playbook site.yml # monta la granja ansible-playbook site.yml
ansible-playbook playbooks/status.yml ansible-playbook playbooks/status.yml
``` ```
**Empieza por el preflight siempre.** Te dice qué blades hay dentro del chasis leyéndolo del DMI, El preflight va primero. Identifica el modelo de blade leyéndolo del DMI, comprueba si esas CPUs
si esas CPUs pueden con Android x86_64, y cuántas instancias caben. Antes de gastar un minuto. sirven para Android x86_64 y calcula cuántas instancias caben.
**Y antes de encender el chasis**, el inventario trae un bloque de **piloto de un nodo** para Para probar sin encender el chasis, el inventario incluye un bloque de piloto de un nodo que
probar el pipeline entero en un sobremesa, por 20 €/mes y sin ruido. levanta todo el pipeline en un sobremesa.
Guía de trabajo y siguientes pasos: **[GUIA.md](GUIA.md)**. ## Contenido
--- | | |
|---|---|
| [GUIA.md](GUIA.md) | Estado, qué está verificado y qué no, siguientes pasos |
| [docs/requisitos.md](docs/requisitos.md) | Eléctrico, físico, red, tiempo. Checklist de bloqueantes |
| [docs/costes.md](docs/costes.md) | Consumo y coste por escenario |
| [docs/seguridad.md](docs/seguridad.md) | 11 hallazgos, uno crítico |
| [docs/usabilidad.md](docs/usabilidad.md) | Cómo se opera la flota |
| [02_device_lab/ansible/](02_device_lab/ansible/) | La automatización |
| [02_device_lab/hardware_m1000e.md](02_device_lab/hardware_m1000e.md) | El chasis según el manual |
| [01_investigacion/](01_investigacion/) | Mercado, stack, capa de identidad, marco legal |
## Aviso ## Por qué esto no sirve para plataformas sociales
Este repositorio documenta cómo funcionan las granjas de dispositivos y **por qué fracasan** contra La atestación de dispositivo dejó de ser estadística y pasó a ser criptográfica. Un Android
las plataformas. La automatización que contiene levanta un laboratorio de QA para probar apps certificado lleva una clave privada grabada en el TEE de fábrica, con cadena de certificados hasta
propias. una raíz de Google. Un contenedor no la tiene y no puede tenerla: no hay software que la produzca.
No contiene, ni va a contener, operativa de alta masiva de cuentas: proveedores de SIM, evasión de Por eso el mercado vende teléfonos físicos de 400 $ en lugar de software para racks, y por eso este
fingerprint o maduración de cuentas. Eso es fraude de identidad a escala, en la UE está bajo laboratorio sirve para probar apps propias y no para otra cosa. El desarrollo está en
persecución activa, y además **no funcionaría** con este hardware por lo que se explica en [01_investigacion/capa_identidad.md](01_investigacion/capa_identidad.md).
[capa_identidad.md](01_investigacion/capa_identidad.md).
Contexto legal: [legal_ue.md](01_investigacion/legal_ue.md). Este repositorio no contiene operativa de alta masiva de cuentas. Contexto legal en
[01_investigacion/legal_ue.md](01_investigacion/legal_ue.md).

103
assets/arquitectura.svg Normal file
View file

@ -0,0 +1,103 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 620" width="960" height="620" font-family="ui-monospace, 'DejaVu Sans Mono', Menlo, monospace">
<rect width="960" height="620" fill="#0f1720"/>
<text x="32" y="44" fill="#e6edf3" font-size="22" font-weight="bold" font-family="system-ui, sans-serif">Arquitectura de la granja</text>
<text x="32" y="68" fill="#7d8590" font-size="13">Dell PowerEdge M1000e · 16 blades Debian · ~45 Android en contenedor</text>
<!-- Chasis -->
<rect x="32" y="92" width="590" height="490" rx="8" fill="#161b22" stroke="#30363d" stroke-width="1.5"/>
<text x="52" y="118" fill="#58a6ff" font-size="13" font-weight="bold">CHASIS M1000e · 10U · 200,5 kg · 2,63,6 kW</text>
<!-- Coordinador -->
<rect x="52" y="134" width="550" height="72" rx="6" fill="#1c2128" stroke="#d29922" stroke-width="1.5"/>
<text x="68" y="158" fill="#d29922" font-size="13" font-weight="bold">blade-01 · COORDINADOR</text>
<text x="68" y="178" fill="#adbac7" font-size="11.5">Debian 12 · adb · fleet.sh · devices.txt</text>
<text x="68" y="196" fill="#7d8590" font-size="11">No corre Android. Único punto de control de la flota.</text>
<!-- Nodos de carga: header -->
<text x="52" y="238" fill="#3fb950" font-size="13" font-weight="bold">blade-02 … blade-16 · NODOS DE CARGA (15)</text>
<!-- Detalle de un blade -->
<rect x="52" y="252" width="270" height="240" rx="6" fill="#1c2128" stroke="#3fb950" stroke-width="1.5"/>
<text x="68" y="274" fill="#3fb950" font-size="12" font-weight="bold">blade-NN · 8 GB RAM</text>
<rect x="68" y="286" width="238" height="38" rx="4" fill="#22272e" stroke="#444c56"/>
<text x="80" y="303" fill="#adbac7" font-size="11">Debian 12 · sobre el hierro</text>
<text x="80" y="317" fill="#7d8590" font-size="9.5">binder · hwbinder · vndbinder</text>
<rect x="68" y="330" width="238" height="26" rx="4" fill="#22272e" stroke="#444c56"/>
<text x="80" y="347" fill="#adbac7" font-size="11">Docker CE + Compose v2</text>
<rect x="80" y="364" width="214" height="26" rx="4" fill="#1f6feb" fill-opacity="0.18" stroke="#1f6feb"/>
<text x="92" y="381" fill="#79c0ff" font-size="10.5">redroid-NN-01 · Android 13</text>
<rect x="80" y="394" width="214" height="26" rx="4" fill="#1f6feb" fill-opacity="0.18" stroke="#1f6feb"/>
<text x="92" y="411" fill="#79c0ff" font-size="10.5">redroid-NN-02 · Android 13</text>
<rect x="80" y="424" width="214" height="26" rx="4" fill="#1f6feb" fill-opacity="0.18" stroke="#1f6feb"/>
<text x="92" y="441" fill="#79c0ff" font-size="10.5">redroid-NN-03 · Android 13</text>
<text x="68" y="472" fill="#7d8590" font-size="10">Sin VM ni LXC anidado: cada capa</text>
<text x="68" y="485" fill="#7d8590" font-size="10">se comería una instancia entera.</text>
<!-- Los otros blades apilados -->
<g fill="#1c2128" stroke="#2d5a3d">
<rect x="342" y="252" width="260" height="34" rx="5"/>
<rect x="342" y="292" width="260" height="34" rx="5"/>
<rect x="342" y="332" width="260" height="34" rx="5"/>
<rect x="342" y="372" width="260" height="34" rx="5"/>
</g>
<text x="356" y="274" fill="#7d8590" font-size="11">blade-03 → 3 Android</text>
<text x="356" y="314" fill="#7d8590" font-size="11">blade-04 → 3 Android</text>
<text x="356" y="354" fill="#7d8590" font-size="11">blade-05 → 3 Android</text>
<text x="356" y="394" fill="#7d8590" font-size="11"></text>
<text x="356" y="428" fill="#7d8590" font-size="11">blade-16 → 3 Android</text>
<rect x="342" y="444" width="260" height="48" rx="5" fill="#1f6feb" fill-opacity="0.12" stroke="#1f6feb"/>
<text x="356" y="464" fill="#79c0ff" font-size="13" font-weight="bold">15 × 3 = 45 Android</text>
<text x="356" y="482" fill="#7d8590" font-size="10.5">con RAM a 32 GB → 15 × 14 = 210</text>
<!-- Fabric A -->
<rect x="52" y="504" width="550" height="60" rx="6" fill="#1c2128" stroke="#a371f7" stroke-width="1.5"/>
<text x="68" y="526" fill="#a371f7" font-size="12" font-weight="bold">FABRIC A · ranuras A1 / A2 · Ethernet integrada (LOM) de cada blade</text>
<text x="68" y="546" fill="#7d8590" font-size="10.5">Conmutación interna entre blades, sin tarjetas intermedias. Hace posible macvlan.</text>
<text x="68" y="559" fill="#7d8590" font-size="10.5">Fabrics B y C (FC / InfiniBand) no se usan aquí.</text>
<!-- Flechas hacia el control -->
<path d="M 622 170 L 700 170" stroke="#d29922" stroke-width="2" fill="none" marker-end="url(#a)"/>
<path d="M 622 534 L 700 534" stroke="#a371f7" stroke-width="2" fill="none" marker-end="url(#p)"/>
<defs>
<marker id="a" markerWidth="9" markerHeight="9" refX="8" refY="4.5" orient="auto">
<path d="M0,0 L9,4.5 L0,9 z" fill="#d29922"/>
</marker>
<marker id="p" markerWidth="9" markerHeight="9" refX="8" refY="4.5" orient="auto">
<path d="M0,0 L9,4.5 L0,9 z" fill="#a371f7"/>
</marker>
</defs>
<!-- Panel derecho: control -->
<rect x="700" y="92" width="228" height="200" rx="8" fill="#161b22" stroke="#30363d" stroke-width="1.5"/>
<text x="716" y="118" fill="#e6edf3" font-size="13" font-weight="bold" font-family="system-ui, sans-serif">Nodo de control</text>
<text x="716" y="142" fill="#adbac7" font-size="11">Ansible (solo builtin)</text>
<text x="716" y="162" fill="#7d8590" font-size="10.5">preflight.yml → reconocer</text>
<text x="716" y="178" fill="#7d8590" font-size="10.5">site.yml → desplegar</text>
<text x="716" y="194" fill="#7d8590" font-size="10.5">apk.yml → instalar APK</text>
<text x="716" y="210" fill="#7d8590" font-size="10.5">status.yml → comprobar</text>
<text x="716" y="234" fill="#adbac7" font-size="11">SSH → los 16 blades</text>
<text x="716" y="256" fill="#7d8590" font-size="10.5">forks = 20: la flota entera</text>
<text x="716" y="272" fill="#7d8590" font-size="10.5">en paralelo</text>
<rect x="700" y="308" width="228" height="130" rx="8" fill="#161b22" stroke="#30363d" stroke-width="1.5"/>
<text x="716" y="332" fill="#e6edf3" font-size="13" font-weight="bold" font-family="system-ui, sans-serif">Control de flota</text>
<text x="716" y="356" fill="#79c0ff" font-size="11">fleet connect</text>
<text x="716" y="374" fill="#79c0ff" font-size="11">fleet list</text>
<text x="716" y="392" fill="#79c0ff" font-size="11">fleet install app.apk</text>
<text x="716" y="410" fill="#79c0ff" font-size="11">fleet shell '&lt;cmd&gt;'</text>
<text x="716" y="428" fill="#79c0ff" font-size="11">fleet ip</text>
<rect x="700" y="454" width="228" height="110" rx="8" fill="#161b22" stroke="#f85149" stroke-width="1.5"/>
<text x="716" y="478" fill="#f85149" font-size="12" font-weight="bold" font-family="system-ui, sans-serif">Sin móviles físicos</text>
<text x="716" y="500" fill="#7d8590" font-size="10.5">Cada dispositivo es un</text>
<text x="716" y="515" fill="#7d8590" font-size="10.5">contenedor redroid sobre</text>
<text x="716" y="530" fill="#7d8590" font-size="10.5">el kernel del blade.</text>
<text x="716" y="551" fill="#7d8590" font-size="10.5">Detectables como emulador.</text>
</svg>

After

Width:  |  Height:  |  Size: 7 KiB

106
assets/chasis.svg Normal file
View file

@ -0,0 +1,106 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 560" width="960" height="560" font-family="ui-monospace, 'DejaVu Sans Mono', Menlo, monospace">
<rect width="960" height="560" fill="#0f1720"/>
<text x="32" y="42" fill="#e6edf3" font-size="22" font-weight="bold" font-family="system-ui, sans-serif">Dell PowerEdge M1000e</text>
<text x="32" y="65" fill="#7d8590" font-size="12.5">Manual del propietario, modelo BMX01, rev. A06 (oct. 2019) · 44,0 × 44,7 × 75,5 cm · 10U · 200,5 kg cargado</text>
<!-- FRONTAL -->
<text x="32" y="102" fill="#58a6ff" font-size="14" font-weight="bold">PANEL FRONTAL — los blades</text>
<rect x="32" y="114" width="890" height="170" rx="8" fill="#161b22" stroke="#30363d" stroke-width="1.5"/>
<!-- fila superior -->
<g>
<rect x="52" y="134" width="82" height="60" rx="4" fill="#1c2128" stroke="#d29922" stroke-width="1.5"/>
<text x="86" y="170" fill="#d29922" font-size="15" font-weight="bold" text-anchor="middle">1</text>
<text x="86" y="186" fill="#7d8590" font-size="8.5" text-anchor="middle">coord.</text>
</g>
<g fill="#1c2128" stroke="#3fb950" stroke-width="1.2">
<rect x="142" y="134" width="82" height="60" rx="4"/>
<rect x="232" y="134" width="82" height="60" rx="4"/>
<rect x="322" y="134" width="82" height="60" rx="4"/>
<rect x="412" y="134" width="82" height="60" rx="4"/>
<rect x="502" y="134" width="82" height="60" rx="4"/>
<rect x="592" y="134" width="82" height="60" rx="4"/>
<rect x="682" y="134" width="82" height="60" rx="4"/>
</g>
<g fill="#adbac7" font-size="15" text-anchor="middle" font-weight="bold">
<text x="183" y="170">2</text><text x="273" y="170">3</text><text x="363" y="170">4</text>
<text x="453" y="170">5</text><text x="543" y="170">6</text><text x="633" y="170">7</text><text x="723" y="170">8</text>
</g>
<!-- fila inferior -->
<g fill="#1c2128" stroke="#3fb950" stroke-width="1.2">
<rect x="52" y="202" width="82" height="60" rx="4"/>
<rect x="142" y="202" width="82" height="60" rx="4"/>
<rect x="232" y="202" width="82" height="60" rx="4"/>
<rect x="322" y="202" width="82" height="60" rx="4"/>
<rect x="412" y="202" width="82" height="60" rx="4"/>
<rect x="502" y="202" width="82" height="60" rx="4"/>
<rect x="592" y="202" width="82" height="60" rx="4"/>
<rect x="682" y="202" width="82" height="60" rx="4"/>
</g>
<g fill="#adbac7" font-size="15" text-anchor="middle" font-weight="bold">
<text x="93" y="238">9</text><text x="183" y="238">10</text><text x="273" y="238">11</text><text x="363" y="238">12</text>
<text x="453" y="238">13</text><text x="543" y="238">14</text><text x="633" y="238">15</text><text x="723" y="238">16</text>
</g>
<!-- LCD -->
<rect x="790" y="134" width="112" height="128" rx="5" fill="#1c2128" stroke="#a371f7" stroke-width="1.5"/>
<text x="846" y="168" fill="#a371f7" font-size="12" font-weight="bold" text-anchor="middle">LCD</text>
<text x="846" y="190" fill="#7d8590" font-size="9.5" text-anchor="middle">panel control</text>
<text x="846" y="208" fill="#7d8590" font-size="9.5" text-anchor="middle">asistente config</text>
<text x="846" y="226" fill="#7d8590" font-size="9.5" text-anchor="middle">2 × USB</text>
<text x="846" y="244" fill="#7d8590" font-size="9.5" text-anchor="middle">VGA</text>
<text x="52" y="300" fill="#7d8590" font-size="11">16 blades de media altura — 8 arriba y 8 abajo. Toda bahía vacía necesita módulo de relleno o se degrada la refrigeración.</text>
<!-- POSTERIOR -->
<text x="32" y="342" fill="#58a6ff" font-size="14" font-weight="bold">PANEL POSTERIOR — infraestructura compartida</text>
<rect x="32" y="354" width="890" height="180" rx="8" fill="#161b22" stroke="#30363d" stroke-width="1.5"/>
<!-- ventiladores -->
<g fill="#1c2128" stroke="#f85149" stroke-width="1.2">
<rect x="52" y="372" width="86" height="34" rx="4"/><rect x="146" y="372" width="86" height="34" rx="4"/>
<rect x="240" y="372" width="86" height="34" rx="4"/><rect x="334" y="372" width="86" height="34" rx="4"/>
<rect x="428" y="372" width="86" height="34" rx="4"/><rect x="522" y="372" width="86" height="34" rx="4"/>
<rect x="616" y="372" width="86" height="34" rx="4"/><rect x="710" y="372" width="86" height="34" rx="4"/>
<rect x="804" y="372" width="86" height="34" rx="4"/>
</g>
<g fill="#f85149" font-size="10.5" text-anchor="middle">
<text x="95" y="394">VENT 1</text><text x="189" y="394">VENT 2</text><text x="283" y="394">VENT 3</text>
<text x="377" y="394">VENT 4</text><text x="471" y="394">VENT 5</text><text x="565" y="394">VENT 6</text>
<text x="659" y="394">VENT 7</text><text x="753" y="394">VENT 8</text><text x="847" y="394">VENT 9</text>
</g>
<!-- IO + CMC -->
<rect x="52" y="418" width="256" height="52" rx="5" fill="#1c2128" stroke="#a371f7" stroke-width="1.5"/>
<text x="180" y="440" fill="#a371f7" font-size="13" font-weight="bold" text-anchor="middle">A1 B1 C1</text>
<text x="180" y="459" fill="#7d8590" font-size="10" text-anchor="middle">módulos de I/O (izquierda)</text>
<rect x="320" y="418" width="150" height="52" rx="5" fill="#1c2128" stroke="#d29922" stroke-width="1.5"/>
<text x="395" y="437" fill="#d29922" font-size="11.5" font-weight="bold" text-anchor="middle">CMC 1 · iKVM</text>
<text x="395" y="455" fill="#d29922" font-size="11.5" font-weight="bold" text-anchor="middle">CMC 2</text>
<rect x="482" y="418" width="256" height="52" rx="5" fill="#1c2128" stroke="#a371f7" stroke-width="1.5"/>
<text x="610" y="440" fill="#a371f7" font-size="13" font-weight="bold" text-anchor="middle">C2 B2 A2</text>
<text x="610" y="459" fill="#7d8590" font-size="10" text-anchor="middle">módulos de I/O (derecha)</text>
<rect x="750" y="418" width="140" height="52" rx="5" fill="#1c2128" stroke="#444c56"/>
<text x="820" y="440" fill="#7d8590" font-size="10" text-anchor="middle">Fabric A → Ethernet</text>
<text x="820" y="456" fill="#7d8590" font-size="10" text-anchor="middle">B/C → FC · IB</text>
<!-- PSU -->
<g fill="#1c2128" stroke="#3fb950" stroke-width="1.2">
<rect x="52" y="482" width="132" height="34" rx="4"/><rect x="192" y="482" width="132" height="34" rx="4"/>
<rect x="332" y="482" width="132" height="34" rx="4"/><rect x="472" y="482" width="132" height="34" rx="4"/>
<rect x="612" y="482" width="132" height="34" rx="4"/><rect x="752" y="482" width="138" height="34" rx="4"/>
</g>
<g fill="#3fb950" font-size="10.5" text-anchor="middle">
<text x="118" y="504">PSU 1</text><text x="258" y="504">PSU 2</text><text x="398" y="504">PSU 3</text>
<text x="538" y="504">PSU 4</text><text x="678" y="504">PSU 5</text><text x="821" y="504">PSU 6</text>
</g>
<text x="32" y="550" fill="#f85149" font-size="11.5">Obligatorio por manual: las 6 fuentes y los 9 ventiladores instalados en todo momento — con 3 blades o con 16.</text>
</svg>

After

Width:  |  Height:  |  Size: 6.8 KiB

67
assets/red-modos.svg Normal file
View file

@ -0,0 +1,67 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 470" width="960" height="470" font-family="ui-monospace, 'DejaVu Sans Mono', Menlo, monospace">
<rect width="960" height="470" fill="#0f1720"/>
<text x="32" y="42" fill="#e6edf3" font-size="22" font-weight="bold" font-family="system-ui, sans-serif">Los dos modos de red</text>
<text x="32" y="65" fill="#7d8590" font-size="12.5">redroid_network_mode en group_vars/all.yml</text>
<!-- PORTMAP -->
<rect x="32" y="88" width="432" height="300" rx="8" fill="#161b22" stroke="#3fb950" stroke-width="1.5"/>
<text x="52" y="116" fill="#3fb950" font-size="15" font-weight="bold">portmap · por defecto</text>
<text x="52" y="136" fill="#7d8590" font-size="11">NAT de Docker. Funciona en cualquier sitio.</text>
<rect x="52" y="152" width="392" height="120" rx="5" fill="#1c2128" stroke="#444c56"/>
<text x="68" y="174" fill="#adbac7" font-size="11.5">blade-02 · 10.0.0.12</text>
<rect x="68" y="186" width="170" height="24" rx="3" fill="#1f6feb" fill-opacity="0.18" stroke="#1f6feb"/>
<text x="78" y="203" fill="#79c0ff" font-size="10.5">redroid-01 (interno)</text>
<rect x="68" y="214" width="170" height="24" rx="3" fill="#1f6feb" fill-opacity="0.18" stroke="#1f6feb"/>
<text x="78" y="231" fill="#79c0ff" font-size="10.5">redroid-02 (interno)</text>
<rect x="68" y="242" width="170" height="24" rx="3" fill="#1f6feb" fill-opacity="0.18" stroke="#1f6feb"/>
<text x="78" y="259" fill="#79c0ff" font-size="10.5">redroid-03 (interno)</text>
<g stroke="#3fb950" stroke-width="1.3" fill="none">
<path d="M 238 198 L 288 198"/><path d="M 238 226 L 288 226"/><path d="M 238 254 L 288 254"/>
</g>
<text x="296" y="202" fill="#adbac7" font-size="10.5">:5555</text>
<text x="296" y="230" fill="#adbac7" font-size="10.5">:5556</text>
<text x="296" y="258" fill="#adbac7" font-size="10.5">:5557</text>
<text x="296" y="180" fill="#7d8590" font-size="10">puertos del blade</text>
<text x="52" y="298" fill="#adbac7" font-size="11">adb → 10.0.0.12:5555, :5556, :5557</text>
<text x="52" y="320" fill="#3fb950" font-size="10.5">✓ No hace falta saber nada de la LAN</text>
<text x="52" y="336" fill="#3fb950" font-size="10.5">✓ redroid_adb_bind_ip limita la escucha</text>
<text x="52" y="356" fill="#d29922" font-size="10.5">✗ Los Android están tras NAT: no son</text>
<text x="52" y="371" fill="#d29922" font-size="10.5"> pares de red entre sí</text>
<!-- MACVLAN -->
<rect x="496" y="88" width="432" height="300" rx="8" fill="#161b22" stroke="#a371f7" stroke-width="1.5"/>
<text x="516" y="116" fill="#a371f7" font-size="15" font-weight="bold">macvlan · para oasis_mobile</text>
<text x="516" y="136" fill="#7d8590" font-size="11">IP real de LAN por el switch de Fabric A.</text>
<rect x="516" y="152" width="392" height="120" rx="5" fill="#1c2128" stroke="#444c56"/>
<text x="532" y="174" fill="#adbac7" font-size="11.5">blade-02 · 10.0.0.12</text>
<rect x="532" y="186" width="200" height="24" rx="3" fill="#a371f7" fill-opacity="0.18" stroke="#a371f7"/>
<text x="542" y="203" fill="#d2a8ff" font-size="10.5">redroid-01 → 10.0.0.20</text>
<rect x="532" y="214" width="200" height="24" rx="3" fill="#a371f7" fill-opacity="0.18" stroke="#a371f7"/>
<text x="542" y="231" fill="#d2a8ff" font-size="10.5">redroid-02 → 10.0.0.21</text>
<rect x="532" y="242" width="200" height="24" rx="3" fill="#a371f7" fill-opacity="0.18" stroke="#a371f7"/>
<text x="542" y="259" fill="#d2a8ff" font-size="10.5">redroid-03 → 10.0.0.22</text>
<g stroke="#a371f7" stroke-width="1.3" fill="none">
<path d="M 732 198 L 800 198"/><path d="M 732 226 L 800 226"/><path d="M 732 254 L 800 254"/>
</g>
<text x="808" y="230" fill="#adbac7" font-size="10.5">LAN</text>
<text x="790" y="180" fill="#7d8590" font-size="10">directo a la red</text>
<text x="516" y="298" fill="#adbac7" font-size="11">adb → 10.0.0.20:5555, .21:5555, .22:5555</text>
<text x="516" y="320" fill="#3fb950" font-size="10.5">✓ Los dos APKs se ven como pares reales</text>
<text x="516" y="336" fill="#3fb950" font-size="10.5">✓ Lo más cerca de "dos móviles en la misma wifi"</text>
<text x="516" y="356" fill="#f85149" font-size="10.5">✗ El anfitrión NO habla con sus propios</text>
<text x="516" y="371" fill="#f85149" font-size="10.5"> contenedores macvlan → coordinador aparte</text>
<!-- Aviso -->
<rect x="32" y="404" width="896" height="48" rx="6" fill="#161b22" stroke="#f85149" stroke-width="1.5"/>
<text x="52" y="424" fill="#f85149" font-size="11.5" font-weight="bold">S1 · adb no tiene autenticación y los contenedores son privilegiados</text>
<text x="52" y="442" fill="#7d8590" font-size="10.5">Quien alcance el puerto 5555 acaba siendo root en el blade. En macvlan, bind_ip no aplica: la única defensa es una VLAN aislada.</text>
</svg>

After

Width:  |  Height:  |  Size: 4.8 KiB

61
assets/stack-software.svg Normal file
View file

@ -0,0 +1,61 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 520" width="960" height="520" font-family="ui-monospace, 'DejaVu Sans Mono', Menlo, monospace">
<rect width="960" height="520" fill="#0f1720"/>
<text x="32" y="42" fill="#e6edf3" font-size="22" font-weight="bold" font-family="system-ui, sans-serif">Stack de software</text>
<text x="32" y="65" fill="#7d8590" font-size="12.5">Todo software libre. Sin colecciones externas de Ansible, sin dependencias de pago.</text>
<!-- Capas -->
<rect x="32" y="88" width="560" height="58" rx="6" fill="#1f6feb" fill-opacity="0.18" stroke="#1f6feb" stroke-width="1.5"/>
<text x="52" y="114" fill="#79c0ff" font-size="15" font-weight="bold">redroid 13</text>
<text x="52" y="134" fill="#adbac7" font-size="11">Android 13 en contenedor · memfd (sin ashmem) · ~2 GB por instancia</text>
<rect x="32" y="154" width="560" height="52" rx="6" fill="#1c2128" stroke="#444c56" stroke-width="1.5"/>
<text x="52" y="180" fill="#e6edf3" font-size="15" font-weight="bold">Docker CE + Compose v2</text>
<text x="52" y="198" fill="#7d8590" font-size="11">Repo oficial de Docker · compose generado por plantilla Jinja</text>
<rect x="32" y="214" width="560" height="66" rx="6" fill="#1c2128" stroke="#f85149" stroke-width="1.5"/>
<text x="52" y="240" fill="#f85149" font-size="15" font-weight="bold">binder_linux</text>
<text x="52" y="258" fill="#adbac7" font-size="11">devices: binder, hwbinder, vndbinder</text>
<text x="52" y="273" fill="#7d8590" font-size="10.5">Debian trae el módulo pero SIN binderfs → hay que cargarlos a mano. Aquí es donde esto se atasca.</text>
<rect x="32" y="288" width="560" height="52" rx="6" fill="#1c2128" stroke="#a371f7" stroke-width="1.5"/>
<text x="52" y="314" fill="#a371f7" font-size="15" font-weight="bold">Debian 12 bookworm</text>
<text x="52" y="332" fill="#7d8590" font-size="11">Directo sobre el blade. Sin Proxmox, sin VM, sin LXC anidado.</text>
<rect x="32" y="348" width="560" height="52" rx="6" fill="#1c2128" stroke="#3fb950" stroke-width="1.5"/>
<text x="52" y="374" fill="#3fb950" font-size="15" font-weight="bold">Blade Dell · Fabric A</text>
<text x="52" y="392" fill="#7d8590" font-size="11">Ethernet integrada (LOM) → ranuras A1 / A2 del chasis</text>
<!-- Llave lateral -->
<path d="M 604 88 L 616 88 L 616 400 L 604 400" stroke="#30363d" stroke-width="1.5" fill="none"/>
<text x="628" y="238" fill="#7d8590" font-size="11">×15 nodos</text>
<text x="628" y="254" fill="#7d8590" font-size="11">de carga</text>
<!-- Panel derecho: orquestación -->
<rect x="712" y="88" width="216" height="312" rx="8" fill="#161b22" stroke="#d29922" stroke-width="1.5"/>
<text x="730" y="114" fill="#d29922" font-size="14" font-weight="bold" font-family="system-ui, sans-serif">Orquestación</text>
<text x="730" y="142" fill="#e6edf3" font-size="12" font-weight="bold">Ansible</text>
<text x="730" y="160" fill="#7d8590" font-size="10.5">solo ansible.builtin</text>
<text x="730" y="176" fill="#7d8590" font-size="10.5">6 roles · 7 playbooks</text>
<text x="730" y="204" fill="#e6edf3" font-size="12" font-weight="bold">adb sobre TCP</text>
<text x="730" y="222" fill="#7d8590" font-size="10.5">del coordinador a</text>
<text x="730" y="237" fill="#7d8590" font-size="10.5">toda la flota</text>
<text x="730" y="265" fill="#e6edf3" font-size="12" font-weight="bold">fleet.sh</text>
<text x="730" y="283" fill="#7d8590" font-size="10.5">connect · list · install</text>
<text x="730" y="298" fill="#7d8590" font-size="10.5">shell · ip · reboot</text>
<text x="730" y="326" fill="#e6edf3" font-size="12" font-weight="bold">scrcpy</text>
<text x="730" y="344" fill="#7d8590" font-size="10.5">ver y tocar una</text>
<text x="730" y="359" fill="#7d8590" font-size="10.5">instancia concreta</text>
<text x="730" y="386" fill="#484f58" font-size="10.5">GADS · Appium (pendiente)</text>
<!-- Nota inferior -->
<rect x="32" y="418" width="896" height="70" rx="6" fill="#161b22" stroke="#30363d"/>
<text x="52" y="442" fill="#e6edf3" font-size="12" font-weight="bold">Lo que este stack NO puede hacer</text>
<text x="52" y="462" fill="#7d8590" font-size="11">Ninguna instancia pasa la atestación por hardware: no hay TEE, ni arranque verificado, ni banda base, ni clave de fábrica.</text>
<text x="52" y="478" fill="#7d8590" font-size="11">Sirve para probar tus propias apps. Para plataformas con atestación, no — y no es cuestión de potencia. Ver capa_identidad.md</text>
</svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

View file

@ -1,25 +1,23 @@
# Docs # Docs
Lo que hay que leer antes de encender nada.
| | | | | |
|---|---| |---|---|
| **[requisitos.md](requisitos.md)** | Qué hace falta: eléctrico, físico, hardware, software, red, accesos y tiempo. Con checklist de bloqueantes. | | [requisitos.md](requisitos.md) | Eléctrico, físico, hardware, red, accesos y tiempo. Checklist de bloqueantes |
| **[costes.md](costes.md)** | Lo que cuesta tenerlo en marcha, por escenario y por dispositivo. La luz es el coste real del proyecto. | | [costes.md](costes.md) | Consumo y coste por escenario y por dispositivo |
| **[seguridad.md](seguridad.md)** | Repaso de seguridad con 11 hallazgos, incluidos los que introduce el código de este proyecto. | | [seguridad.md](seguridad.md) | 11 hallazgos, incluidos los que introduce el código de este proyecto |
| [usabilidad.md](usabilidad.md) | Cómo se opera la flota una vez montada |
## Las tres conclusiones, en corto ## Resumen
**Requisitos** — el bloqueante no es técnico: el chasis pide 2,63,6 kW, más de lo que tiene **Requisitos.** El bloqueante no es técnico. El chasis pide 2,63,6 kW —más de lo que tiene
contratado una vivienda española, y hace 7085 dB. Sin un sitio con potencia, extracción y contratado una vivienda española—, hace 7085 dB y su techo térmico continuo son 35 °C. El manual
tolerancia al ruido, la vía es el piloto en el sobremesa. obliga además a las seis fuentes y los nueve ventiladores, se usen 3 blades o 16.
**Costes** — la granja completa 24/7 son **~340 €/mes**, unos 4.100 € al año: entre tres y ocho **Costes.** La granja completa 24/7 son ~360 €/mes, unos 4.300 € al año: más de lo que vale el
veces lo que vale el hierro de segunda mano. Encendida **por ventanas** baja a ~56 €/mes. Y con hierro de segunda mano. Por ventanas de 4 h/día baja a ~59 €/mes. Con 8 GB por blade el sobremesa
8 GB por blade, el sobremesa sale más barato por dispositivo que el chasis; solo la ampliación de sale más barato por dispositivo que el chasis; solo la ampliación de RAM invierte eso.
RAM invierte eso.
**Seguridad** — hay un hallazgo **crítico**: adb no tiene autenticación y los contenedores son **Seguridad.** Un hallazgo crítico: adb no tiene autenticación y los contenedores son
privilegiados, así que quien alcance el puerto 5555 de un blade acaba siendo root en él. Se ha privilegiados, así que quien alcance el puerto 5555 de un blade acaba siendo root en él. Mitigado a
mitigado a medias en el código (`redroid_adb_bind_ip`); lo que lo cierra de verdad es una **VLAN medias con `redroid_adb_bind_ip`; lo cierra una VLAN aislada. Antes de eso, cambiar las
aislada**. Y antes de eso, cambiar las credenciales de fábrica del CMC y de los 16 iDRAC. credenciales de fábrica del CMC y de los 16 iDRAC.

View file

@ -3,8 +3,8 @@
El hardware ya está. El coste real de este proyecto es **la luz**, y no es pequeño. El hardware ya está. El coste real de este proyecto es **la luz**, y no es pequeño.
> **Todas las cifras de consumo son estimaciones.** El M1000e reporta consumo real por chasis y por > **Todas las cifras de consumo son estimaciones.** El M1000e reporta consumo real por chasis y por
> blade desde el CMC — antes de comprometerse con nada, hay que mirar ahí. Es media hora de trabajo > blade desde el CMC (*Chassis → Power Management*) — antes de comprometerse con nada, hay que
> y sustituye todo este documento por datos. > mirar ahí. Es media hora de trabajo y sustituye todo este documento por datos.
--- ---
@ -12,12 +12,28 @@ El hardware ya está. El coste real de este proyecto es **la luz**, y no es pequ
| | | | | |
|---|---| |---|---|
| Consumo fijo del chasis | 350 W (ventiladores, CMC, switches, pérdidas de las fuentes) — rango 250500 W | | **Consumo fijo del chasis** | **500 W** — rango 350700 W |
| Consumo por blade con Android en marcha | 140 W — rango 100200 W | | Consumo por blade con Android en marcha | 140 W — rango 100200 W |
| Precio de la electricidad | **0,18 €/kWh** — rango 0,150,22 según tarifa y tramo | | Precio de la electricidad | **0,18 €/kWh** — rango 0,150,22 según tarifa y tramo |
| Horas al mes | 730 | | Horas al mes | 730 |
| Reparto | 1 blade coordinador + N de carga × 3 instancias | | Reparto | 1 blade coordinador + N de carga × 3 instancias |
### De dónde sale el consumo fijo
El manual del M1000e obliga a tener **las seis fuentes y los nueve ventiladores instalados en todo
momento**, se use un blade o dieciséis. Ese suelo lo componen:
- **9 módulos de ventilador**, con clasificación de 12 V a 5,06,3 A cada uno. A régimen moderado,
del orden de 150250 W en conjunto; a plena velocidad, mucho más
- **Módulos de I/O** — un switch de fabric consume del orden de 50150 W, y hay al menos uno
- **CMC** (una o dos) e iKVM
- **Pérdidas de conversión de las seis fuentes** — el manual da 353 W de disipación máxima por
fuente de 2.700 W
Si los blades resultan ser **M630 y el sitio pasa de 30 °C**, el manual exige activar **ECM**
(modo de refrigeración mejorado), que sube el caudal de los ventiladores — y con él, el consumo y
el ruido. Ese caso se iría al extremo alto del rango.
--- ---
## Coste mensual por escenario, 24/7 ## Coste mensual por escenario, 24/7
@ -25,43 +41,45 @@ El hardware ya está. El coste real de este proyecto es **la luz**, y no es pequ
| Escenario | Blades | Potencia | kWh/mes | **€/mes** | Android | **€/Android/mes** | | Escenario | Blades | Potencia | kWh/mes | **€/mes** | Android | **€/Android/mes** |
|---|---|---|---|---|---|---| |---|---|---|---|---|---|---|
| Solo sobremesa, chasis apagado | 0 | 150 W | 110 | **20 €** | 8 | **2,5 €** | | Solo sobremesa, chasis apagado | 0 | 150 W | 110 | **20 €** | 8 | **2,5 €** |
| Piloto en el chasis | 3 | 770 W | 562 | **101 €** | 6 | **16,9 €** | | Piloto en el chasis | 3 | 920 W | 672 | **121 €** | 6 | **20,2 €** |
| Media granja | 8 | 1.470 W | 1.073 | **193 €** | 21 | **9,2 €** | | Media granja | 8 | 1.620 W | 1.183 | **213 €** | 21 | **10,1 €** |
| Granja completa | 16 | 2.590 W | 1.891 | **340 €** | 45 | **7,6 €** | | Granja completa | 16 | 2.740 W | 2.000 | **360 €** | 45 | **8,0 €** |
| Completa + RAM a 32 GB | 16 | 2.750 W | 2.008 | **361 €** | **210** | **1,7 €** | | Completa + RAM a 32 GB | 16 | 2.900 W | 2.117 | **381 €** | **210** | **1,8 €** |
Granja completa 24/7: **~4.100 €/año**. Granja completa 24/7: **~4.300 €/año**.
### Tres cosas que dice esta tabla Tres lecturas:
**El sobremesa gana al chasis por dispositivo — hasta que se amplíe la RAM.** 2,5 €/Android en el - **El sobremesa gana al chasis por dispositivo** hasta que se amplíe la RAM: 2,5 € contra 8,0 €.
sobremesa contra 7,6 € en el chasis completo. Con 8 GB por blade, encender el M1000e para hacer lo Con 8 GB por blade, encender el M1000e para hacer lo que ya hace el sobremesa es pagar tres veces
que ya hace el sobremesa es pagar tres veces más por dispositivo. más por dispositivo.
- **Los pilotos parciales son el peor caso.** El manual obliga a las seis fuentes y los nueve
**Los pilotos en el chasis son el peor negocio de todos.** Los 350 W fijos se pagan igual con 3 ventiladores estén los blades que estén, así que el suelo de ~500 W se paga con 3 blades igual
blades que con 16, así que el piloto sale a 16,9 € por Android — casi siete veces el sobremesa. Si que con 16: el piloto sale a 20 € por Android. Si se enciende el chasis, se enciende entero; para
se enciende el chasis, se enciende entero; y para probar, se usa el sobremesa. probar se usa el sobremesa.
- **La ampliación de RAM es lo único que cambia la ecuación**: de 8,0 € a 1,8 € por Android con
**La ampliación de RAM es lo único que cambia la ecuación.** De 7,6 € a 1,7 € por Android, por el prácticamente el mismo recibo. No ahorra dinero, multiplica por 4,4 lo que se obtiene por el que
mismo recibo de la luz. No ahorra dinero: multiplica por 4,7 lo que se obtiene por el dinero que ya ya se gasta.
se está gastando.
--- ---
## El modo que sí sale a cuenta: encendido bajo demanda ## El modo que sí sale a cuenta: encendido bajo demanda
El CMC permite encender y apagar blades individualmente. Un laboratorio de QA no necesita 45 La CMC permite encender y apagar blades individualmente y fijar presupuesto de alimentación. Un
Android a las cuatro de la mañana. laboratorio de QA no necesita 45 Android a las cuatro de la mañana.
| Uso | Potencia | kWh/mes | €/mes | €/Android/mes | | Uso | kWh/mes | €/mes | €/Android/mes |
|---|---|---|---|---| |---|---|---|---|
| 24/7 | 2.590 W | 1.891 | 340 € | 7,6 € | | 24/7 | 2.000 | 360 € | 8,0 € |
| **4 h/día** | 2.590 W | 311 | **56 €** | **1,2 €** | | **4 h/día** | 329 | **59 €** | **1,3 €** |
| 8 h/día laborables | 2.590 W | 456 | 82 € | 1,8 € | | 8 h/día laborables | 482 | 87 € | 1,9 € |
**Ventanas de prueba en vez de servicio permanente**: el coste cae seis veces y el proyecto pasa de **Ventanas de prueba en vez de servicio permanente**: el coste cae seis veces y el proyecto pasa de
inviable a trivial. Es como debería operarse esto salvo que aparezca una razón para lo contrario. inviable a trivial. Es como debería operarse esto salvo que aparezca una razón para lo contrario.
Ojo: apagar blades **no ahorra el suelo de ~500 W** si el chasis sigue encendido. El ahorro de
verdad es apagar el chasis entero entre ventanas.
--- ---
## Costes de una vez ## Costes de una vez
@ -69,10 +87,12 @@ inviable a trivial. Es como debería operarse esto salvo que aparezca una razón
| Concepto | Coste | Notas | | Concepto | Coste | Notas |
|---|---|---| |---|---|---|
| **RAM 8 → 32 GB × 16 blades** | **320640 €** | Si son M620 (DDR3 ECC): ~1020 € el módulo de 16 GB de segunda mano, 2 por blade. Si son M630 (DDR4): 8001.300 € | | **RAM 8 → 32 GB × 16 blades** | **320640 €** | Si son M620 (DDR3 ECC): ~1020 € el módulo de 16 GB de segunda mano, 2 por blade. Si son M630 (DDR4): 8001.300 € |
| **PDU con 6 tomas C19** | 80250 € | Las fuentes usan **CEI/IEC C20**; los C13 domésticos no valen |
| **Magnetotérmico de curva D** | 2060 € | La irrupción es de **55 A por fuente durante 10 ms**; una curva C salta |
| Módulos de relleno para bahías vacías | 515 €/ud. | Obligatorios según el manual. Si faltan, se compran |
| SSD por blade, si faltan | ~400 € | 16 × ~25 € | | SSD por blade, si faltan | ~400 € | 16 × ~25 € |
| PDU con tomas C19 + cableado | 50150 € | Las fuentes del M1000e no usan C13 |
| Subida de potencia contratada | 1050 € | Derecho de cambio, una vez | | Subida de potencia contratada | 1050 € | Derecho de cambio, una vez |
| **Total realista** | **~4001.200 €** | Sin contar los SSD si los blades ya tienen disco | | **Total realista** | **~4501.400 €** | Sin contar los SSD si los blades ya tienen disco |
Coste fijo adicional: subir de 3,45 a 6,9 kW contratados añade **~130 €/año** solo en término de Coste fijo adicional: subir de 3,45 a 6,9 kW contratados añade **~130 €/año** solo en término de
potencia, se use o no. potencia, se use o no.
@ -83,26 +103,23 @@ potencia, se use o no.
| Opción | Coste | Cuándo tiene sentido | | Opción | Coste | Cuándo tiene sentido |
|---|---|---| |---|---|---|
| **Sobremesa, 8 Android** | ~20 €/mes | Desarrollo diario y pruebas de `oasis_mobile`. Silencioso, ya encendido. | | **Sobremesa, 8 Android** | ~20 €/mes | Desarrollo diario y pruebas de `oasis_mobile`. Silencioso, ya encendido |
| **Chasis bajo demanda, 45 Android** | ~56 €/mes + 4001.200 € de entrada | Matrices de prueba grandes, escenarios multi-dispositivo | | **Chasis bajo demanda, 45 Android** | ~59 €/mes + 4501.400 € de entrada | Matrices de prueba grandes, escenarios multi-dispositivo |
| **Chasis 24/7, 45 Android** | ~340 €/mes | Solo si algo tiene que estar servido permanentemente | | **Chasis 24/7, 45 Android** | ~360 €/mes | Solo si algo tiene que estar servido permanentemente |
| **Device farm en la nube** | ~0,09 €/dispositivo-hora | Uso esporádico. 45 dispositivos 24/7 saldrían por ~2.950 €/mes: diez veces el chasis | | **Device farm en la nube** | ~0,09 €/dispositivo-hora | Uso esporádico. 45 dispositivos 24/7 saldrían por ~2.950 €/mes: ocho veces el chasis |
| **Teléfonos físicos tipo GenFarmer** | 3961.364 $/dispositivo | Otro producto: son los únicos que pasan atestación de hardware. 45 dispositivos = 17.80061.400 $ | | **Teléfonos físicos tipo GenFarmer** | 3961.364 $/dispositivo | Otro producto: son los únicos que pasan atestación de hardware. 45 dispositivos = 17.80061.400 $ |
**El punto de equilibrio con la nube** está en torno al **11 % de utilización**: si cada dispositivo **El punto de equilibrio con la nube** está en torno al **12 % de utilización**: si cada dispositivo
se usa más de ~84 horas al mes, el chasis 24/7 sale más barato. Por debajo, la nube gana. Y por se usa más de ~89 horas al mes, el chasis 24/7 sale más barato. Por debajo, la nube gana. Y por
debajo del 11 %, lo que gana de verdad es encender el chasis solo cuando haga falta. debajo de eso, lo que gana de verdad es encender el chasis solo cuando haga falta.
--- ---
## El dato incómodo ## Hierro contra electricidad
Un M1000e con 16 blades vale hoy de segunda mano entre **500 y 1.500 €**. Un M1000e con 16 blades vale hoy de segunda mano entre 500 y 1.500 €. Tenerlo encendido 24/7
durante un año cuesta unos 4.300 € de luz: entre tres y nueve veces lo que vale el hardware. No es
Tenerlo encendido 24/7 durante un año cuesta **~4.100 € de luz**. argumento para tirarlo, sino para no dejarlo encendido por defecto.
**La electricidad de un año cuesta entre tres y ocho veces lo que vale el hierro.** Eso no es un
argumento para tirarlo — es un argumento para no dejarlo encendido por defecto.
--- ---
@ -113,7 +130,8 @@ argumento para tirarlo — es un argumento para no dejarlo encendido por defecto
ruido. Ver [ansible/README.md](../02_device_lab/ansible/README.md). ruido. Ver [ansible/README.md](../02_device_lab/ansible/README.md).
3. **Encender el chasis solo con un caso concreto que el sobremesa no cubra** — matriz de versiones 3. **Encender el chasis solo con un caso concreto que el sobremesa no cubra** — matriz de versiones
de Android, o el escenario multi-dispositivo de los dos APKs a escala real. de Android, o el escenario multi-dispositivo de los dos APKs a escala real.
4. **Si se enciende, encenderlo entero y por ventanas.** Los 350 W fijos hacen que los pilotos 4. **Si se enciende, encenderlo entero y por ventanas.** Las seis fuentes y los nueve ventiladores
parciales sean el peor negocio. son obligatorios por manual: el suelo de ~500 W hace que los pilotos parciales sean el peor
5. **La RAM antes que nada más.** 400 € que multiplican por 4,7 la capacidad sin tocar el recibo. negocio posible.
5. **La RAM antes que nada más.** ~400 € que multiplican por 4,4 la capacidad sin tocar el recibo.
Pero primero hay que saber qué blades son — lo dice `playbooks/preflight.yml`. Pero primero hay que saber qué blades son — lo dice `playbooks/preflight.yml`.

View file

@ -5,21 +5,44 @@ es lo que descarta el proyecto antes que ninguna consideración técnica.
--- ---
## 1 · Eléctrico y físico — lee esto primero ## 1 · Eléctrico y físico
Datos del *Manual del propietario del M1000e* (Dell, rev. A06, oct. 2019).
| Requisito | Detalle | | Requisito | Detalle |
|---|---| |---|---|
| **Potencia contratada** | El chasis completo tira **2,63,6 kW**. Un domicilio español típico tiene **3,45 kW contratados**: no da. Hace falta subir a 6,9 kW o más, o un local con suministro trifásico. | | **Potencia contratada** | El chasis completo tira **2,63,6 kW**. Un domicilio español típico tiene **3,45 kW contratados**: no da. Hace falta subir a 6,9 kW o más, o un local con suministro trifásico. |
| **Fuentes** | **Seis, obligatorias.** El manual: *«El sistema requiere seis fuentes de alimentación para su funcionamiento habitual.»* No es opcional ni escalable. |
| **Tensión** | Fuente de 3.000 W: **200240 V CA, 16 A**. Fuente de 2.700 W: 100240 V, 16 A. España a 230 V vale. |
| **Conectores** | **CEI/IEC C20** — hace falta una **PDU con 6 tomas C19**. Los C13 domésticos no valen. |
| **Corriente de irrupción** | **55 A por fuente durante ≤10 ms.** Con seis arrancando a la vez, un magnetotérmico de **curva C salta**: hace falta **curva D** o arranque escalonado. |
| **Circuito** | Dedicado. Nada de compartir con el resto de la instalación. | | **Circuito** | Dedicado. Nada de compartir con el resto de la instalación. |
| **Tensión y conectores** | Dell recomienda **208240 V** para el M1000e. España a 230 V vale. Fuentes con conectores **C19/C20**, no los C13 normales. | | **Espacio** | **10U** de rack (44,0 × 44,7 × 75,5 cm) |
| **Espacio** | **10U** de rack, con raíles capaces de aguantar el peso. | | **Peso** | **200,5 kg cargado** (44,6 kg vacío). Dato del manual — el spec sheet comercial decía 179 kg y se queda corto. Raíles y suelo tienen que ir sobrados. |
| **Peso** | **179 kg cargado.** El rack tiene que soportarlo y el suelo también. | | **Temperatura** | **10 °C a 35 °C en continuo.** Ampliado a 40 °C solo <10 % de las horas del año, y a 45 °C solo <1 %. |
| **Refrigeración** | 2,6 kW de consumo son 2,6 kW de calor: como dos radiadores eléctricos a tope. Necesita extracción real, no una ventana. | | **Refrigeración** | **Nueve módulos de ventilador, obligatorios los nueve.** 2,6 kW de consumo son 2,6 kW de calor: como dos radiadores eléctricos a tope. Extracción real, no una ventana. |
| **Ruido** | 7085 dB con los 9 ventiladores en marcha. **No es una máquina de vivienda.** | | **Bahías vacías** | **Todas tapadas con módulo de relleno.** Sin ellos el aire se escapa por el hueco y se degrada la refrigeración del resto. |
| **Ruido** | 7085 dB con los 9 ventiladores. **No es una máquina de vivienda.** |
> **Esto es lo que decide.** Si no hay sitio con potencia, extracción y tolerancia al ruido, el > **Esto es lo que decide.** Si no hay sitio con potencia, extracción y tolerancia al ruido, el
> resto de este documento no importa: la vía es el piloto en el sobremesa. > resto de este documento no importa: la vía es el piloto en el sobremesa.
### Consecuencias
**Seis fuentes y nueve ventiladores, siempre.** No se puede arrancar el chasis a medias para
"probar con tres blades": el coste fijo se paga igual. O entero, o nada — y para probar está el
sobremesa.
**35 °C es el techo continuo.** Una habitación en Madrid en agosto, con 2,6 kW de calor dentro y
sin climatización, se pasa de ahí sin dificultad. El rango ampliado cubre menos del 10 % de las
horas del año: es margen para incidencias, no una solución.
### ECM — modo de refrigeración mejorado
El manual lo exige si los blades son **M630 con CPUs de 120 W o más**, o si el entorno pasa de
**30 °C**. Requiere los nueve ventiladores de tercera generación, y significa **más consumo y más
ruido**. Depende del modelo de blade, que aún no está confirmado.
--- ---
## 2 · Hardware ## 2 · Hardware
@ -29,10 +52,16 @@ es lo que descarta el proyecto antes que ninguna consideración técnica.
Dell PowerEdge M1000e — ver [hardware_m1000e.md](../02_device_lab/hardware_m1000e.md). Dell PowerEdge M1000e — ver [hardware_m1000e.md](../02_device_lab/hardware_m1000e.md).
- 16 blades de media altura (8 arriba + 8 abajo) - 16 blades de media altura (8 arriba + 8 abajo)
- Al menos 2 fuentes (mejor 3+3 en redundancia) - **Las 6 fuentes** y **los 9 ventiladores**, más rellenos en toda bahía vacía
- Módulos de I/O FlexIO con conectividad entre blades y hacia la LAN - **Un módulo de I/O en A1** como mínimo (A1 + A2 para redundancia). Fabric A es la Ethernet
integrada de los blades, así que **no hacen falta tarjetas intermedias**
- CMC accesible - CMC accesible
> **Ojo con qué módulo hay en A1/A2.** Un módulo **switch** (M6220, M6348, MXL, M8024-k…) conmuta
> entre blades dentro del chasis, que es justo lo que necesita el modo `macvlan`. Un módulo de
> **paso a través** saca 16 RJ-45 al exterior y deja la conmutación en manos de un switch externo.
> Cambia el montaje de red por completo.
### Por blade ### Por blade
| | Mínimo | Recomendado | | | Mínimo | Recomendado |
@ -124,9 +153,12 @@ Mantenimiento posterior: 24 h al mes.
**Bloqueantes** — si alguno falla, el proyecto no sale: **Bloqueantes** — si alguno falla, el proyecto no sale:
- [ ] Sitio con potencia suficiente, extracción y tolerancia al ruido - [ ] Sitio con potencia suficiente, extracción y **temperatura por debajo de 35 °C todo el año**
- [ ] Tolerancia a 7085 dB
- [ ] Alguien asume la factura eléctrica (ver [costes.md](costes.md)) - [ ] Alguien asume la factura eléctrica (ver [costes.md](costes.md))
- [ ] Rack de 10U que aguante 179 kg - [ ] Rack de 10U que aguante **200,5 kg**
- [ ] **PDU con 6 tomas C19** y magnetotérmico de **curva D** (irrupción de 55 A por fuente)
- [ ] Las 6 fuentes, los 9 ventiladores y los rellenos, presentes
- [ ] Los blades arrancan y el CMC responde - [ ] Los blades arrancan y el CMC responde
**Antes de encender**: **Antes de encender**:

View file

@ -25,7 +25,7 @@ Incluye los fallos que introduce el propio código de este proyecto, no solo los
## S1 · adb sin autenticación sobre contenedor privilegiado — **crítico** ## S1 · adb sin autenticación sobre contenedor privilegiado — **crítico**
El fallo más serio, y es una cadena de tres eslabones que por separado parecen asumibles: Una cadena de tres eslabones que por separado parecen asumibles:
1. **adb no tiene autenticación** cuando escucha en TCP. Quien llega al puerto, entra. 1. **adb no tiene autenticación** cuando escucha en TCP. Quien llega al puerto, entra.
2. **Las imágenes de redroid son `userdebug`**, así que `adb root` funciona: shell de root dentro 2. **Las imágenes de redroid son `userdebug`**, así que `adb root` funciona: shell de root dentro
@ -33,19 +33,17 @@ El fallo más serio, y es una cadena de tres eslabones que por separado parecen
3. **El contenedor es `privileged: true`** — redroid lo exige para acceder a binder. Un privilegiado 3. **El contenedor es `privileged: true`** — redroid lo exige para acceder a binder. Un privilegiado
ve los devices del anfitrión y puede montar su sistema de ficheros. ve los devices del anfitrión y puede montar su sistema de ficheros.
Encadenado: **cualquiera que alcance el puerto 5555 de un blade acaba siendo root en ese blade.** Encadenado: cualquiera que alcance el puerto 5555 de un blade acaba siendo root en ese blade, sin
No hace falta ningún exploit, solo `adb connect`. exploit, solo con `adb connect`. Con 45 dispositivos son 45 puertas.
Y con 45 dispositivos son 45 puertas. Corregido en parte: el compose ataba adb a `0.0.0.0`. Ahora hay `redroid_adb_bind_ip`, que permite
atarlo solo a la interfaz interna del chasis:
**Qué se ha corregido hoy.** El compose ataba adb a `0.0.0.0` — todas las interfaces. Ahora hay
`redroid_adb_bind_ip`, así que se puede atar solo a la interfaz interna del chasis:
```yaml ```yaml
blade-02: { ansible_host: 10.0.0.12, redroid_adb_bind_ip: 10.0.0.12 } blade-02: { ansible_host: 10.0.0.12, redroid_adb_bind_ip: 10.0.0.12 }
``` ```
**Qué falta, y es lo que de verdad cierra el agujero:** **Lo que cierra el agujero:**
- **Red de laboratorio aislada.** VLAN propia para la granja, sin ruta hacia la LAN de casa ni - **Red de laboratorio aislada.** VLAN propia para la granja, sin ruta hacia la LAN de casa ni
hacia internet salvo lo imprescindible. Es la medida que importa; el resto son parches. hacia internet salvo lo imprescindible. Es la medida que importa; el resto son parches.
@ -84,7 +82,7 @@ cada Android **con IP real en la red**, cada uno con S1 encima.
- VLAN dedicada para la granja, con el coordinador como único puente. - VLAN dedicada para la granja, con el coordinador como único puente.
- Reservar el rango de IPs en el DHCP, o habrá colisiones con máquinas reales. - Reservar el rango de IPs en el DHCP, o habrá colisiones con máquinas reales.
- No usar la LAN de casa. Nunca. - No usar la LAN doméstica.
--- ---

168
docs/usabilidad.md Normal file
View file

@ -0,0 +1,168 @@
# Usabilidad
Cómo se trabaja con esto en el día a día. No la instalación —eso está en
[ansible/README.md](../02_device_lab/ansible/README.md)— sino **cómo se usa una vez montado**, y
qué decisiones de diseño hacen que sea llevadero o insufrible.
---
## Un solo punto de control
45 dispositivos son ingobernables si hay que entrar a cada blade. Por eso **todo pasa por el
coordinador**:
```
tú coordinador 45 Android
┌────┐ ssh ┌──────────────────┐ adb ┌───┬───┬───┐
│ │ ──────────► │ fleet · adb │ ─────────► │ · │ · │ · │
└────┘ │ devices.txt │ └───┴───┴───┘
└──────────────────┘
```
`devices.txt` lo genera Ansible a partir del inventario y de la RAM real de cada blade. Nunca se
edita a mano: si cambia la flota, se relanza `playbooks/coordinator.yml` y se regenera.
---
## Órdenes
```bash
fleet connect # conecta adb a toda la flota
fleet list # qué hay conectado, y cuántos faltan
fleet install app.apk # instala en todos
fleet shell '<cmd>' # ejecuta en todos
fleet ip # IP de cada Android
fleet reboot # reinicia todo
```
Todas son **idempotentes o inocuas**. `connect` se puede lanzar mil veces. Ninguna borra nada.
La única destructiva del proyecto es `playbooks/destroy.yml`, y exige `-e confirmar=si`.
### Por qué `fleet list` dice "declarados" y "conectados"
```
declarados: 45 · conectados: 43
```
Esa resta es el diagnóstico más útil del sistema. Si no cuadra, hay dos contenedores caídos y se
sabe al instante, sin mirar 15 blades. El siguiente paso es `playbooks/status.yml`, que dice en
qué nodo.
---
## Flujos de trabajo reales
### Probar una APK nueva en toda la flota
```bash
ansible-playbook playbooks/apk.yml -e apk_local_path=~/oasis-0.9.1.apk
```
Un solo comando desde el portátil: copia el APK al coordinador, conecta la flota e instala en los
45. Sale un recuento de `ok` / `FALLO` por dispositivo.
### El caso de los dos APKs que se tienen que ver
Es el que motivó el proyecto. Con `redroid_network_mode: macvlan`:
```bash
fleet ip # cada Android con su IP real de LAN
fleet install oasis-A.apk # ...o instalar distinto en cada mitad
adb -s 10.0.0.20:5555 install oasis-B.apk
```
Los dos se ven como **pares de red de verdad**, no a través de traducciones. Es lo más cerca de
"dos móviles en la misma wifi" sin tener dos móviles.
### Mirar una instancia concreta
```bash
scrcpy -s 10.0.0.20:5555
```
Ventana con la pantalla del Android, ratón y teclado. Para depurar algo visual no hay nada mejor.
### Comprobar una propiedad en toda la flota
```bash
fleet shell 'getprop ro.build.version.release'
fleet shell 'pm list packages | grep oasis'
```
---
## Decisiones de diseño
| Decisión | Por qué |
|---|---|
| **Preflight de solo lectura** | Se puede lanzar contra hardware ajeno sin miedo. Contesta "¿qué hay aquí y sirve?" sin tocar nada |
| **Instancias automáticas por RAM** | No hay que calcular ni mantener un número por blade. Se amplía la RAM y el siguiente despliegue se ajusta solo |
| **`fleet` en el PATH** | `fleet list`, no `/opt/granja/fleet.sh list` |
| **Playbooks pequeños y con nombre obvio** | `preflight`, `provision`, `devices`, `apk`, `status`, `destroy`. Se adivina cuál usar |
| **Todo relanzable** | `site.yml` es idempotente. Ante la duda, se relanza |
| **Errores que dicen qué hacer** | El fallo de binder no dice "error": dice que el módulo estaba en uso, que la config persistente ya está escrita y que basta reiniciar ese blade |
| **`destroy.yml` conserva los datos** | Borrar `/data` exige un segundo flag. Lo destructivo nunca es el camino por defecto |
---
## Problemas conocidos
Ordenados por probabilidad. Están documentados porque son inevitables, no porque sean fallos.
### 1 · Binder, la primera vez
**Síntoma**: el playbook falla con "faltan devices binder tras el modprobe".
**Causa**: el módulo ya estaba cargado y en uso, así que no se pudo recargar con los parámetros
nuevos.
**Solución**: la configuración persistente ya quedó escrita. Reinicia ese blade y relanza. Pasa una
sola vez por máquina.
### 2 · macvlan: el anfitrión no ve a sus propios contenedores
**Síntoma**: adb desde un blade no encuentra los Android de ese mismo blade.
**Causa**: limitación del driver macvlan, no un error de configuración.
**Solución**: no es un problema en este diseño — el coordinador es un blade **distinto** y desde
fuera sí se llega. Por eso `apk.yml` se ejecuta siempre desde el coordinador. Si algún día montas
adb en un nodo de carga, es esto.
### 3 · El primer arranque de redroid tarda
**Síntoma**: `fleet connect` falla justo después de `site.yml`.
**Causa**: un Android recién creado tarda en levantar por primera vez, sobre todo con render por
software y 45 a la vez.
**Solución**: esperar y reintentar. `fleet connect` es inocuo y se puede repetir.
---
## Ergonomía del hardware
Cosas que no son software pero deciden si esto se usa o se abandona:
**El ruido manda.** 7085 dB significa que no se puede estar en la misma habitación sin protección.
Todo el trabajo tiene que ser remoto — de ahí que no haya nada en el diseño que exija tocar el
chasis en marcha.
**El LCD frontal es el mejor amigo en el arranque.** Configura la red de la CMC con su asistente,
sin cable serie ni portátil enganchado. Es el camino corto la primera vez.
**Encender por ventanas cambia el hábito.** Si el chasis no está siempre en marcha (y no debería,
ver [costes.md](costes.md)), el flujo pasa a ser: encender → esperar arranque → `fleet connect`
trabajar → apagar. Merece la pena tener eso en un script y no en la cabeza.
---
## Pendiente
- **GADS** — UI web con la flota, vista de pantallas y Appium integrado. Es el salto de calidad
cuando se pasa de una decena de dispositivos. No está automatizado a propósito: montar un
despliegue de Node sin poder probarlo sería complejidad sin verificar
- **Script de encendido/apagado por ventanas** contra la CMC vía RACADM
- **`fleet watch`** — un panel de estado que se refresque solo
- **Registro de auditoría en `fleet`** — hoy no deja rastro de quién hizo qué (hallazgo S10 en
[seguridad.md](seguridad.md))