Salvaguardas del instalador
El instalador escribe en un router que no configuró él, por la propia sesión ssh de administrador
del operador, así que no hay ninguna frontera de privilegios entre un error y el router. Lo que hace
sus veces es un conjunto de rechazos: dónde se detiene install antes de escribir, qué no toca, qué
trata como un fallo, y cómo uninstall demuestra que ha terminado en vez de limitarse a decirlo.
Listado antes de escribir
Sección titulada «Listado antes de escribir»install no escribe nada hasta haber impreso cada orden que ejecutaría, con su texto exacto de
RouterOS. En este orden:
- ejecuta
doctor, la comprobación previa de solo lectura, en una sola conexión ssh, salvo que se dé--no-doctor; un requisito que falte lo detiene conN prerequisite(s) missing; nothing was written. Una líneaWARNse imprime y no lo detiene. Con--no-doctor, sin--archy sin--remote-image, una conexión de una sola lectura toma en su lugar la arquitectura del router, y la salida lo dice; - construye o carga la imagen de la arquitectura que informó el router (
--agent-tartiene que coincidir con ella;--remote-imagedeja la elección a RouterOS); - imprime el listado, con el token enmascarado como
value="(token)"; - pregunta
write the objects above to the router? [y/N], salvo que se dé--yes; cualquier cosa que no seayoYlo detiene connot confirmed; nothing written; - solo entonces escribe, el manifiesto de la instalación el primero.
plan, install --dry-run y upgrade --dry-run se detienen después del listado y no abren
ninguna conexión.
upgrade no ejecuta doctor. En una sola conexión lee la forma con la que se hizo la instalación
(su manifiesto, o sus objetos etiquetados para una instalación que no lo tiene), si están todos los
pasos, la arquitectura del router y, con --remote-image, la comprobación de credencial de registro
de doctor, que imprime; cuando la forma que lee cambia el plan que daban las opciones, una segunda
conexión pregunta por los pasos de ese plan. Rechaza un router sin instalación (nothing to upgrade: run install first)
y una instalación cuya envlist tiene un TOKEN si no recibe --token. Lista el manifiesto de la
instalación, que escribe siempre el primero, y el paso del contenedor; cualquier otro paso de la
instalación que el router ya no tenga se lista después y se crea antes del contenedor. Después hace
la misma pregunta. Con y quita el contenedor, la envlist y la imagen y los vuelve a
escribir, la envlist a partir de las opciones dadas a upgrade.
Lo que install escribe en tu router
- el manifiesto de la instalación, un fichero
mikroscope/en el disco de la instalación que lista las opciones y cada objeto de abajo<name>. manifest.txt - 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-imagehaga 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.
Objetos ajenos
Sección titulada «Objetos ajenos»doctor nombra los objetos con los que chocaría una instalación antes de escribir nada: una veth,
una envlist o un nombre de contenedor que no son de esta instalación, un fichero en la ruta del
manifiesto de la instalación que no es su manifiesto, y una ruta que se solapa con la /30. Después, antes de escribir, install hace al router tres preguntas sobre cada paso en una
sola conexión ssh: ¿está nuestro objeto?, ¿existe algo con el mismo efecto?, ¿lleva nuestra
etiqueta? Un objeto que existe pero no lleva la etiqueta de mikroscope detiene install, nombrando
el paso:
veth interface veth-mikroscope exists on the router and was not created by mikroscope (no ownership tag); pick another --name/--veth/--subnet, or remove it by hand if it is yours; nothing was writtenLo que cuenta como «el mismo efecto» es la identidad del objeto, no solo su nombre:
| Paso | Choca con cualquier existente | Es nuestro cuando lleva |
|---|---|---|
| manifiesto de la instalación | un fichero en mikroscope/ en el disco de la instalación |
su línea tag= con la etiqueta |
| veth | /interface/veth con el mismo nombre |
la etiqueta en comment |
| dirección del router | /ip/address en esa veth |
la etiqueta en comment |
| pertenencia a la lista de interfaces | miembro con esa interfaz en esa lista | la etiqueta en comment |
| pertenencia a la lista de direcciones | entrada con la /30 en esa lista | la etiqueta en comment |
| dst-nat de expose | regla dstnat con esa dirección de destino, puerto y protocolo |
la etiqueta en comment |
| accept en forward de expose | regla forward con la dirección del contenedor, ese puerto y ese protocolo |
la etiqueta en comment |
| contenedor | un contenedor en la misma veth, una envlist llamada <name>-env, un fichero en la ruta de la imagen o un contenedor llamado como --container-name |
un contenedor con la etiqueta; una envlist con la marca |
Desliza en horizontal para ver todas las columnas
Un paso que ya es nuestro se salta, así que ejecutar install dos veces no crea nada la segunda vez.
install tiene todas las respuestas antes de su primera escritura, así que un objeto ajeno en
cualquier paso lo detiene sin haber escrito nada, también con --no-doctor. uninstall nunca toca
el objeto ajeno.
Objetos sin etiqueta
Sección titulada «Objetos sin etiqueta»Ni /container/envs ni /file tienen campo de comentario, así que la instalación los firma de otra
manera. El manifiesto lleva la etiqueta en una línea tag= y es de esta instalación solo mientras
la lleve. En el paso del contenedor, la primera entrada que se escribe en la envlist es MIKROSCOPE_TAG con la etiqueta
exacta, y el fichero de imagen cuenta como nuestro solo mientras exista esa marca. Una envlist ajena
con el mismo nombre, un fichero ajeno en la ruta de la imagen o la envlist de otro contenedor son,
por tanto, ajenos, y detienen install. Los restos de una instalación anterior de mikroscope — una
envlist bajo nuestra marca sin contenedor — son nuestros para sustituirlos, e install los limpia
antes de escribir los nuevos.
Selectores exactos
Sección titulada «Selectores exactos»Todo objeto que crea install lleva el comentario mikroscope:<name> (managed by mikroscope), al
pie de la letra. Todo objeto de red se elimina por ese comentario exacto junto con la identidad
que usó su comprobación — comment="…", nunca una coincidencia por patrón. El contenedor se elimina
solo por el comentario, y la envlist y la imagen, que no llevan comentario, por list="<name>-env"
y el nombre exacto del fichero de imagen, solo mientras exista la entrada de marca con la etiqueta
exacta; el manifiesto, la raíz del contenedor y el directorio mikroscope, por sus rutas exactas,
que derivan de --name y --disk. Así que uninstall no puede alcanzar una instalación hecha a mano, ni nada cuyo comentario
o nombre comparta una subcadena con el nombre del contenedor.
Todo find pone entre comillas cada valor no numérico salvo los enumerados chain y action. Sin
comillas, una dirección o un puerto se interpretan como valores tipados y la comparación con el
valor guardado sale vacía. Una palabra suelta como tcp se lee como el nombre de una variable,
cuyo valor sin definir es vacío, así que find chain=dstnat protocol=tcp no coincide con ninguna
regla mientras que protocol="tcp" coincide con todas las de TCP.
Errores de escritura
Sección titulada «Errores de escritura»Una escritura de RouterOS no imprime nada cuando tiene éxito, y por ssh informa de los errores como
texto, con estado de salida 0 o 1, abandonando el resto de una línea unida con ;. Así que
install trata cualquier salida de una escritura como un fallo
(create <step>: router said "…") y se detiene ahí. Cuando ssh sale con un estado distinto de
cero, el error empieza por lo que imprimió RouterOS, así que sus palabras sobreviven donde solo se
muestra la primera línea de un error, como en las líneas skip de uninstall.
El tar de la imagen se sube con scp antes de que se ejecute el paso del contenedor, y antes de que
exista la marca. Si ese paso falla después, install borra el fichero subido
(undo removed the uploaded …); de lo contrario contaría como fichero ajeno en cada intento
posterior. El tar se queda cuando ya lo tiene un contenedor de esta instalación — el paso se detuvo
en su espera de la extracción, y RouterOS puede seguir extrayéndolo (keep …) — y uninstall
retira los dos juntos. El plazo de ssh para una orden es de 3 minutos, o el --extract-timeout y un
minuto más cuando eso es mayor, así que la espera de la extracción termina con su propio mensaje y
no con ssh interrumpido.
uninstall lee la salida de la misma manera en sentido contrario: una eliminación que imprimió algo
se informa como skip, no como gone.
Límites de entrada
Sección titulada «Límites de entrada»Toda opción que llega a una orden de RouterOS se interpola en ella tal cual. No hay privilegio que escalar — la orden se ejecuta como tu administrador — pero unas comillas o un punto y coma convertirían un error claro en un confuso error de sintaxis de RouterOS, o un selector en algo más amplio de lo pretendido. Por eso cada valor se comprueba antes de la primera conexión, y uno fuera de estos límites detiene la orden con la regla que ha incumplido:
| Opción | Se acepta |
|---|---|
--name |
^[A-Za-z0-9][A-Za-z0-9_. |
--veth |
^[A-Za-z0-9][A-Za-z0-9_. |
--iface-list, --addr-list |
^[A-Za-z0-9][A-Za-z0-9_., o none para no unirse a ninguna lista; --iface-list rechaza las listas integradas de RouterOS all, dynamic y static, que no admiten miembros |
--container-name |
^[A-Za-z0-9][A-Za-z0-9_., o vacío para el nombre que ponga RouterOS |
--disk |
^[A-Za-z0-9][A-Za-z0-9_, o vacío para la flash interna; --ephemeral fuerza tmpfs |
--arch |
arm64, arm, amd64 o auto |
--token |
^[A-Za-z0-9_.-]{0,128}$ |
--subnet |
una /30 IPv4, escrita como su dirección de red |
--port |
1–65535 |
--rate |
1–100 Hz |
--buffer |
10–3600 s |
--memory-max |
^\d{1,6}[KMG]?$ |
--mem-limit-mb |
8–1024 |
--floor-hz |
0–1000 |
--capture-mb |
0–256 |
--restart-max-count |
0–100 |
--restart-interval |
^\d{1,4}[smh]$ |
--start-on-boot |
auto, yes o no |
--extract-timeout |
^\d{1,4}[smh]$, 10–600 s |
--expose |
necesita --lan-address como dirección IPv4; install, upgrade y plan necesitan además un token no vacío |
--triggers |
la propia lista de condiciones del agente, interpretada por agent.ParseTriggers |
--remote-image |
una referencia de registro: owner/name:1.0.0, con host o sin él, sin comillas, espacios ni punto y coma |
--ssh-option |
una clave entre StrictHostKeyChecking, UserKnownHostsFile, ConnectTimeout, HostKeyAlgorithms, PubkeyAcceptedAlgorithms, IdentitiesOnly y ServerAliveInterval, y un valor que cumpla ^[A-Za-z0-9_./ |
Desliza en horizontal para ver todas las columnas
--ssh-option no llega a RouterOS sino a las líneas de órdenes de ssh y scp, y rige la misma regla:
ninguna clave que ejecute una orden o lea un fichero como configuración (ProxyCommand,
LocalCommand, Include), para que un valor en un fichero de entorno no pueda convertirse en
ejecución de órdenes. Sus opciones van antes de las propias de la CLI,
-o BatchMode=yes -o ConnectTimeout=15, porque ssh se queda con el primer valor que lee de cada
opción.
No hay excepción. --triggers la comprueba la misma puerta que el resto: Finish se la pasa a
agent.ParseTriggers, el propio intérprete del agente, que es la autoridad sobre lo que significa
una condición. Una condición desconocida, un umbral mal formado, unas comillas o un punto y coma
hacen fallar el verbo con estado de salida 2 antes de la primera conexión, y no se escribe nada.
El agente vuelve a interpretar TRIGGERS al arrancar, porque la envlist se puede editar a mano en
el router. Ante un valor que no puede interpretar sale con un estado distinto de cero y una línea
mikroscope-agent: bad configuration: … en el log del router; con la política on-failure, RouterOS
lo reintenta hasta --restart-max-count veces.
Comprobaciones de la imagen
Sección titulada «Comprobaciones de la imagen»Dos de las cuatro vías de instalación entregan al router algo que la CLI no ha construido, y cada una tiene su propia comprobación antes de que se escriba nada.
--agent-tar <fichero>, el tar de imagen que publica la release, se lee e inspecciona primero en tu máquina. Tiene que ser un tar de tipo docker-save con exactamente una imagen de una sola capa cuyo entrypoint sea/mikroscope-agent, y su arquitectura tiene que coincidir con la del router (que leedoctor) o con un--archexplícito; si no, el verbo se detiene, y ante una discrepancia nombra el recurso que hay que descargar (--agent-tar … is a linux/arm64 image and the router is arm: download the mikroscope-agent-armv5.tar asset instead, conarmv7para--goarm 7). Esa comprobación dice que el tar es una imagen del agente de mikroscope de la arquitectura correcta. No dice que sea el tar que publicó la release: verifícalo contrachecksums.txtde la release, y su firma cosign si la usas, antes de pasarlo.--remote-image <referencia>hace que el router se descargue la imagen él mismo, así que no se sube nada y ningún tar acaba en el dispositivo. La referencia se contrasta con un patrón de referencia de registro antes de llegar a la línea de órdenes, porque RouterOS la recibe dentro de una cadena entrecomillada en una línea unida por;. Va entera enremote-image=, con el host del registro incluido: una referencia sin host, o con un alias de Docker Hub, pasa a serregistry-1.docker.io/…, y cualquier otro host se conserva. Después el router necesita alcanzar ese registro por su propia red. mikroscope nunca escribe/container/config, el ajuste global que guarda elregistry-urldel equipo y su único usuario y contraseña de registro, y no necesita nada de él: el host dentro deremote-image=manda sobreregistry-url(Ajustes del registro). Confiar en la imagen es confiar en ese registro: nada en la CLI verifica lo que el router se descarga. Cuando hay un usuario puesto, RouterOS lo presenta al registro que nombraregistry-url, y una credencial pensada para otro registro puede terminar enauth errorla descarga de una imagen pública.doctoravisa cuando hay un usuario puesto yregistry-urlestá vacío o nombra un host distinto del que viene la imagen (WARN no registry credential meant for another registry), yupgradeimprime la misma comprobación antes de retirar nada; los dos leenregistry-urly solo si hay un usuario puesto, nunca el nombre. La contraseña no se puede leer en absoluto.--agent-tarno descarga de ningún registro, así que no se envía ninguna credencial de registro.
Scripts y tokens
Sección titulada «Scripts y tokens»plan --rsc escribe la instalación como un script de RouterOS para un router al que solo llegas por
WinBox o WebFig. Lleva las mismas órdenes que ejecuta install, en el mismo orden, con las mismas
etiquetas y el mismo manifiesto de la instalación, así que uninstall retira una instalación hecha
por script tan por completo como una propia. Se ejecuta como un solo bloque cuyas guardas lo
detienen antes de su primera escritura en un router que no puede recibirlo: por debajo de RouterOS
7.24, sin el paquete container o sin device-mode, sin el tar en la vía del tar, o con una veth, una
envlist, un contenedor de --container-name o un fichero en la ruta del manifiesto con los nombres
de la instalación que no son de mikroscope. Una envlist sin la marca de mikroscope recibiría si no
la marca, y uninstall retiraría después con ella las entradas que guarda. Y, cuando --token o
MIKROSCOPE_TOKEN está fijado, la línea de la envlist lleva el token en claro, porque el router lo necesita. El propio script lo dice en su cabecera. Trata el
fichero como tratas el token: no lo subas a un repositorio, no lo pegues donde quede registrado y
bórralo de los Files del router después del /import. Sin token no guarda ningún secreto, solo el
plan. Pégalo solo en el indicador ] >: un script pegado mientras RouterOS pregunta por la licencia
pierde sus primeras líneas. Script de RouterOS y el Generador de
scripts muestran las dos formas de ejecutarlo.
plan, install --dry-run y upgrade --dry-run enmascaran el token en lo que imprimen por el
terminal (value="(token)"); --rsc no puede, porque el script tiene que ejecutarse.
Las órdenes de la propia CLI nunca ponen el token en una línea de órdenes de esta máquina: la orden
de RouterOS que lo escribe le llega a ssh por su entrada estándar, así que no aparece en la tabla de
procesos mientras se ejecuta ssh. La CLI lo lee de --token o de MIKROSCOPE_TOKEN; la variable lo
mantiene también fuera de la línea de órdenes de la propia CLI.
Verificación de uninstall
Sección titulada «Verificación de uninstall»uninstall retira todo lo que creó la instalación, y nada más.
- Lee el manifiesto de la instalación,
mikroscope/, en la conexión que lee la forma de la instalación, y toma de él la forma con que se hizo; rechaza una opción que la contradiga, nombrando los dos valores. Una instalación hecha antes de que existiera el manifiesto no tiene ninguno, y su forma se lee de sus objetos etiquetados.<name>. manifest.txt - Ejecuta cada eliminación de la más reciente a la más antigua, ignorando lo que ya no está. El
paso del contenedor, una vez retirado el contenedor de esta instalación, retira la raíz del
contenedor
mikroscope/<name>si RouterOS la dejó. - Elimina, por la etiqueta exacta y nada más amplio, cualquier otro objeto que lleve la etiqueta de la instalación en los menús donde escribe una instalación, y en cualquier otro menú que liste el manifiesto.
- Elimina el manifiesto el último: primero la raíz del contenedor, si queda una, ningún contenedor
la usa y el manifiesto es de esta instalación, después el manifiesto, y después el directorio
mikroscopecuando no queda nada más en él. Un/file/removede un directorio se lleva todo lo que hay debajo, así que un directorio con cualquier otra cosa dentro se queda. Una ruta solo se borra con la palabra del contenedor etiquetado o del manifiesto; sin ninguno de los dos, una raíz que ningún contenedor usa se informa, no se borra. - Pregunta al router, en una sola conexión, cuántos objetos de cada paso siguen ahí, cuántos llevan
la etiqueta en cada menú además de los que contaron esos pasos, y si está alguna ruta que lista
el manifiesto; imprime una línea por paso con la cuenta y falla nombrando cada paso, menú o ruta
que quede (
uninstall left objects behind: …). Una eliminación que no imprimió nada no es una prueba; la cuenta sí.
status hace esa misma cuenta de forma independiente, en la conexión que lee la forma de la
instalación.
Lo que uninstall nunca toca: device-mode, el paquete container, /container/config, ni ninguna
lista, disco, regla o fichero que el router ya tuviera antes de la instalación, incluido un
directorio mikroscope con otros ficheros dentro. Un directorio mikroscope vacío en el disco de
la instalación se borra aunque estuviera antes de la instalación: nada en él dice de quién es, y
borrarlo no se lleva nada consigo.
El paso del contenedor es el lento, y el orden dentro de él es lo que mantiene honesta la cuenta:
- el contenedor se detiene (con guarda, porque detener un contenedor detenido es un error), y
uninstallespera, hasta 30 s, a que RouterOS lo informe ni en marcha ni deteniéndose: RouterOS se niega a eliminar un contenedor que aún se está deteniendo (cannot remove running), y quita la marca de en marcha antes de que se haya detenido; /container/removevuelve antes de que el contenedor haya desaparecido, y un/file/removede la imagen lanzado entretanto no hace nada, en silencio, así que espera hasta 20 s a que el contenedor desaparezca, y luego reintenta la eliminación del fichero durante hasta 15 s;- se va el resto de la envlist, y la marca se va la última, solo cuando el fichero ya no está.
Si la eliminación del fichero no surte efecto, la marca se queda, la cuenta sigue incluyendo la
envlist y el fichero, y uninstall lo dice en vez de informar de que está limpio.
El laboratorio virtual de
RouterOS lo comprueba para
cada vía de instalación, y para una instalación sin manifiesto: después de uninstall, el /export
del router es igual al tomado antes de la instalación, y /file no lista ninguna ruta de
mikroscope.