Installing the agent
This page answers two questions: what mikroscope install does to your router,
and how you get the router back. install puts a 6.1 MiB
agent image in a container on the router; uninstall removes it again.
On RB5009UG+S+, RouterOS 7.24.2, , a scripted
doctor → install → status → upgrade → uninstall round trip
(make roundtrip, which passes --ephemeral to doctor, install and upgrade) left
the router’s /export byte-identical, its # header lines aside. Every object
install creates carries the comment mikroscope:<name> (managed by mikroscope),
except the envlist and the image file, which cannot; the envlist carries the
tag as its MIKROSCOPE_TAG entry. Nothing is written before it is listed;
removal selects by that tag plus the object’s identity, never by pattern, and is
verified by ownership counts.
Before the first install
Section titled “Before the first install”Three things have to be true on the router, and the tool cannot make any of them
true for you: a container-capable architecture on RouterOS 7.24 or later, the
container package, and device-mode container=yes — the last one needs a
physical button press or a power cycle.
What the router needs covers all three.
mikroscope doctor checks them read-only, in one ssh connect, and prints the
exact command or physical step for anything missing.
One decision comes before the first install and not after it: where the agent
image comes from. A checkout builds it, --agent-tar takes the one the release
publishes, --remote-image has the router pull it, and plan --rsc writes a
script that installs without this CLI at all.
Four ways to install lays the four out.
What install does, in order
Section titled “What install does, in order”-
Gets the agent image. From a checkout, the CLI builds it:
go build .for/ cmd/ mikroscope-agent linux/<arch>(--arch, defaultarm64) withCGO_ENABLED=0, packed into an image tar without Docker, and the build path is relative, so run it from the checkout.--agent-tartakes the tar the release publishes instead, and checks it before it uploads it.--remote-imageskips this step entirely: the router pulls the image itself and nothing is uploaded. Four ways to install is the choice, with what each route needs. -
Prints the plan. One line of options (a token shows as
token=(set), never its value), the tag, then every RouterOS command numbered, with thescpupload and its size before the container step. It ends withnothing above has been written yet.mikroscope planandinstall --dry-runstop here, before any ssh connect. -
Runs
doctor. Any missing prerequisite stops the install withN prerequisite(s) missing; nothing was written.--no-doctorskips this step. -
Asks
write the objects above to the router? [y/N].--yesskips the question. -
Asks the router about every step at once. One connect asks, for each step, whether mikroscope’s object is there and whether the effect exists under any other owner. A step already ours prints
ok … (already present)and is skipped; an effect that exists without the tag stops the install, naming it; an absent one is created, one connect per write. -
Uploads the image and creates the container. The tar goes up with
scp; one command then writes the envlist, adds the container, waits up to 15 s for the container to appear, then 3 s more (RouterOS extracts the image at add time), deletes the tar and starts the container. With--remote-imagethere is no upload and no tar to wait for or delete: the container is added withremote-image=and started. Either way the container is added withprivileged=, which RouterOS knows from 7.24: on an earlier 7.x this is the step that fails, and--privileged=falseis the way through. -
Probes the agent from your host and says which transport works: Reaching the agent.
A second install on a router where every step is already ours creates nothing
and goes straight to the probe.
What install writes to your router
- a veth
- one address
- one interface-list membership
- one address-list entry
- an envlist
- the image tar, unless
--remote-imagehas the router pull the image - the container
Every object carries the comment mikroscope:<name> (managed by mikroscope)
mikroscope plan prints every command before anything is written.
uninstall removes by exact tag plus identity, never by pattern, and fails naming the step if anything remains.
Where each of those objects lives, what the envlist carries and which container settings are written is on Where things go. Why two of them are firewall list memberships is on The two firewall traps.
How ownership is decided
Section titled “How ownership is decided”The tag is the only thing a removal matches on, together with the object’s own
identity: the veth by name, the address by interface, a list membership by list
and interface, an address-list entry by list and address. Neither
/container/envs nor /file carries a comment, so the envlist is signed by an
entry MIKROSCOPE_TAG whose value is the exact tag, and the uploaded image
counts as mikroscope’s only while that marker exists. The agent ignores the
entry.
Every find quotes its address and port attributes. Unquoted, RouterOS parses
them as typed values and the comparison with the stored one comes back empty — an
unquoted dst-port=9123 matches nothing (verified on RB5009UG+S+, RouterOS 7.24.2, ).
Over ssh, RouterOS reports an error as text with exit status 0 and abandons the
rest of a ;-joined line at the first one. A write that prints anything is
therefore treated as a failure. If the container step fails after the upload,
the uploaded tar is taken back (undo removed the uploaded …), because without
the marker it would count as foreign forever. What else the installer refuses is
on What the installer refuses.
Upgrade
Section titled “Upgrade”What upgrade replaces
- a new image and the container
- the envlist, rewritten from the flags
upgradeis given - network objects stay
Every object carries the comment mikroscope:<name> (managed by mikroscope)
mikroscope plan prints every command before anything is written.
mikroscope upgrade gets the image the same way install does — a build from
the checkout, --agent-tar, or --remote-image and no image at all — checks
that every step is present
(otherwise nothing to upgrade: run install first), asks for confirmation,
removes the container step, waits for RouterOS’s asynchronous removal, creates
the step again with the new image and probes the agent. Unlike install, it
prints no plan and runs no doctor: its prompt is the same
write the objects above to the router? [y/N] with nothing listed above it.
mikroscope plan with the same flags shows the container command it will write.
The envlist belongs to the container step, so upgrade writes it again from the
flags upgrade itself is given. --port, --rate, --buffer, --memory-max,
--mem-limit-mb, --capture-mb, --triggers, --floor-hz, --privileged,
--ephemeral and --expose read no environment variable: pass them again or
they return to their defaults. That is also the way to change them without
touching the network objects. Two omissions are not harmless. An upgrade
without --ephemeral re-creates the container with its image and root on the
internal flash and start-on-boot=yes. An upgrade of an --expose install
without --expose and without a token (--token or MIKROSCOPE_TOKEN)
re-creates the agent with no token, while the two LAN firewall rules stay.
Uninstall
Section titled “Uninstall”What uninstall removes
- a veth
- one address
- one interface-list membership
- one address-list entry
- an envlist
- the image tar, unless
--remote-imagehas the router pull the image - the container
Every object carries the comment mikroscope:<name> (managed by mikroscope)
mikroscope plan prints every command before anything is written.
uninstall removes by exact tag plus identity, never by pattern, and fails naming the step if anything remains.
mikroscope uninstall runs the removals newest first. A removal that fails or
prints anything is reported as skip with what the router said, and the rest
continue. A step whose selector finds nothing prints gone just the same, which
is why the count, not the removal output, decides. Then it asks the ownership
count of every step in one connect, prints one line per step, and
either ends with verified: nothing mikroscope created remains on the router or
fails with uninstall left objects behind, naming the steps still present.
The container removal waits, because RouterOS does not: /container/remove
returns before the container is gone, and a /file/remove of the image issued
meanwhile did nothing, silently (RB5009UG+S+, RouterOS 7.24.2, ). So it
stops the container, removes it, waits up to 20 s for it to vanish, retries the
tar removal for up to 15 s, and removes the marker only once the file is gone. If
it is not, the marker stays and the count says so.
Status
Section titled “Status”mikroscope status prints the ownership count of every step, from one connect.
When nothing is installed it ends with the verified line and probes nothing.
Otherwise it probes the agent’s /healthz with a 3 s timeout and prints its
version, rate, sequence and oldest sequence, uptime, slipped ticks and round
trip, then one line about the board: whether this build knows how to turn the
kernel’s port names (eth0, eth1, …) into RouterOS’s on it. Where it does
not, the line asks for the measurement that would add the board; RouterOS ports
and kernel names shows how to take it. If
the agent does not answer, it prints agent: not reachable from this host with
the error, and no board line; status still exits 0.
Day to day
Section titled “Day to day”mikroscope doctor # read-onlymikroscope plan # every command, nothing writtenmikroscope install [--ephemeral] # doctor, confirmation, writes, probemikroscope status # ownership counts + agent healthmikroscope upgrade # new image, container onlymikroscope uninstall # removes and verifiesmikroscope image --arch arm64 # the tar, for side-loading by handmikroscope plan --rsc --out install.rsc # the same writes, as a RouterOS script--router takes user@host or an ssh config alias and is required by every verb
that connects.
Flags and the environment
Section titled “Flags and the environment”For these verbs, the flags that read their default from a variable are
--router, --ssh-port, --ssh-key, --name, --veth, --subnet,
--iface-list, --addr-list, --disk, --arch, --token, --lan-address,
--agent-tar and --remote-image (MIKROSCOPE_ROUTER, MIKROSCOPE_SSH_PORT
and so on); .env.example documents them. The CLI does not read .env itself:
set -a; . ./.env; set +aEvery value that reaches a RouterOS command is bounded before the first
connection: names, disks, the architecture, memory syntax, the token’s
characters, the port and rate ranges, the registry reference, the subnet, which
must be an IPv4 /30 given at its network address, and --triggers, which the
agent’s own parser decides on — an unknown condition, a bad threshold, a quote
or a semicolon fails the verb with exit 2 and writes nothing. The agent parses
TRIGGERS again when it starts, because an envlist can be edited by hand on
the router; a value it rejects there makes it exit and log
bad configuration. The full list is on
Commands and flags and
Environment variables.
What ssh costs the router
Section titled “What ssh costs the router”Each ssh connect costs the RB5009 20–27 % CPU for its duration. So the CLI
batches every read into one connect — doctor is one, status is one, the
state questions of install are one — and each write takes one more, plus the
scp upload. ssh is never a data path: record and forward reach the agent
over HTTP or the RouterOS API.