App Dev · · 5 min read
NetLay: Cabinets, switches and a map that pings itself
The first working NetLay build, a map you can drag things around on, a data model that refuses to double book a port, and a pinger that had to be taught Windows lies.
From an empty folder to a live map#
Last week I introduced NetLay, the map of the building with every cabinet, switch and port on it. This week is the first build, which went from an empty folder to something genuinely useful in an afternoon, and then took considerably longer to stop being wrong.
Choosing the shape.#
The first decision made itself. The map has to ping things, and a browser cannot send an ICMP packet no matter how nicely you ask it, so there has to be something running outside the browser. That meant a small server, and once you have a small server you may as well let it hold the data too.
So the back end is FastAPI with SQLModel on top of SQLite, and the front end is React and TypeScript built with Vite, using zustand for state and plain SVG for the map. No diagramming library. I looked at a few and they all wanted to own the interaction model, and the interaction model is most of what makes this thing feel like a map rather than a form with pictures.
A desktop application would have been the obvious alternative and I decided against it for now, mostly because the moment two people want to look at the same map, a web app has already solved a problem the desktop version would be starting on.
The gotcha that ate an afternoon.#
Pings go out through icmplib, which can send unprivileged ICMP so nobody needs to run this as an administrator. When that isn't available it falls back to running the operating system's own ping command and reading what comes back.
That fallback is where the afternoon went. On Windows, ping exits with status code zero when the destination is unreachable. It prints "Destination host unreachable", it clearly knows perfectly well that it failed, and it still hands back a zero like everything is fine. If you trust the exit code, which of course I did, every device on your map goes green and stays green, which is the single worst failure mode available to a monitoring tool.
So the fallback now parses the actual output and looks for TTL=. If there is a TTL in the reply, something answered. If there isn't, it didn't, whatever the exit code claims.
The data model, first cut.#
Layout, then cabinet, then switch, then the devices on the end of it. The one constraint I put in on day one is that the pair of switch and port has to be unique, so a port can only ever have one thing plugged into it. That sounds obvious written down. It is also the rule that every spreadsheet I have ever inherited was quietly breaking.
Everything on the map has world coordinates and the canvas pans and zooms over the top of them, so dragging a cabinet across the plan is just moving a number, and the cables follow because they are drawn between the two ends rather than stored anywhere.
The map#
You can pan and zoom, drag things where you want them, and every device draws a line back to the cabinet it belongs to. Behind it all you can drop in a floor plan image, or leave the plain grid if you haven't got one to hand.
The status side of it is the part I enjoyed. A background pinger works through the devices and pushes the results to the browser over a WebSocket, so dots turn green or red and the line to a dead device goes dashed without the page asking for anything. There is a small live badge in the toolbar so you can tell the difference between "everything is fine" and "the thing that tells you everything is fine has fallen over", which is a distinction I have cared about ever since a dashboard lied to me for a weekend.
It polls every thirty seconds by default with a one second timeout, thirty two pings in flight at once, and a five second floor on the interval so nobody can accidentally turn it into a packet flood. There is a Ping all button for when you don't want to wait.
At launch it knew about printers, UPSs, access points, cameras, PCs, servers and a general purpose "other", which covers most of what is actually hanging off a switch in a small office.
Small things that turned out to matter.#
A layout exports to a single JSON file, and the floor plan image goes inside it as base64 rather than sitting alongside as a second file to lose. One file is a thing you can email to somebody. Two files is a thing somebody will send you half of.
Every device gets an Open link that goes to its web interface, defaulting to http:// and the address. It is a two line feature and it is the one I use most days, because half of what you do with a printer or a UPS is open the thing's own page.
What was already wrong#
Two things, and both of them are the next post.
Cabinets were drawn as a box with a summary inside it, so many switches and so many ports used out of so many. The switches themselves were not on the map at all, which is fine right up until a cabinet has three of them and you need to know which one you are talking about.
Worse, ports were integers. Port 17. Anybody who has spent time in front of a Cisco switch has just winced, because the real name of that port carries the stack member, the module and the number, and all three of those matter when you are stood in front of the rack. That one has bothered me since the day I typed it.
Try it yourself#
The portable build is up, so you can have a look at the thing I have been describing rather than taking my word for it.
NetLay portable v0.1.0 (51.5 MB)
It is Windows 10 or 11. Unzip it anywhere you like and run start.cmd. There is no installer, it does not need administrator rights, and it does not need the internet, because Python is bundled inside the folder along with the built web interface. It will ask whether you want it on this PC only or shared with the rest of the network, and it remembers what you told it. The default address is http://localhost:8010.
It ships with an empty database and no accounts, so the first person to open it creates the admin login. That also means there is nothing of mine in it, which is the way I would want it if somebody handed me a zip file.
Next time, teaching it to name ports the way the switch does, and putting the switches themselves on the map where they belong.