Building iontoolkit

Strata Cloud Manager has a button that opens a terminal on an ION. I pressed that button while watching what the browser was asking the controller for. The answer was a WebSocket connection that could be used outside of the browser and then scripted against.

That idea became iontoolkit, a Go-based CLI tool I now use for read-only commands across my customer’s fleet of five thousand devices.

F12

Strata Cloud Manager is a front end that makes API calls to the controller. Just about every action you take in the portal is just Strata Cloud manager making calls to api.sase.paloaltonetworks.com.

its all APIs? It always has been!

Among engineers (and even PA product managers!) who work with Strata Cloud, it’s an open secret that the official API documentation is out of date. I knew how Strata Cloud Manager exposes its APIs, so I started by pressing F12 and watching what it sends when the toolkit button gets pressed.

Strata Cloud Manager makes two API calls when you hit the toolkit button:

GET  /sdwan/v3.2/api/elements/{eid}
WSS  /sdwan/v2.0/api/elements/{eid}/ws/toolkitsessions?cols=84&rows=63

The GET checks the ION before the portal tries to connect.

The WebSocket is the interesting part. That’s the Toolkit session.

Let’s see if I can just curl it

1234-5678910 Login:
Login timed out after 60 seconds.

That’s promising. The ION picked up, printed a login prompt, waited a minute for a human, and hung up. curl opened the socket and received the prompt, but it was not acting as an interactive terminal client, so nothing framed my keystrokes into WebSocket messages and nothing I typed reached that prompt.

I knew that I could get the ION’s CLI into my console.

Using the prompt as the delimiter

Once I could talk to the ION, I needed to know when a command was finished.

I couldn’t just wait for the socket to become quiet. coder/websocket treats a read deadline as fatal, so using silence as the delimiter just kills the connection.

I decided to use the device hostname prompt as a delimiter. Every ION has a predictable hostname, and I sent the command. I can look for the hostname and command, then wait until the hostname returns. Everything that shows up while waiting is command output.

hostname# {your command}
command output
hostname#

The raw terminal output is full of ANSI control sequences and redraw garbage. Claude wrote the cleanup code for that part. I know what goes into it and what comes out of it, but the regex in the middle is still mostly AI magic. Thanks, AI.

This was my first Go project. The first working version that was able to remotely execute commands and return their output took me about 12 hours, and most of that time was spent working with the Palo Alto controller, not fighting the language.