# CLI

Cada verbo de la CLI de mikroscope y sus opciones, agrupadas por verbo, con el valor por defecto de cada opción, los valores que admite y la variable MIKROSCOPE_* que la fija, leídos del código Go.

Source: https://docs.jmrp.io/mikroscope/es/reference/cli/

`mikroscope` recibe un verbo y sus opciones. Las tablas de abajo dan el valor por defecto de cada
opción, los valores que admite y la variable de entorno que la fija, tal como las
definen [`cmd/mikroscope/`](https://github.com/jmrplens/mikroscope/tree/main/cmd/mikroscope) y [`internal/router/options.go`](https://github.com/jmrplens/mikroscope/blob/main/internal/router/options.go).

## Uso y códigos de salida

```sh
mikroscope <verb> [flags]
```

Los verbos se reparten en cinco grupos, cada uno con su propio juego de opciones: los verbos de
despliegue (`doctor`, `plan`, `install`, `upgrade`, `uninstall`, `status`, `image`), los de
grabación (`record`, `mark`, `plot`), el colector (`forward`), `dashboards` y `version`. Las
opciones son opciones del paquete `flag` de Go: `-rate 50` y `--rate 50` son lo mismo, y un booleano
se desactiva con `-privileged=false`.

| Estado | Cuándo                                                                                                                                                                                                                                                                                     |
| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `0`    | el verbo terminó                                                                                                                                                                                                                                                                           |
| `1`    | el verbo se ejecutó y falló (un requisito que falta, un error del router, un destino que no se pudo construir, un panel sin datos, un almacén que `dashboards publish` no pudo publicar), el verbo es desconocido, o una opción de `uninstall`, `record`, `mark`, `plot`, `forward` o `dashboards` no se pudo analizar o validar                 |
| `2`    | no se dio ningún verbo, o una opción de `doctor`, `plan`, `install`, `upgrade`, `status` o `image` no se pudo analizar o validar; no se envió nada al router                                                                                                                              |

Cada opción de despliegue y de conexión se valida antes de conectarse a nada, en una sola función,
`FinishFor` en [`internal/router/options.go`](https://github.com/jmrplens/mikroscope/blob/main/internal/router/options.go), así que un valor malo detiene el verbo sin
enviar nada al router y nombra el valor que rechaza:

```text
$ mikroscope install --rate 500
mikroscope: rate must be 1-100 Hz, got 500
```

Eso sale con 2; `uninstall --rate 500`, `record --port 0` y `forward --port 0` salen con 1.
`--triggers` pasa por el `ParseTriggers` del propio agente, así que una condición desconocida, un
umbral mal escrito, una comilla o un punto y coma hacen fallar el verbo de la misma forma. El agente
vuelve a analizar `TRIGGERS` al arrancar, que es lo que detecta una envlist editada a mano en el
router: el contenedor sale con estado `2` tras una línea `mikroscope-agent: bad configuration:` en
el log del router, y `restart-policy=on-failure` lo vuelve a arrancar.

### Valores por defecto

- Una opción que nombra una variable en las tablas de abajo lee su valor por defecto de
  `MIKROSCOPE_<KEY>`. Una variable con la cadena vacía cuenta como no definida, y una opción en la
  línea de órdenes gana siempre.
- **Solo tienen variable las opciones que la nombran.** `--rate`, `--buffer`, `--port`,
  `--memory-max`, `--mem-limit-mb`, `--capture-mb`, `--triggers`, `--floor-hz`, `--privileged`,
  `--ephemeral`, `--expose`, `--restart-max-count`, `--restart-interval`, `--start-on-boot`,
  `--container-name` y `--extract-timeout` son solo opciones.
- `status`, `upgrade` y `uninstall` toman de la instalación del router las opciones que describen su
  forma cuando no se les dan ([Forma de la
  instalación](https://docs.jmrp.io/mikroscope/es/reference/cli/#pasa-la-misma-forma-a-status-upgrade-y-uninstall)).
- La CLI no lee `.env` por sí misma; expórtalo antes con `set -a; . ./.env; set +a`. [Variables de
  entorno](https://docs.jmrp.io/mikroscope/es/reference/environment/) enumera todas las variables, incluidas las
  credenciales que no tienen ninguna opción.

## Órdenes de despliegue

Los siete verbos de despliegue comparten las [opciones de
despliegue](https://docs.jmrp.io/mikroscope/es/reference/cli/#opciones-de-los-verbos-de-despliegue); una opción que a un verbo no le sirve se acepta,
se comprueba y se ignora. Las opciones propias de cada verbo son estas:

| Verbo       | Qué hace                                                                                                                                                                                                                        | Escribe en el router | Sus opciones propias                                   |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- | ------------------------------------------------------ |
| `doctor`    | Comprobación previa de solo lectura en una conexión ssh; cada comprobación que falla nombra su arreglo. Después lee el anillo del agente en marcha en busca de un bucle, churn de STP, flaps de enlace y descartes softnet.     | no                   | ninguna                                                |
| `plan`      | Imprime cada objeto que crearía `install` y se detiene; no se conecta a nada. Con `--rsc` escribe en su lugar un script de RouterOS.                                                                                            | no                   | `--rsc`, `--out`                                       |
| `install`   | Ejecuta `doctor`, consigue la imagen de la arquitectura del router, imprime el listado, pregunta, escribe el manifiesto de la instalación y después cada objeto, y sondea el agente desde este equipo.                          | sí                   | `--dry-run`, `--yes`, `--no-doctor`                    |
| `upgrade`   | Lee la forma de la instalación, consigue una imagen nueva, lista el manifiesto, el paso del contenedor y cualquier paso que el router ya no tenga, pregunta, los escribe, vuelve a crear el paso del contenedor y sondea.       | sí                   | `--dry-run`, `--yes`                                   |
| `uninstall` | Lee el manifiesto de la instalación, borra todo lo que creó la instalación, del más reciente al más antiguo y el manifiesto el último, y verifica por recuento y por etiqueta. No lista ni borra nada sin `--yes`.            | sí                   | `--yes`, `--targets`, las opciones de destino y de Grafana |
| `status`    | Lee la forma de la instalación e imprime el recuento de propiedad de cada paso; si hay algo instalado, sondea el agente e imprime su salud y su placa.                                                                          | no                   | ninguna                                                |
| `image`     | Construye el tar de la imagen del agente y lo escribe en `--out`, para cargarlo a mano; no se conecta a nada.                                                                                                                  | no                   | `--out`                                                |

### `doctor`

```sh
mikroscope doctor
```

Ejecuta estas comprobaciones, en este orden, y sale con 1 con `N prerequisite(s) missing; nothing
was written` cuando imprime una línea `MISSING`; una línea `WARN` no cambia nada:

Las comprobaciones que ejecuta doctor:

| Comprobación, tal como se imprime | Pasa cuando | La solución que nombra |
| --- | --- | --- |
| RouterOS 7.24 or later | `/system/resource` informa una `version` 7.24 o posterior, que se lee con número de parche o sin él y sea cual sea el canal, como en `7.24 (stable)` o `7.25rc1 (testing)` | actualiza RouterOS a 7.24 o posterior (`/system/package/update`), y el paquete `container` con él |
| architecture has a container package | el `architecture-name` del router es `arm`, `arm64` o `x86_64`, las arquitecturas para las que MikroTik publica un paquete `container` | ninguno: en este router no puede ejecutarse ningún agente |
| the router picks the image's architecture | con `--remote-image`: siempre, con la arquitectura del router, porque RouterOS la elige del índice multiarquitectura de la imagen. Un aviso en `arm`, donde el índice tiene `linux/arm/v5` y `linux/arm/v7` y no se sabe cuál descarga RouterOS | en `arm`, si el contenedor se detiene con `Exec format error`, instala desde `mikroscope-agent-armv5.tar` con `--agent-tar` |
| architecture matches the --agent-tar image | con `--agent-tar`: la arquitectura del propio tar es la del router (`amd64` para `x86_64`); `--arch` no hace falta | descarga el recurso de la versión que nombra, `mikroscope-agent-<arch>.tar` |
| architecture read from the router | sin ninguna de las dos opciones de imagen y con `--arch` sin fijar (o `auto`): siempre; `install` y `upgrade` construyen o cargan la imagen de la arquitectura que leyó doctor | ninguno |
| architecture matches --arch <arch> | con un `--arch` explícito y sin opciones de imagen: el `architecture-name` del router es el que corresponde a `--arch` (`arm64`, `arm`, `x86_64`) | vuelve a ejecutar con el `--arch` que nombra, o quita `--arch` para que `install` la lea del router |
| container package installed and enabled | existe un paquete `container` con `disabled=no` | descarga el paquete `container` de esta arquitectura y versión de RouterOS, súbelo y reinicia; si ya está y deshabilitado, `/system/package/enable container` y reinicia |
| device-mode container=yes | `/system/device-mode` informa `container=yes` | `/system/device-mode/update container=yes` y confírmalo como pide la consola: en un router que dice `update: please activate by turning power off or pressing reset or mode button`, pulsa el botón reset o mode o corta la alimentación; en CHR, que dice `update: turn off power in 5m to activate changes`, apaga y enciende la VM en menos de 5 minutos |
| free memory ≥ <--memory-max> | `free-memory` es al menos lo que pide `--memory-max`, 64 MiB por defecto | libera memoria en el router, o pide menos con `--memory-max` |
| free memory leaves room for the pull | un aviso, solo con `--remote-image`: `free-memory` es al menos `--memory-max` más 16 MiB, margen para que RouterOS descargue y extraiga la imagen antes de que arranque el agente. No se ha medido cuánto ocupa una descarga, así que el margen es una estimación | instala desde un tar con `--agent-tar` si la descarga falla |
| free flash ≥ <size> (image tar + extracted root) | sin `--disk` ni `--ephemeral`: `free-hdd-space` es al menos el doble de la imagen más 4 MiB. Con `--remote-image` no se sube nada y el nombre acaba en `(extracted root)`: la raíz en la que se extrae la imagen descargada, 7 MiB, más 4 MiB | libera flash, o instala con `--disk tmpfs` o `--ephemeral` donde exista un disco tmpfs |
| disk <disk> exists | con `--disk` o `--ephemeral`: existe un disco con ese slot | `/disk/add type=tmpfs tmpfs-max-size=64M slot=tmpfs` para un disco en RAM, o nombra un disco existente con `--disk` |
| disk <disk> has ≥ <size> free (image tar + extracted root) | con `--disk` o `--ephemeral`, cuando el disco existe: su espacio libre es al menos el doble de la imagen más 4 MiB; con `--remote-image`, la raíz de 7 MiB más 4 MiB, como en la comprobación de la flash | libera espacio en ese disco, o da a un disco tmpfs un `tmpfs-max-size` mayor |
| disk tmpfs is RAM | con `--ephemeral`: el disco del slot `tmpfs` es de tipo `tmpfs` | libera el slot para un disco tmpfs, o instala con `--disk <slot>` sin `--ephemeral` |
| start-on-boot suits a root in RAM | un aviso, cuando el disco es tmpfs: start-on-boot queda en `no`, porque un reinicio vacía el disco y un contenedor que arranca con el equipo no tiene raíz | pasa `--start-on-boot no`, o `--ephemeral` |
| veth name <veth> is free or ours | ninguna veth tiene ese nombre, o la que lo tiene lleva la etiqueta de esta instalación | elige otra `--veth` (y otra `--subnet`), o borra la veth a mano si es un resto tuyo |
| envlist <name>-env is free or ours | ninguna envlist tiene ese nombre, o la que lo tiene contiene la entrada `MIKROSCOPE_TAG` de esta instalación | elige otro `--name` |
| install manifest <disk/>mikroscope/<name>.manifest.txt is free or ours | no hay ningún fichero en la ruta del manifiesto de instalación, o el que hay contiene la línea `tag=` de esta instalación | mueve el fichero a otro sitio, o elige otro `--name` |
| container name <name> is free or ours | con `--container-name`: ningún contenedor tiene ese nombre, o el que lo tiene lleva la etiqueta de esta instalación | elige otro `--container-name` |
| subnet <subnet> does not overlap a route | ninguna ruta de la tabla main, activa o no, cae dentro de la /30, y ninguna red conectada de otra interfaz contiene su extremo del router. Las rutas que solo contienen la /30 (una ruta por defecto, un prefijo más amplio hacia una VPN), las rutas blackhole y la propia veth de la instalación no cuentan | elige otra /30 con `--subnet` |
| interface list <list> exists | existe la lista `--iface-list` (por defecto `LAN`). Con `--iface-list none` doctor imprime `interface list the veth joins` y lo da por bueno: no se escribe ninguna pertenencia | `--iface-list none` si ninguna regla del cortafuegos necesita la veth en una lista (doctor lo ofrece primero en ese caso); si no, `/interface/list/add name=…`, o pasa la lista que usa tu regla de descarte `in-interface-list=!…` |
| address list <list> | siempre: install añade la /30 a la lista `--addr-list` (por defecto `LANs`), lo que la crea si falta, y uninstall retira la entrada. Con `--addr-list none` doctor imprime `address list the /30 joins`. Si alguna regla necesita esa pertenencia lo responde la fila siguiente | ninguno |
| no firewall rule drops the agent's replies | doctor lee todas las reglas activas de las cadenas por las que pasan las respuestas del agente, `/ip/firewall/raw` prerouting y `/ip/firewall/filter` forward e input, y recorre cada una como RouterOS, gana la primera que coincide, con las respuestas en las listas a las que se une el plan: ninguna regla las descarta. Un aviso cuando una regla podría hacerlo, porque filtra por algo que doctor no evalúa (un destino, una marca, un límite de tasa), y cuando las respuestas a un equipo de la LAN pasan pero una regla podría descartar las que van al propio router (filter input), que necesita el transporte por relay | las `--iface-list` y `--addr-list` que dejan pasar las respuestas; cuando ninguna lista lo consigue (una regla `src-address=!<rango>`, por ejemplo), añade antes de esa regla una de aceptación para `in-interface=<veth>`, o elige una `--subnet` dentro del rango |
| no firewall rule doctor reads is invalid or names a deleted list | un aviso: ninguna regla de raw prerouting ni de filter forward e input está marcada como inválida, que RouterOS salta como si no existiera (nombra una interfaz que se quitó o no está lista, y `about` dice cuál), y ninguna nombra una lista de interfaces que se quitó, que RouterOS guarda como el id de la lista (`in-interface-list=!*2000010`) y aplica como una lista vacía. Una regla cambiada un momento antes se lee inválida, sin motivo, hasta que RouterOS la aplica | corrige o quita lo que nombra una regla inválida; vuelve a poner por nombre una lista borrada, porque crear una lista con el mismo nombre no repara la regla. Sin motivo, ejecuta `doctor` otra vez |
| --lan-address <address> is the router's | con `--expose`: una interfaz del router tiene esa dirección | pasa la dirección que el router tiene en su LAN, tal como la lista `/ip/address/print` |
| --lan-address is not on the uplink | un aviso, con `--expose`: la interfaz que tiene la dirección no lleva la ruta por defecto, no está en ninguna lista `WAN` y no comparte ninguna lista de interfaces con la interfaz que lleva la ruta por defecto | pasa la dirección LAN del router: en el enlace de subida el dst-nat publicaría el agente hacia Internet |
| no registry credential meant for another registry | un aviso, solo con `--remote-image`: no hay usuario en `/container/config`, o el host de `registry-url` es el host del que se descarga la imagen, contando todas las grafías de Docker Hub como una. Un `registry-url` vacío con usuario puesto avisa. Doctor lee si hay usuario, nunca el nombre, y no puede leer la contraseña | `/container/config` guarda un solo usuario para todo el equipo, y una credencial de otro registro puede hacer que la descarga de una imagen pública acabe en `auth error`. Instala desde un tar con `--agent-tar`, pasa un `--remote-image` del registro al que pertenece el usuario, o borra el usuario si nada más lo necesita |
| the installed agent published on the LAN asks for a token | un aviso, que solo aparece cuando una instalación con este `--name` tiene un dst-nat en la LAN: su entorno contiene un `TOKEN`. Doctor cuenta las entradas, nunca lee el valor | `upgrade` con el mismo `--name` y `--token <secreto>`; o retira el agente, las reglas de LAN y el contenedor juntos con `uninstall --name <nombre> --yes` |
| the router does not answer DNS from its uplink | un aviso: `allow-remote-requests` de `/ip/dns` está apagado, o una regla de raw prerouting o de filter input descarta una consulta UDP al puerto 53 que entra por la interfaz de la ruta por defecto activa, recorrida como en la comprobación de trampas, gana la primera que coincide. Un aviso de que las consultas podrían pasar cuando una regla filtra por algo que doctor no evalúa, una lista de direcciones de origen por ejemplo. IPv6 no se lee | una regla de descarte para el puerto 53 UDP y TCP en el enlace de subida antes de cualquier aceptación que lo coja, o `/ip/dns/set allow-remote-requests=no` si ningún equipo de la LAN usa el router como resolvedor |
| nothing tagged for <name> that these flags do not select | un aviso: en cada menú donde escribe una instalación, los objetos con su etiqueta no son más que los que selecciona el plan de estas opciones. Una instalación hecha con otras opciones (`--expose`, otras listas, otra `--subnet`) deja más | ejecuta `status` y `uninstall` sin opciones de forma, para que lean el manifiesto de la instalación, o con las opciones con que se hizo |

El `doctor` suelto, pero no el que ejecuta `install`, lee después una vez el anillo del agente por
HTTP desde la dirección .2 de `--subnet` en `--port`, enviando `--token`, y desiste a los 3 s. Pasa
el mismo `--subnet`, `--port` y `--token` con los que se instaló el agente. Los hallazgos se definen
en [Requisitos](https://docs.jmrp.io/mikroscope/es/install/prerequisites/#lo-que-muestra-el-agente-en-marcha) y nunca
cambian el estado de salida.

### `plan`

```sh
mikroscope plan
mikroscope plan --rsc --remote-image jmrplens/mikroscope-agent:1.6.1 --out mikroscope.rsc
```

- Sin `--rsc` imprime el listado que imprimiría `install`, igual que `install --dry-run`, con el
  token enmascarado como `(token)`.
- Con `--rsc` escribe la instalación entera como un script de RouterOS, en `--out` o en la salida
  estándar. Con `--out` imprime `<out>: N lines; review it, then paste it into the router's
  terminal or /import it`. Pégalo solo en el indicador `] >`: un script pegado mientras RouterOS
  pregunta por la licencia pierde sus primeras líneas ([Script de
  RouterOS](https://docs.jmrp.io/mikroscope/es/install/script/#run-on-the-router)). Con un token puesto, el script lo lleva en
  claro ([Salvaguardas del
  instalador](https://docs.jmrp.io/mikroscope/es/security/installer/#un-script-rsc-generado-es-una-credencial)).
- Aquí `--arch auto` es `arm64`, porque no se le pregunta nada al router.

### `install`

```sh
mikroscope install --remote-image jmrplens/mikroscope-agent:1.6.1
```

1. `doctor`, en una conexión, salvo con `--no-doctor`. Un requisito que falta la detiene sin
   escribir nada.
2. Con `--arch auto`, la arquitectura que leyó doctor; `--no-doctor` sin `--remote-image` hace una
   conexión más para leerla, y lo dice.
3. La imagen: compilada, leída de `--agent-tar`, o ninguna con `--remote-image`.
4. El listado, y después `write the objects above to the router? [y/N]` salvo con `--yes`.
   Cualquier cosa que no sea `y` la detiene con `not confirmed; nothing written`.
5. El manifiesto de la instalación, después cada objeto, e `install done: N step(s) created`.
6. El sondeo desde este equipo ([Acceso por
   red](https://docs.jmrp.io/mikroscope/es/install/reaching-the-agent/#lo-que-te-dice-el-sondeo-tras-install)).

`--dry-run` se detiene tras el listado y no abre ninguna conexión.

### `upgrade`

```sh
mikroscope upgrade --remote-image jmrplens/mikroscope-agent:1.6.1
```

- Una conexión lee cómo se hizo la instalación, si está cada paso, la arquitectura del router y,
  con `--remote-image`, la comprobación de credenciales de registro de doctor. `upgrade` no ejecuta
  `doctor`.
- Rechaza un router sin instalación (`nothing to upgrade: run install first`), y una instalación con
  token cuando no recibe ninguno.
- Lista el manifiesto de la instalación, el paso del contenedor y cualquier paso que el router ya no
  tenga, pregunta, escribe el manifiesto y los pasos que faltan, borra y vuelve a crear el paso del
  contenedor, y sondea. Los objetos de red se quedan.
- La envlist se escribe a partir de las opciones que recibe `upgrade`: una opción de ajuste que
  falte vuelve a su valor por defecto ([Forma de la
  instalación](https://docs.jmrp.io/mikroscope/es/reference/cli/#pasa-la-misma-forma-a-status-upgrade-y-uninstall)).
- `--dry-run` se detiene tras el listado y no abre ninguna conexión.

### `uninstall`

```sh
mikroscope uninstall                                             # lista los objetos del router
mikroscope uninstall --yes                                       # y los borra
mikroscope uninstall --targets all --influx … --grafana …        # lista todo
mikroscope uninstall --targets all --influx … --grafana … --yes  # y lo borra
```

Sin `--yes` lista: con `--router` lee antes la forma de la instalación, y sin ella lista solo a
partir de las opciones. `--targets` lo amplía más allá del router:

| Objetivo    | Qué se va                                                                                                                                                                                                                                         |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `router`    | todo lo que creó `install`: los objetos del manifiesto de la instalación, cualquier otro objeto con su etiqueta, la raíz del contenedor, el manifiesto y el directorio `mikroscope` si no queda nada más en él. El valor por defecto              |
| `dashboard` | por cada almacén que nombran las opciones de destino: el dashboard `mikroscope-<almacén>`, se importara como se importara, y la fuente de datos `mikroscope-<almacén>`. Ni la carpeta, ni una fuente de datos adoptada, ni las reglas de alerta provisionadas |
| `data`      | las tablas e índices que escribieron los destinos, y los ficheros que escribieron los de fichero                                                                                                                                                |
| `all`       | los tres de arriba                                                                                                                                                                                                                                |

Los objetivos `dashboard` y `data` toman las opciones de [destino](https://docs.jmrp.io/mikroscope/es/reference/cli/#destinos) y de
[Grafana](https://docs.jmrp.io/mikroscope/es/reference/cli/#publicar-en-grafana) de `forward`, para encontrar los almacenes. De las de Grafana, `uninstall`
lee `--grafana` y `--grafana-datasource-uid`, ignora las demás y rechaza `--grafana-dry-run`: su
ejecución de prueba es dejar fuera `--yes`. Cuando una opción de destino nombra un almacén,
`dashboard` necesita además `--grafana` (o
`MIKROSCOPE_GRAFANA_URL`, y después `GRAFANA_URL`) y `GRAFANA_TOKEN`, y se detiene con
`--targets dashboard needs --grafana …` sin un Grafana y con
`--targets dashboard needs GRAFANA_TOKEN` sin el token. Sin ninguna opción de destino,
`--targets dashboard` o `data` no encuentra ningún almacén e imprime
`nothing of this is here to remove`; `all` actúa entonces solo sobre los objetos del router.

- **No se borra nada sin `--yes`**, el mismo `--yes` que toman los verbos de despliegue. Una tabla
  borrada no se puede reponer como `install` repone un objeto del router.
- **Los almacenes se listan antes de tocar el router.** Los objetivos `dashboard` y `data` se
  listan primero, así que uno que no se puede listar detiene el verbo antes de borrar nada, también
  los objetos del router de `all`.
- **Un Grafana que no puede leer lo detiene.** Solo un 404 cuenta como que no está. Un Grafana
  inalcanzable, un token rechazado o un error del servidor detienen el verbo con `asking Grafana
  whether dashboard mikroscope-<almacén> is there: …` y estado de salida 1, antes de borrar nada.
- **Las tablas se le preguntan al almacén, nunca van compiladas.** Una lista dentro del binario
  serían las medidas que escribe esta versión, y las que merece la pena borrar son las que ya nadie
  escribe: lo que recogía una versión anterior, o una fuente apagada desde entonces. Se reclama todo
  lo que lleva el prefijo `mikroscope_`; nada más se toca.
- **Una fuente de datos adoptada no se borra.** Una nombrada en `--grafana-datasource-uid` era de
  otro antes de esto y es de otro después.
- **Una que no se va no detiene a las demás.** Cada fallo se imprime con lo que dijo el almacén y el
  borrado continúa.

> **Tres destinos no guardan nada que esto pueda borrar**
>
> A `--prom` lo raspan en vez de escribirle, así que las series viven en un Prometheus del que esto
> no ha oído hablar y caducan con su retención. `--graphite` no ofrece borrado en absoluto: quita a
> mano los ficheros whisper. `--sql` escribe un fichero, y las filas ya cargadas en una base de datos
> real desde él hay que borrarlas allí, o con `--postgres` apuntado a esa base. Cada uno imprime su
> propio motivo en lugar de faltar en silencio.

> **InfluxDB 3 borra una tabla renombrándola**
>
> Una tabla borrada por `/api/v3/configure/table` se queda en `information_schema` con un nombre
> que lleva el instante del borrado, `mikroscope_cpu-<timestamp>`. Esas están fuera y no se vuelven
> a ofrecer; sin ese filtro, un uninstall listaría las mismas tablas en cada ejecución, las borraría
> con éxito y no se vaciaría nunca. El borrado pide `hard_delete_at=now`, que el servidor acepta y
> programa.

### `status`

```sh
mikroscope status
```

Imprime lo que leyó de la instalación, el recuento de propiedad de cada paso y, cuando hay algo
instalado, la salud del agente, leída directamente con un plazo de 3 s:

```text
install on the router (manifest mikroscope/mikroscope.manifest.txt): veth veth-mikroscope, subnet 172.30.10.0/30, lists LAN/LANs, port 9123, …
  1     install manifest mikroscope/mikroscope.manifest.txt
  1     veth interface veth-mikroscope
  …
agent: 1.6.1 (<commit>) built <time>, 10 Hz, seq 19 (oldest 1), up 2s, 0 slipped, 1ms round trip
```

### `image`

```sh
mikroscope image --arch arm64 --out mikroscope-agent-arm64.tar
```

Construye el tar de la imagen del agente para `--arch`, `arm64` con `auto`, y lo escribe en `--out`,
por defecto `mikroscope-agent-<arch>.tar`. Rechaza `--remote-image`, porque no hay ningún tar que
escribir.

### Forma de la instalación

`status`, `upgrade` y `uninstall` leen cómo se hizo la instalación del router antes de construir su
plan: de su manifiesto, `mikroscope/<name>.manifest.txt` en su disco, o, para una instalación sin
manifiesto, de los objetos que llevan su etiqueta.

- Una opción de forma que no se da toma el valor con que se hizo la instalación: `--veth`,
  `--subnet`, `--iface-list`, `--addr-list`, `--disk` (y `--ephemeral`), `--port`, `--expose` con
  `--lan-address`, `--container-name` y `--start-on-boot`, y para `status` y `uninstall`
  `--remote-image`. `uninstall --yes` sin ninguna otra opción retira una instalación hecha con
  cualquiera de ellas.
- Sin manifiesto, una pertenencia a una lista que el router no tiene no se lee como `none`: decide
  la opción, o su valor por defecto, y `upgrade` vuelve a crear la pertenencia.
- Una opción dada, o fijada por su variable `MIKROSCOPE_*`, que contradiga la instalación se
  rechaza antes de escribir nada, nombrando los dos valores: `the install named mikroscope on the
  router does not match the flags: installed with --iface-list MYLAN, given LAN`. Así ocurre con
  `--veth`, `--subnet`, `--iface-list`, `--addr-list`, `--disk` y `--ephemeral`, `--port`, y
  `--expose` con `--lan-address`. `--container-name`, `--start-on-boot` y `--remote-image` se
  rellenan si no se dan y nunca se rechazan: gana la opción dada, y `upgrade` toma su imagen solo de
  sus propias opciones.
- `--name` selecciona la instalación, y nunca se lee del router.
- `upgrade` vuelve a escribir la envlist a partir de sus propias opciones: un `upgrade` sin el
  `--rate`, `--buffer`, `--mem-limit-mb`, `--capture-mb`, `--triggers` o `--floor-hz` con los que
  instalaste escribe en su lugar los valores por defecto, y `--memory-max`, `--privileged`,
  `--restart-max-count` y `--restart-interval` vuelven igualmente a los suyos. Rechaza una
  instalación cuya envlist tiene un `TOKEN` si no recibe `--token`: `the install named mikroscope
  asks for a token and upgrade would write its envlist without one: pass --token (or
  MIKROSCOPE_TOKEN)`.

### Escrituras en el router

**Lo que `install` escribe en tu router**

- el manifiesto de la instalación, un fichero `mikroscope/<name>.manifest.txt` en el disco de la instalación que lista las opciones y cada objeto de abajo
- una veth
- una dirección
- una pertenencia a lista de interfaces, salvo con `--iface-list none`
- una entrada de address-list, salvo con `--addr-list none`
- una envlist
- el tar de la imagen, que se borra en cuanto el contenedor está extraído, salvo que `--remote-image` haga que el router se la baje
- el contenedor, y su raíz `mikroscope/<name>` en el mismo disco

Cada objeto lleva el comentario `mikroscope:<name> (managed by mikroscope)`

`mikroscope plan` imprime cada orden antes de escribir nada.

`uninstall` elimina por etiqueta exacta más identidad, nunca por patrón, y falla nombrando el paso si queda algo.

**Lo que añade `install --expose`**

- dos reglas de cortafuegos, etiquetadas
- el token pasa a ser obligatorio
- `uninstall` y `status` encuentran las dos reglas por el manifiesto y la etiqueta, con `--expose` o sin él

Cada objeto lleva el comentario `mikroscope:<name> (managed by mikroscope)`

`mikroscope plan` imprime cada orden antes de escribir nada.

**Lo que sustituye `upgrade`**

- el manifiesto de la instalación, que se escribe siempre el primero, así que una instalación hecha antes de que existiera lo recibe
- una imagen nueva y el contenedor
- la envlist, reescrita con las opciones que recibe `upgrade`; se niega con una instalación con token si no recibe `--token`
- cualquier otro objeto de la instalación que el router ya no tenga, que se crea de nuevo antes del contenedor
- los objetos de red se quedan

Cada objeto lleva el comentario `mikroscope:<name> (managed by mikroscope)`

`mikroscope plan` imprime cada orden antes de escribir nada.

**Lo que elimina `uninstall`**

- cada objeto del manifiesto de la instalación, y cualquier otro objeto que lleve su etiqueta
- la raíz del contenedor `mikroscope/<name>`, con el contenedor, o con la palabra del manifiesto si queda una raíz
- el manifiesto, lo último, y después el directorio `mikroscope` si no queda nada más en él
- nunca device-mode, el paquete `container`, `/container/config`, ni una lista, disco o regla que el router ya tuviera

Cada objeto lleva el comentario `mikroscope:<name> (managed by mikroscope)`

`mikroscope plan` imprime cada orden antes de escribir nada.

`uninstall` elimina por etiqueta exacta más identidad, nunca por patrón, y falla nombrando el paso si queda algo.

## Opciones de despliegue

`doctor`, `plan`, `install`, `upgrade`, `uninstall`, `status` e `image` admiten todas las opciones de
abajo.

### Conexión

| Opción         | Por defecto                           | Variable                                        | Admite                                                                                                                                                                                                                                  | Significado                                                                                                                                                                                                                                              |
| -------------- | ------------------------------------- | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--router`     | ninguno, obligatoria                  | `MIKROSCOPE_ROUTER`                             | `user@host` o un alias de la configuración de ssh                                                                                                                                                                                       | destino de ssh; todos los verbos salvo `plan`, `install --dry-run`, `upgrade --dry-run`, `image` y un `uninstall` sin `--yes` fallan sin ella                                                                                                              |
| `--ssh-port`   | vacío (configuración de ssh)          | `MIKROSCOPE_SSH_PORT`                           |                                                                                                                                                                                                                                         | puerto de ssh                                                                                                                                                                                                                                            |
| `--ssh-key`    | vacío (agente o configuración de ssh) | `MIKROSCOPE_SSH_KEY`                            |                                                                                                                                                                                                                                         | fichero de identidad de ssh                                                                                                                                                                                                                              |
| `--ssh-option` | ninguno                               | `MIKROSCOPE_SSH_OPTIONS`, separadas por comas   | `Clave=valor`, repetible; la clave, una de `StrictHostKeyChecking`, `UserKnownHostsFile`, `ConnectTimeout`, `HostKeyAlgorithms`, `PubkeyAcceptedAlgorithms`, `IdentitiesOnly`, `ServerAliveInterval`; el valor, `^[A-Za-z0-9_./~+:-]{1,256}$` | una opción de ssh y scp, que va antes de las propias de la CLI, `-o BatchMode=yes -o ConnectTimeout=15`; la primera opción sustituye la lista entera de la variable. Un router que aún no está en `known_hosts` necesita `StrictHostKeyChecking=accept-new`, porque la CLI ejecuta ssh en modo batch |

### Objetos del router

| Opción          | Por defecto           | Variable                 | Admite                                                                              | Significado                                                                                                                                                                     |
| --------------- | --------------------- | ------------------------ | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--name`        | `mikroscope`          | `MIKROSCOPE_NAME`        | `^[A-Za-z0-9][A-Za-z0-9_.-]{0,31}$`                                                 | el nombre de la instalación; etiqueta cada objeto como `mikroscope:<name> (managed by mikroscope)` y da nombre a la envlist, la raíz y el manifiesto                             |
| `--veth`        | `veth-mikroscope`     | `MIKROSCOPE_VETH`        | `^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$`                                                 | nombre de la interfaz veth en el router                                                                                                                                         |
| `--subnet`      | `172.30.10.0/30`      | `MIKROSCOPE_SUBNET`      | una /30 IPv4 en su dirección de red                                                 | el router toma `.1`, el agente `.2`                                                                                                                                             |
| `--port`        | `9123`                | ninguna                  | 1–65535                                                                             | puerto HTTP del agente en la veth                                                                                                                                               |
| `--iface-list`  | `LAN`                 | `MIKROSCOPE_IFACE_LIST`  | el mismo patrón que `--veth`, o `none`; ni `all`, ni `dynamic`, ni `static`         | lista de interfaces a la que se une la veth; `none` no escribe ninguna pertenencia ([Listas del firewall](https://docs.jmrp.io/mikroscope/es/install/firewall/))                                     |
| `--addr-list`   | `LANs`                | `MIKROSCOPE_ADDR_LIST`   | el mismo patrón que `--veth`, o `none`                                              | lista de direcciones a la que se une la /30, que la entrada crea si la lista no tiene ninguna; `none` no escribe ninguna entrada                                                 |
| `--disk`        | vacío (flash interna) | `MIKROSCOPE_DISK`        | `^[A-Za-z0-9][A-Za-z0-9_-]{0,31}$`                                                  | disco de RouterOS para el manifiesto, el tar de la imagen y la raíz: `tmpfs`, `disk1`, `usb1` …                                                                                 |
| `--ephemeral`   | `false`               | ninguna                  |                                                                                     | fuerza `--disk tmpfs`, y `start-on-boot=no` salvo que `--start-on-boot` diga otra cosa: nada se escribe en la flash, nada sobrevive a un reinicio                                |
| `--expose`      | `false`               | ninguna                  | necesita `--lan-address`; `install`, `upgrade` y `plan` necesitan además `--token`  | hace dst-nat del puerto del agente en la dirección LAN del router; añade dos reglas de cortafuegos etiquetadas ([Exponer en la LAN](https://docs.jmrp.io/mikroscope/es/security/expose/))           |
| `--lan-address` | vacío                 | `MIKROSCOPE_LAN_ADDRESS` | una dirección IPv4                                                                  | la dirección LAN del router para `--expose`                                                                                                                                     |

### Imagen del agente

| Opción           | Por defecto                     | Variable                  | Admite                                                                  | Significado                                                                                                                                                                                                                                                                                                                                              |
| ---------------- | ------------------------------- | ------------------------- | ----------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--arch`         | `auto`                          | `MIKROSCOPE_ARCH`         | `arm64`, `arm`, `amd64` o `auto`                                        | arquitectura del equipo, usada como `GOARCH` y en el manifiesto de la imagen. `auto` la lee del router: `doctor`, `install` y `upgrade` la toman del lote de doctor (`install --no-doctor` hace una conexión para ella, y ninguna con `--remote-image`, donde el router elige la arquitectura del índice de la imagen); `plan`, `--dry-run` e `image`, que no se conectan a nada, toman `arm64` |
| `--goarm`        | `5`                             | ninguna                   | `5`, `6` o `7`                                                          | nivel de `GOARM`, usado solo con `--arch arm`: 5 arranca en todos los ARM de 32 bits que vende MikroTik, 7 no arranca en las placas EN7562CT ([Requisitos](https://docs.jmrp.io/mikroscope/es/install/prerequisites/) las enumera)                                                                                                                                         |
| `--agent-tar`    | vacío (compilar el agente aquí) | `MIKROSCOPE_AGENT_TAR`    | una ruta a un tar de imagen del agente                                  | `plan`, `install`, `upgrade`, `image`: sube este tar en vez de compilar uno, así no hace falta ni cadena de herramientas de Go ni una copia del repositorio. El tar se comprueba antes: uno que no sea una imagen del agente mikroscope, o que esté compilado para otra arquitectura que la del router o `--arch`, hace fallar el verbo nombrando el recurso que hay que descargar |
| `--remote-image` | vacío (subir un tar)            | `MIKROSCOPE_REMOTE_IMAGE` | una referencia de registro, `owner/name:tag` o `host/owner/name:tag`    | `plan`, `install`, `upgrade`: el router se descarga la imagen él mismo, así que no se compila ni se sube nada y no queda ningún tar en el equipo. La referencia entera va en `remote-image=`, con el host del registro incluido: sin host, `docker.io`, `index.docker.io` o `registry.hub.docker.com` pasan a ser `registry-1.docker.io`, y cualquier otro host se conserva. `/container/config registry-url` ni hace falta ni se escribe, y la imagen publicada no necesita login de registro |

> **Tres maneras de conseguir la imagen del agente, a una opción de distancia**
>
> Sin `--agent-tar` ni `--remote-image`, `plan`, `install`, `upgrade` e `image` ejecutan
> `go build -trimpath ./cmd/mikroscope-agent` con `CGO_ENABLED=0`, `GOOS=linux` y la arquitectura
> como `GOARCH` ([`internal/image/image.go`](https://github.com/jmrplens/mikroscope/blob/main/internal/image/image.go)), que necesita una copia del repositorio y
> una cadena de herramientas de Go en el `PATH`; sin ella la compilación falla nombrando ambas
> opciones y la versión de Go, antes de que se liste nada. Con `--agent-tar` leen y comprueban el
> tar publicado. Con `--remote-image` no se compila ni se sube nada. `plan --rsc` no consigue
> ninguna imagen en esta máquina: su script necesita `--remote-image` o un tar que ya esté en el
> router. [Métodos de instalación](https://docs.jmrp.io/mikroscope/es/install/routes/) pone las vías una al lado de otra.

### Ajustes del agente

| Opción           | Por defecto                                | Variable           | Admite                                                          | Significado                                                                                                                                                                                                                                                                                                                              |
| ---------------- | ------------------------------------------ | ------------------ | --------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--rate`         | `10`                                       | ninguna            | 1–100                                                           | cadencia del muestreador en Hz (envlist `RATE_HZ`); 10, 50 y 100 Hz van sin pérdidas ([Techo de muestreo](https://docs.jmrp.io/mikroscope/es/cost/rate-ceiling/))                                                                                                                                                                                           |
| `--buffer`       | `60`                                       | ninguna            | 10–3600                                                         | búfer circular en segundos (envlist `BUFFER_S`)                                                                                                                                                                                                                                                                                          |
| `--mem-limit-mb` | `0` (derivado)                             | ninguna            | `0`, u 8–1024                                                   | límite blando de memoria de Go del agente en MiB (envlist `MEM_LIMIT_MB`). `0` lo deriva del anillo: cadencia × búfer × 3 456 B × 2,5, redondeado hacia arriba, con un mínimo de 16 MiB y un máximo de ¾ de `--memory-max` mientras ese máximo aún deje sitio al anillo. Eso da 16 con los valores por defecto. Un número que pases se usa tal cual |
| `--capture-mb`   | `4`                                        | ninguna            | 0–256                                                           | presupuesto de captura por disparo en MiB (envlist `CAPTURE_MB`); `0` desactiva las capturas                                                                                                                                                                                                                                             |
| `--triggers`     | vacío (el conjunto por defecto del agente) | ninguna            | véase [Captura por disparo](https://docs.jmrp.io/mikroscope/es/record/triggers/)    | condiciones de disparo, separadas por comas (envlist `TRIGGERS`)                                                                                                                                                                                                                                                                         |
| `--floor-hz`     | `0`                                        | ninguna            | 0–1000                                                          | una cadencia única para todas las fuentes de nivel, en Hz (envlist `FLOOR_HZ`); `0` mantiene los suelos por fuente; igual a `--rate` lee y emite cada fuente en cada tick                                                                                                                                                                |
| `--token`        | vacío                                      | `MIKROSCOPE_TOKEN` | `^[A-Za-z0-9_.-]{0,128}$`                                       | token bearer que exige el agente (envlist `TOKEN`); `install`, `upgrade` y `plan` lo necesitan con `--expose`, y `upgrade` rechaza una instalación que lo tenga si no recibe ninguno; `doctor` también lo envía para leer el anillo del agente. Le llega a ssh por la entrada estándar, nunca en una línea de órdenes                  |

### Ajustes del contenedor

| Opción                | Por defecto                | Variable | Admite                                | Significado                                                                                                                                                                                                                                                    |
| --------------------- | -------------------------- | -------- | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--container-name`    | vacío (lo nombra RouterOS) | ninguna  | `^[A-Za-z0-9][A-Za-z0-9_.-]{0,31}$`   | el `name=` del contenedor; `doctor` comprueba que ningún otro contenedor lo tenga. Los borrados seleccionan por la etiqueta, no por este nombre                                                                                                                |
| `--memory-max`        | `64M`                      | ninguna  | `^\d{1,6}[KMG]?$`                     | `memory-max` del cgroup del contenedor, en sintaxis de RouterOS                                                                                                                                                                                                |
| `--privileged`        | `true`                     | ninguna  |                                       | ejecuta el contenedor con `privileged=yes`; `-privileged=false` lo desactiva ([Modo privilegiado](https://docs.jmrp.io/mikroscope/es/limits/privileged/))                                                                                                                          |
| `--start-on-boot`     | `auto`                     | ninguna  | `auto`, `yes` o `no`                  | `start-on-boot` del contenedor; `auto` es `no` con `--ephemeral` y `yes` sin ella. `doctor` avisa con `yes` si la raíz está en un disco tmpfs                                                                                                                  |
| `--restart-max-count` | `5`                        | ninguna  | 0–100                                 | `restart-max-count` de la `restart-policy=on-failure` del contenedor                                                                                                                                                                                           |
| `--restart-interval`  | `10s`                      | ninguna  | `^\d{1,4}[smh]$`                      | `restart-interval` entre esos reinicios                                                                                                                                                                                                                        |
| `--extract-timeout`   | `120s`                     | ninguna  | `^\d{1,4}[smh]$`, de 10 a 600 s       | vía del tar: cuánto espera el paso del contenedor a que RouterOS extraiga la imagen antes de borrar el tar; si se agota, se detiene y lo dice, y el tar se queda. El plazo de ssh para una orden, 3 minutos, crece hasta este valor y un minuto más cuando eso es mayor |

Dos ajustes del contenedor no son opciones: `logging=yes` e `ignore-remote-image-change=yes`.
[Almacenamiento y ajustes del contenedor](https://docs.jmrp.io/mikroscope/es/install/layout/#los-ajustes-del-contenedor) los tiene
todos.

### Control de la ejecución

| Opción        | Por defecto                   | Variable | Significado                                                                                                                                             |
| ------------- | ----------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--dry-run`   | `false`                       | ninguna  | `install` y `upgrade`: imprimen el listado y no escriben nada; no se abre ninguna conexión                                                              |
| `--yes`       | `false`                       | ninguna  | `install`, `upgrade`: no pregunta antes de escribir. `uninstall`: borra lo que lista, cosa que sin esta opción no hace                                 |
| `--no-doctor` | `false`                       | ninguna  | `install`: se salta las comprobaciones previas; con `--arch auto` y sin `--remote-image`, una conexión lee la arquitectura del router                   |
| `--out`       | `mikroscope-agent-<arch>.tar` | ninguna  | `image`: ruta de salida del tar. `plan --rsc`: dónde se escribe el script; vacío lo escribe en la salida estándar                                       |
| `--rsc`       | `false`                       | ninguna  | `plan`: escribe un script de RouterOS que instala desde el propio router, en vez del listado                                                            |

## record, mark y plot

Los tres verbos comparten un juego de opciones con `forward`, así que una opción que significa algo
para un hermano se acepta y se ignora: `plot --for 5m` se analiza y no hace nada. La tabla marca qué
verbo lee cada opción. `--from-start` es la excepción: solo `record` la registra, y `forward`,
`mark` y `plot` la rechazan como opción desconocida. `forward` empieza siempre por la muestra más
reciente del agente ([`internal/forward/`](https://github.com/jmrplens/mikroscope/tree/main/internal/forward)).

| Opción          | Por defecto                  | Variable              | La lee                      | Significado                                                                                                                                                                                                                                                                                                                    |
| --------------- | ---------------------------- | --------------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `--out`         | `capture-<UTC time>`         | ninguna               | `record`, `mark`            | prefijo de salida: `<out>.jsonl`, `.csv`, `.markers.csv`, `.meta.json`. `mark` necesita el prefijo de una grabación existente                                                                                                                                                                                                  |
| `--for`         | `0` (hasta Ctrl-C)           | ninguna               | `record`, `forward`         | funciona este tiempo y se detiene                                                                                                                                                                                                                                                                                              |
| `--from-start`  | `false`                      | ninguna               | `record`                    | rellena con todo lo que guarda el anillo del agente antes de pasar a directo                                                                                                                                                                                                                                                   |
| `--poll`        | `500ms`                      | ninguna               | `record`, `forward`         | cada cuánto se tira del anillo del agente                                                                                                                                                                                                                                                                                      |
| `--batch`       | `0`                          | ninguna               | `record`, `forward`         | muestras por petición; `0` es el doble de lo que produce un `--poll` a la cadencia del agente, nunca menos de 20. El relay limita una petición a 13. Una petición se repite hasta que vuelve corta                                                                                              |
| `--transport`   | `auto`                       | ninguna               | `record`, `forward`         | `auto` (directo, luego relay), `direct` (HTTP a la veth) o `relay` (`/tool fetch` sobre la API de RouterOS; cada llamada devuelve como mucho 64 512 B y tarda unos 3 ms o alrededor de 1 s; consulta [Acceso por red](https://docs.jmrp.io/mikroscope/es/install/reaching-the-agent/)) |
| `--log-markers` | `false`                      | ninguna               | `record`, `mark`            | `record`: tras grabar, trae el log del router por la API y añade las líneas que casan a `<out>.markers.csv`. `mark`: añade las líneas del log de la ventana de la grabación                                                                                                                                                    |
| `--topics`      | `system,interface,container` | ninguna               | `record`, `mark`            | temas del log que se conservan como marcadores con `--log-markers`                                                                                                                                                                                                                                                             |
| `--router-tz`   | `Local`                      | ninguna               | `record`, `mark`            | zona IANA que muestra el reloj del router; las horas del log de RouterOS no llevan zona                                                                                                                                                                                                                                        |
| `--in`          | ninguno, obligatoria         | ninguna               | `plot`                      | prefijo de la grabación, o la ruta de su `.jsonl`                                                                                                                                                                                                                                                                              |
| `--svg`         | `<in>.svg`                   | ninguna               | `plot`                      | SVG de salida                                                                                                                                                                                                                                                                                                                  |
| `--title`       | el prefijo                   | ninguna               | `plot`                      | título del gráfico                                                                                                                                                                                                                                                                                                             |
| `--api`         | vacío                        | `MIKROSCOPE_API_ADDR` | `record`, `mark`, `forward` | `host:port` de la API de RouterOS, para el relay, `--log-markers` y la capa de la API                                                                                                                                                                                                                                          |
| `--api-user`    | vacío                        | `MIKROSCOPE_API_USER` | `record`, `mark`, `forward` | usuario de la API; su contraseña sale solo de `MIKROSCOPE_API_PASSWORD`                                                                                                                                                                                                                                                        |
| `--token`       | vacío                        | `MIKROSCOPE_TOKEN`    | `record`, `forward`         | token bearer que el transporte directo envía al agente                                                                                                                                                                                                                                                                         |
| `--port`        | `9123`                       | ninguna               | `record`, `forward`         | puerto HTTP del agente                                                                                                                                                                                                                                                                                                         |
| `--subnet`      | `172.30.10.0/30`             | `MIKROSCOPE_SUBNET`   | `record`, `forward`         | la /30 del agente; su dirección es `.2`                                                                                                                                                                                                                                                                                        |

`mark` toma el texto del marcador de los argumentos restantes,
`mikroscope mark --out cap "queue tree applied"`, o `--log-markers` en lugar de texto. `record`
convierte en marcador cada línea que se escribe en un terminal; cuando la entrada estándar no es un
terminal, no la lee.

`auto` prueba primero `/healthz` por el transporte directo. Si no responde, necesita `--api`,
`--api-user` y `MIKROSCOPE_API_PASSWORD` para probar el relay, y falla nombrando `install --expose`
cuando el transporte directo no responde y el relay no está configurado; un relay configurado que
falla informa `relay transport:` y su error. El relay no lleva el token: `/tool fetch` en el router
no envía cabecera `Authorization`, así que de un agente con token solo se puede tirar por el
transporte directo.

## forward

`forward` ejecuta el colector: tira de la capa del kernel desde el agente, consulta la capa de la API
de RouterOS y escribe ambas en cada destino nombrado. Lee `--for`, `--poll`, `--batch`,
`--transport`, `--api`, `--api-user`, `--token`, `--port` y `--subnet` de la tabla de arriba, además
de sus propias opciones de abajo. Se niega a arrancar sin al menos un destino.

### Capa de la API

| Opción              | Por defecto | Variable                | Significado                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| ------------------- | ----------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `--api-mode`        | `full`      | ninguna                 | preajuste. `off` pone `--api-every 0` salvo que la fijes tú, así que el colector no abre ninguna sesión de la capa de la API; el transporte de relay sigue usando la API. `slow` ejecuta la capa cada 10 s sin `/system/health` y sin recuento de conntrack; se siguen leyendo `/system/resource`, `/system/resource/cpu`, `monitor-traffic` sobre `--interfaces` y los contadores de puerto de `--counters-every`. `full` (los valores por defecto de las opciones) lo lee todo. Una opción explícita de las de abajo gana sobre él |
| `--api-every`       | `1s`        | ninguna                 | cadencia de la capa de la API; `0` desactiva la capa. `off` la pone a `0`, `slow` a `10s`                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `--interfaces`      | vacío       | `MIKROSCOPE_INTERFACES` | interfaces separadas por comas para `monitor-traffic`, una sola llamada para todas                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `--conntrack-every` | `0`         | ninguna                 | pregunta el recuento de conntrack con esta frecuencia; `0` nunca, porque es un recorrido de tabla. Un recorrido tardó 1,3 ms con 6 212 entradas. `slow` la pone a `0` salvo que se dé explícitamente                                                                                                                                                                                                                                                                           |
| `--counters-every`  | `10s`       | ninguna                 | lee los contadores acumulados de cada puerto (errores por tipo, reparto de fast-path, caídas de enlace, tamaños de trama) con esta frecuencia; `0` nunca                                                                                                                                                                                                                                                                                                                                                                             |
| `--labels-every`    | `5m`        | ninguna                 | vuelve a leer qué es cada interfaz (etiqueta a partir de su comentario, tipo, listas de interfaces, bridge, MTU); se lee una vez antes del primer tirón del kernel y luego con esta frecuencia; `0` toma el valor por defecto de 5 min                                                                                                                                                                                                                                                                                               |
| `--no-health`       | `false`     | ninguna                 | se salta `/system/health`. `slow` la activa                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |

Sin `--api` ni `--api-user`, `forward` ejecuta solo la capa del kernel. Con ellos, una primera
marcación fallida registra `api tier: not connected yet, will keep trying: …` y la capa conecta en
la primera ronda que el router responda; no queda deshabilitada en toda la vida del proceso.

### Destinos

| Opción              | Por defecto           | Variable                   | Significado                                                                                                                                    |
| ------------------- | --------------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `--file`            | vacío                 | ninguna                    | escribe la línea de tiempo combinada como JSONL en esta ruta (truncada al arrancar)                                                            |
| `--prom`            | vacío                 | ninguna                    | sirve el `/metrics` de Prometheus en esta dirección, por ejemplo `:9124`                                                                       |
| `--influx`          | vacío                 | `MIKROSCOPE_INFLUX_URL`    | servidor de InfluxDB 3, por ejemplo `http://host:8181`. Una URL de escritura completa se sigue tomando tal cual                               |
| `--influx-db`       | vacío                 | `MIKROSCOPE_INFLUX_DB`     | la base de datos a la que escribe `--influx`; se ignora cuando `--influx` ya lleva una ruta de escritura                                       |
| `--loki`            | vacío                 | `MIKROSCOPE_LOKI_URL`      | URL de push de Loki; lleva eventos (log del kernel, huecos, errores de la API, detecciones, disparadores, el registro del equipo), no muestras |
| `--loki-tenant`     | vacío                 | `MIKROSCOPE_LOKI_TENANT`   | `X-Scope-OrgID` para un Loki multiinquilino                                                                                                    |
| `--otlp`            | vacío                 | `MIKROSCOPE_OTLP_URL`      | endpoint de métricas OTLP/HTTP, por ejemplo `http://host:4318/v1/metrics`                                                                      |
| `--graphite`        | vacío                 | `MIKROSCOPE_GRAPHITE_ADDR` | receptor de texto plano de carbon de Graphite, `host:port`                                                                                     |
| `--graphite-prefix` | `mikroscope`          | ninguna                    | primer nodo de cada ruta de métrica de Graphite                                                                                                |
| `--elastic`         | vacío                 | `MIKROSCOPE_ELASTIC_URL`   | URL base de Elasticsearch u OpenSearch para `_bulk`                                                                                            |
| `--elastic-index`   | `mikroscope-%Y.%m.%d` | ninguna                    | nombre del índice; `%Y`, `%m`, `%d` se expanden a la fecha del evento                                                                          |
| `--sql`             | vacío                 | ninguna                    | escribe sentencias de PostgreSQL/TimescaleDB en esta ruta, o en la salida estándar con `-`; no hay driver de base de datos                     |
| `--sql-hypertable`  | `false`               | ninguna                    | emite también llamadas `create_hypertable` de TimescaleDB en la cabecera SQL; se aplica también a `--postgres`                                 |
| `--postgres`        | vacío                 | `MIKROSCOPE_POSTGRES_DSN`  | envía las mismas sentencias a un PostgreSQL en marcha. La única opción de destino que puede llevar una credencial; ver más abajo               |
| `--telegraf`        | vacío                 | `MIKROSCOPE_TELEGRAF_URL`  | receptor de Telegraf: `http://host:8186/telegraf`, `tcp://host:8094` o `udp://host:8094`                                                       |
| `--stdout`          | vacío                 | ninguna                    | escribe en la salida estándar como `lp` (line protocol de InfluxDB) o `json` (NDJSON); cualquier otro valor se rechaza                         |
| `--host-tag`        | `router`              | `MIKROSCOPE_HOST_TAG`      | etiqueta o label de host en cada punto, en todos los destinos                                                                                  |
| `--queue-seconds`   | `60`                  | ninguna                    | segundos de datos que puede retener cada destino con cola antes de descartar el lote más antiguo; `0` o menos toma 60                          |

Ningún **token** de destino es una opción, porque una opción se ve en `ps` y en el historial de la
shell: salen de `MIKROSCOPE_INFLUX_TOKEN`, `MIKROSCOPE_LOKI_TOKEN`, `MIKROSCOPE_OTLP_TOKEN`,
`MIKROSCOPE_ELASTIC_AUTH` y `MIKROSCOPE_TELEGRAF_TOKEN`. Un destino pedido que no se puede construir
detiene `forward` antes de que tire de nada.

`--postgres` es la excepción, a propósito. Una cadena de conexión de PostgreSQL es la forma que toma
cualquier cliente de PostgreSQL, y pgx lee `PGPASSWORD`, `~/.pgpass` y el fichero de servicio igual
que `psql`, así que un DSN **sin** contraseña funciona como un operador ya espera. La opción existe
para que el DSN pueda decir host, base de datos, usuario y `sslmode` en la línea de órdenes; la
contraseña va en uno de esos tres sitios, o en `MIKROSCOPE_POSTGRES_DSN` dentro de un fichero de
entorno. Una contraseña escrita en la opción la puede leer cualquier proceso de la máquina.

Al salir, `forward` imprime el número de muestras del kernel, muestras de la API, huecos y saltos de
desfase, y para cada destino cuántos eventos escribió, descartó y en cuántos falló. Mientras
funciona, registra en la salida de error una línea por minuto con los recuentos de kernel, API,
huecos, disparos y detecciones, el recuento de reinicios del agente, el último número de secuencia,
y los escritos, descartados y errores de cada destino. Cuando la capa de la API ha fallado o ha
reconectado añade `api: N failed round(s), N reconnect(s)`.

El destino Prometheus del colector dimensiona su histograma de ticks ocupados para 10 Hz sea cual sea
la cadencia del agente (`promHistogramRateHz` en [`cmd/mikroscope/sinkflags.go`](https://github.com/jmrplens/mikroscope/blob/main/cmd/mikroscope/sinkflags.go)), así
que la disposición de los buckets no cambia cuando se reconecta a un agente configurado de otra
forma. [Métricas de Prometheus](https://docs.jmrp.io/mikroscope/es/reference/metrics/) cuenta qué más se sigue de esa
constante.

### Publicación en Grafana

`forward` puede crear una fuente de datos y publicar un dashboard por cada almacén al que escribe,
una vez, al arrancar, antes de la primera muestra. [`dashboards publish`](https://docs.jmrp.io/mikroscope/es/reference/cli/#dashboards) hace lo mismo
una vez, con las mismas opciones, y termina sin recoger nada. Está apagado si no se da `--grafana`, y
el token es `GRAFANA_TOKEN`: publicar sin uno escribiría como aquel por quien el servidor tome a
quien pregunta.

En cada ejecución, y en `forward` antes de tocar el router:

1. Comprueba las opciones antes de hacer ninguna petición, también en una ejecución de prueba.
   Rechaza una ejecución sin ningún destino que tenga dashboard, un `--grafana-datasource-sslmode`
   que no sea uno de los cuatro modos de Grafana, y una ejecución de más de un almacén que fije
   `--grafana-datasource-url` o `--grafana-datasource-uid`. Después, salvo en una ejecución de
   prueba, necesita `GRAFANA_TOKEN`.
2. Busca la carpeta `--grafana-folder` por su título, o la crea:
   `folder "<title>" (<uid>) unchanged|created`.
3. Para cada almacén al que escriben sus destinos, en el orden InfluxDB, Elasticsearch, Prometheus,
   PostgreSQL, Graphite, crea la fuente de datos `mikroscope-<almacén>`, la corrige (`updated`) o la
   deja `unchanged`, o adopta la nombrada en `--grafana-datasource-uid` y la deja como está. Después
   pregunta al almacén qué medidas tiene e importa el dashboard `mikroscope-<almacén>` encima de sí
   mismo, en la carpeta.

`forward` registra cada línea en la salida de error tras un prefijo `grafana:`; `dashboards publish`
las imprime en la salida estándar.

Se intenta con todos los almacenes. Uno que falla se informa en una línea propia que lo nombra,
`the datasource for <store>: …` o `the dashboard for <store>: …`, y los que vienen detrás se
publican igual; solo una carpeta que Grafana rechaza detiene la ejecución. `forward` registra
`grafana: could not publish, carrying on without it: <motivo>` una vez por cada almacén que falló y
sigue recogiendo; `dashboards publish` sale con 1. Solo `--influx`, `--elastic`, `--prom`,
`--postgres` o `--sql`, y `--graphite` tienen dashboard: sin ninguno de ellos `dashboards publish`
se detiene con `no sink this builds a dashboard for is configured, so there is nothing to publish`,
y `forward` lo registra como su aviso `grafana: could not publish…` y sigue recogiendo.

| Opción                         | Por defecto  | Variable                                                                    | Significado                                                                                                                                                                   |
| ------------------------------ | ------------ | --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--grafana`                    | vacío        | `MIKROSCOPE_GRAFANA_URL`; en `dashboards publish` y `uninstall`, después `GRAFANA_URL` | el Grafana en el que publicar; vacío no publica nada                                                                                                          |
| `--grafana-folder`             | `mikroscope` | `MIKROSCOPE_GRAFANA_FOLDER`                                                 | la carpeta donde publicar; `--grafana-folder ""` es la carpeta General de Grafana, y una variable vacía se ignora                                                           |
| `--grafana-datasource-uid`     | vacío        | `MIKROSCOPE_GRAFANA_DATASOURCE_UID`                                         | adoptar una fuente de datos existente por uid en vez de crear una, y dejarla intacta; la única forma de publicar `--sql`. Un almacén por ejecución                            |
| `--grafana-datasource-url`     | vacío        | `MIKROSCOPE_GRAFANA_DATASOURCE_URL`                                         | la dirección que consulta Grafana, `host:puerto` para PostgreSQL y una URL para los demás: hace falta para `--prom` y `--graphite`, y sustituye la que darían `--influx`, `--elastic` o `--postgres`. Un almacén por ejecución |
| `--grafana-datasource-sslmode` | vacío        | `MIKROSCOPE_GRAFANA_DATASOURCE_SSLMODE`                                     | `disable`, `require`, `verify-ca` o `verify-full` para la fuente de datos de PostgreSQL, y nada más; vacío toma el modo que nombra `--postgres` si Grafana lo tiene, y `disable` si no |
| `--grafana-dry-run`            | `false`      | ninguna                                                                     | con `--grafana`, imprimir lo que escribiría, sin contactar con ningún Grafana ni necesitar token; `forward` se detiene entonces, antes de recoger, y la rechaza sin un Grafana; `uninstall` la rechaza |

[`uninstall`](https://docs.jmrp.io/mikroscope/es/reference/cli/#uninstall---targets) solo lee `--grafana` y `--grafana-datasource-uid` de estas.

**Un almacén por ejecución** para las dos opciones de fuente de datos: cada una nombra una sola
fuente de datos, y dos almacenes son dos servidores, consultados por dos plugins distintos. Un colector que escribe en
varios almacenes, uno de los cuales necesita una de ellas, se ejecuta sin ella; ese almacén se
publica aparte con `dashboards publish`, con solo su opción de destino y su propio
`--grafana-datasource-url` o `--grafana-datasource-uid`.

Un fallo aquí es un aviso para `forward` y no una negativa a arrancar: las muestras de una hora sin
funcionar no se recuperan, y un dashboard se puede publicar en el siguiente arranque. No borra nada;
lo hace `uninstall --targets dashboard`. `--grafana-dry-run` se ejecuta antes de tocar el router, así
que se puede contestar sin router delante. [Configurar en
Grafana](https://docs.jmrp.io/mikroscope/es/dashboards/import-and-check/#que-lo-haga-el-colector-forward---grafana) dice
qué destinos saben describir su propia fuente de datos y a cuáles hay que decírselo.

## dashboards

```sh
mikroscope dashboards gen
mikroscope dashboards publish --influx http://influx:8181 --influx-db mikroscope --grafana http://grafana:3000
mikroscope dashboards import --store influxdb --datasource-uid <uid>
mikroscope dashboards check  --store influxdb --datasource-uid <uid> --window 1h --end <instante RFC 3339>
```

| Suborden  | Qué hace |
| --------- | -------- |
| `gen`     | escribe los cinco dashboards y los tres ficheros de alertas en `--out`, que crea si no existe; los ficheros solo los puedes leer tú. No contacta con nada |
| `publish` | lo que hace `forward --grafana` al arrancar, una vez, sin router y sin colector: toma las opciones de [destino](https://docs.jmrp.io/mikroscope/es/reference/cli/#destinos) y de [publicación en Grafana](https://docs.jmrp.io/mikroscope/es/reference/cli/#publicar-en-grafana), crea, corrige o adopta la fuente de datos de cada almacén e importa su dashboard, imprime una línea por objeto, y sale con 1 cuando falla algún almacén |
| `import`  | pregunta a la fuente de datos qué medidas tiene, genera el dashboard y lo envía a `/api/dashboards/import` con la sobrescritura activada, a la carpeta General; imprime `imported: <url>`. No crea ninguna fuente de datos |
| `check`   | pregunta y genera como `import`, ejecuta la consulta de cada panel por `/api/ds/query`, imprime una línea por panel y sale con 1 cuando falla algún panel. No escribe nada en Grafana |

`gen`, `import` y `check` admiten las opciones de abajo. `publish` no admite ninguna de ellas, ni
tampoco argumentos: sus opciones son las de destino y de publicación en Grafana de `forward`.

| Opción             | Por defecto        | Variable                                     | La lee            | Significado                                                                                                                         |
| ------------------ | ------------------ | -------------------------------------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `--out`            | `dashboards`       | ninguna                                      | `gen`             | directorio de salida para `mikroscope-<almacén>.json` (cinco) y `mikroscope-alerts-<almacén>.yaml` (tres), que se crea con sus padres |
| `--store`          | `influxdb`         | ninguna                                      | `import`, `check` | `influxdb`, `prometheus`, `postgres`, `graphite` o `elasticsearch`                                                                  |
| `--grafana`        | vacío              | `GRAFANA_URL`, y después `MIKROSCOPE_GRAFANA_URL` | `import`, `check` | URL base de Grafana; el token sale solo de `GRAFANA_TOKEN`                                                                     |
| `--datasource-uid` | vacío, obligatoria | ninguna       | `import`, `check` | el UID de la fuente de datos asociada a `DS_MIKROSCOPE`                                               |
| `--no-probe`       | `false`            | ninguna       | `import`, `check` | no pregunta a la fuente de datos qué medidas contiene; usa los valores compilados por defecto         |
| `--window`         | `15m`              | ninguna       | `check`           | longitud de la ventana de consulta                                                                    |
| `--end`            | ahora              | ninguna       | `check`           | instante RFC 3339 en el que termina la ventana, para comprobar contra una captura que ya ha terminado |
| `--var`            | ninguno            | ninguna       | `check`           | fija una variable del dashboard, `nombre=valor`, repetible: `--var host=router`                       |

`import` y `check` se detienen con `import/check need --grafana, GRAFANA_TOKEN and --datasource-uid`
cuando falta alguno de los tres. Salvo que se dé `--no-probe`, primero preguntan a la fuente de datos
qué medidas contiene; si esa pregunta falla, avisan y siguen con los valores compilados por defecto.
`check` imprime una línea por panel (`ok`, `none` para un panel que se sabe vacío, `FAIL`) y sale con
1 si falla algún panel.

`publish` se detiene con `dashboards publish needs --grafana (or MIKROSCOPE_GRAFANA_URL or
GRAFANA_URL), with the token in GRAFANA_TOKEN` cuando no se nombra ningún Grafana, y con
`dashboards publish needs the sink flags the collector runs with (…)` cuando no se da ninguna opción
de destino, porque cada fuente de datos se describe a partir del destino que escribe en ella. Qué
variable de Grafana lee primero cada suborden está en [Variables de
entorno](https://docs.jmrp.io/mikroscope/es/reference/environment/#grafana). [Configurar en
Grafana](https://docs.jmrp.io/mikroscope/es/dashboards/import-and-check/) pone las cuatro en práctica.

## version

`mikroscope version` imprime `mikroscope` y la identidad de compilación del
paquete [`internal/version/`](https://github.com/jmrplens/mikroscope/tree/main/internal/version). No admite opciones.

## Véase también

- [Variables de entorno](https://docs.jmrp.io/mikroscope/es/reference/environment/): cada variable `MIKROSCOPE_*`, las
  credenciales sin opción y la envlist propia del agente.
- [Instalar con la CLI](https://docs.jmrp.io/mikroscope/es/install/): los verbos de despliegue en el orden en que se
  usan.
- [Grabar, marcar y dibujar](https://docs.jmrp.io/mikroscope/es/record/): qué es una grabación y cómo le llegan los
  marcadores.
- [Ejecutar el colector](https://docs.jmrp.io/mikroscope/es/sinks/): qué hace `forward` con las opciones de arriba.
