Skip to Content
IoT App DevelopmentIronFlock CLIFlags, Output & Exit Codes

Flags, Output & Exit Codes

These rules hold for every ironflock command, and a script can rely on them. The page of each command names only what the command adds.

A command line has one of two shapes:

ironflock <group> <verb> [flags] ironflock agent install -c device.flock ironflock <verb> [flags] ironflock version

The group is the product: agent for the device agent, appliance for the IronFlock appliance, os for IronFlockOS. A verb means the same in every group. Commands about the machine as a whole have no group. ironflock and ironflock <group> without a verb print their help. No command takes positional arguments unless its page says so; everything else is a flag. login and device are reserved names: they answer that they are reserved, with exit code 2.

Global Flags

Every command accepts these flags. All of them but --help may stand before or after the command’s name: ironflock --json version and ironflock version --json are the same.

FlagMeaning
--download-base <url>Base URL of the downloads. Default: the IronFlock cloud, https://instance-registry.ironflock.com/dl; for a device of an IronFlock appliance, some commands take the appliance’s mirror first. See Download Base.
--host [user@]machineRun the command on that machine over SSH instead of here. Give it more than once for several machines. See Remote Machines over SSH.
--hosts <file>Run the command on each machine the file names, one [user@]machine per line. See The Hosts File.
--parallel <n>Run at most n of the machines of --host and --hosts at once. Default 10, from 1 to 100.
--jsonWrite the result to stdout as one JSON object, and ask nothing.
--yesAnswer the command’s question with yes. It never lifts a refusal.
-h, --helpPrint the help of the command.

Flags with Fixed Names

A flag name means the same in every command that has it. -c and -d are the only short flags besides -h.

FlagMeaningCommands
-c, --config <file>the device’s .flock fileagent install, agent configure, doctor, os flash, os install, os reset
-d, --drive <drive>the drive a command writes toos flash
--disk <disk>the disk the running system started from, which the command replacesos install
--output <file>the file a command writes instead of a driveos flash
--http-proxy, --https-proxy, --no-proxythe corporate proxyagent install, agent configure, os install
--proxy-password-file <file>a file or a pipe whose one line is the password of the user in the proxy URLsagent install, agent configure, os install

Download Base and Proxy

The download base comes from --download-base, then from the environment variable IRONFLOCK_DL_BASE, else it is https://instance-registry.ironflock.com/dl. Without either, agent install, doctor, os install and os update take the download mirror of the appliance that the device’s .flock file names, before the cloud (Devices of an IronFlock Appliance).

The proxy comes from the flags, then from HTTP_PROXY, HTTPS_PROXY and NO_PROXY (or their lower-case forms). agent configure is the exception: it changes the proxy of the device with its flags alone, and the environment of the command changes nothing there. A proxy URL looks like http://proxy.example.com:3128; https:// and socks5:// work too, and a URL without a scheme is http://. When the proxy wants a login, the URL names the user, as in http://[email protected]:3128, and --proxy-password-file gives the password (see Secrets). For devices behind a proxy, see Behind a Corporate Proxy.

Output and JSON

stdout carries the result and nothing else. That is one short text for a person, or with --json exactly one JSON object on one line. --help goes to stdout as well. The one exception is agent logs, whose result is the log: with --json it writes one JSON object per line of the log.

stderr carries everything else: progress, the output of the tools a command runs (apt, the Docker installer), warnings, questions and errors.

So a redirect or a command substitution gets the result alone, and a script that wants silence redirects stderr:

# The result as text in a file; progress and warnings still show on the terminal ironflock status > result.txt # The result as JSON in a shell variable, without the messages on stderr result=$(ironflock status --json 2>/dev/null)

Field names in JSON are snake_case. A result has the field action when the command changed something, for example "installed", "configured" or "removed". Fields are added over time, and none is renamed or removed within a major version. A program that reads a result ignores the fields it does not know. With several machines, --json writes one line per machine instead (see Remote Machines over SSH).

Progress

A long step shows on stderr how far it is: a bar on a terminal, otherwise a line at every tenth. With --json, stdout still gets exactly one JSON object, the result, and stderr gets the progress as events, one JSON object per line:

{"event":"progress","phase":"writing","done":104857600,"total":412345678}
FieldMeaning
eventprogress
phasedownloading an image file or a release; checking its SHA-256 against the catalog; preparing the write of os install from the image; writing it to the drive (or the file of --output); verifying the drive (or the file) by reading it back; installing a release into the other slot (os update)
done, totalBytes: of the image file for downloading, checking, preparing and writing, of the image written for verifying. For installing, percent: total is 100.

os install reads the image file twice before the restart: checking compares its SHA-256 with the signed catalog, and preparing unpacks the image once to find its IRONFLOCKOS partition, put the device’s .flock file and the network settings into it, and compute the checksums of what the write puts on the disk. On a terminal they show as Checking and Preparing.

An event comes when a phase starts (done is 0), whenever the whole percent changes, and when the phase is complete (done equals total). A download that resumes jumps to the bytes it has. Other lines on stderr, warnings among them, are text for a person: a program takes the lines that parse as JSON objects and skips the rest.

Questions and Confirmation

A command that changes the machine says first what it will do, then asks:

  • A command that removes or overwrites something says first what goes. A command that installs says first what it will install. agent stop says first what stopping the agent ends.
  • --yes answers every question of the command with yes, and takes the default where the command offers a choice.
  • At the terminal, a question preselects “Yes”, so Enter alone goes on. Three questions preselect “No”, so Enter alone erases and removes nothing: os flash before it erases a drive, os flash before it replaces the file of --output, and agent remove.
  • os reset asks you to type the device’s name, and os install the machine’s host name. Anything else, Enter alone too, answers no.
  • What you typed before a question appeared is discarded. A question is answered after you have read what the command says.
  • Esc answers no: the command changes nothing and ends with exit code 4. Ctrl-C at a question gives no answer, not even the preselected one: the command changes nothing and ends with exit code 130.

A question needs a terminal on both stdin and stderr. Without one (a pipe, CI, a cloud-init script), the command does not wait and does not guess: it ends with exit code 4 and says that --yes confirms. The same holds with --json, which asks nothing. Scripts therefore give --yes together with --json.

--yes never lifts a refusal. When a command refuses (exit code 3, or a check that failed), no flag makes it go on. Each command’s page lists what it refuses. The one exception is an internal disk, which os flash --allow-internal writes when --drive names it.

Over --host, the questions reach you when you run the command at a terminal. On several machines at once nobody is asked, so a command that asks runs there only with --yes (see Remote Machines over SSH).

Root Privileges

A command that changes the system needs root. Without root it ends with exit code 3 and says so. It does not call sudo itself; only --host does, on the other machine. os flash names the command line to type then, with sudo in front.

CommandsRoot
version, completion, os images, os drives, every --helpnot needed
status, doctornot needed. Without root, status says unknown (needs root) for what it cannot read, and doctor marks such checks skipped. With sudo they read it.
agent install, agent configure, agent update, agent remove, agent restart, agent stop, agent startneeded
agent logsneeded: it only reads, but what it reads is root’s alone
os flashneeded to write a drive. Not needed with --output. On macOS, a user who may write the drive’s raw device needs no root.
os install, os update, os rollback, os resetneeded
self-updatewrite access to the folder of the binary, and the binary’s owner and a member of its group, or root. For /usr/local/bin/ironflock that is root

Over --host, a command that needs root runs through sudo on the other machine when the login is not root.

Secrets

No command prints a secret: not the secret of a .flock file, not a WiFi passphrase, not a proxy password, not a license key. That holds for stdout, stderr, --json and error messages.

A secret is never the value of a flag where a file can carry it, because command lines show up in ps and in the shell history. A proxy password is no exception:

  • A proxy URL in a flag names the user without the password: http://[email protected]:3128.
  • A URL with a password, such as http://user:password@proxy:3128, is a wrong command line (exit code 2). It is refused before anything runs, and with --host before it goes to the machine. The error does not repeat it.
  • The password comes from --proxy-password-file: a file, or a pipe (/dev/stdin), of one line.
  • The proxy variables of the environment, which agent install falls back to, may carry a password: they are not on a command line.
# The password from a file sudo ironflock agent configure --https-proxy http://[email protected]:3128 --proxy-password-file proxy-password.txt # The password through a pipe sudo ironflock agent configure --proxy-password-file /dev/stdin --yes < proxy-password.txt

On a device that agent install set up, the proxy password is where only root reads it: in /etc/ironflock/proxy.env (mode 0600). The drop-ins of docker.service and of ironflock-device-agent.service name that file and hold no proxy setting, so systemctl show tells every user the file’s name and nothing of what it holds.

Over --host, a .flock file, a WiFi passphrase file or a proxy password file named in a flag goes to the other machine over the SSH connection, never on a command line (see Remote Machines over SSH). A download base with a login in it ends with exit code 2 before any machine is reached.

Exit Codes

CodeKindMeans
0done
1failedthe command started and could not finish
2usagethe command line is wrong: an unknown command or flag, a missing flag, a reserved name. Nothing was touched.
3preconditionthe machine is not in the state the command needs: not root, no agent installed, an agent installed already, a system the command does not run on. Nothing was touched.
4declinedthe question was answered with no, or it could not be asked and --yes was not given
130interruptedinterrupted (Ctrl-C) before the command finished; with --host also a command on the other machine that ended with a hangup, an interrupt or a termination signal
255sshthe SSH connection of --host failed: the machine was not reached, or the connection broke

An error is one line on stderr, Error: followed by the message. A usage error is followed by a line that names the --help to read. With --json the error is the result: stdout gets an error object, and stderr gets no error line. kind is one of the kinds in the table.

{"error":{"kind":"precondition","message":"the agent is not installed on this machine"}}

Two commands write their result and end with exit code 1 all the same. agent update does so when the agent stays at its version: the result says why, and stderr gets the Error: line. doctor does so when a check failed: the result says which, and no error line follows. With --json, neither writes an error object then: stdout has the result.

With --help, an unknown command is no error: ironflock os nosuch --help prints the help of ironflock os, with exit code 0. On several machines, the command ends with the worst exit code of the machines (see Remote Machines over SSH).

Interrupts

Ctrl-C, SIGTERM, and SIGHUP (when the terminal or the SSH session goes away) end most commands at once, as they end any program, without an error line; the shell sees 130 (143 after SIGTERM, 129 after SIGHUP). Some steps handle them:

  • os flash while it downloads, writes or reads back an image, and os update while it downloads and checks a bundle, stop at the next block. They say what they left, as an error of the kind interrupted, and end with 130; os update then installs nothing. Once os flash has read back the last block, its closing steps finish and it ends with 0. A second Ctrl-C ends the process at once; with --output it can leave the .part file behind.
  • agent logs --follow follows the log until such a signal, and then ends with 0.
  • agent update stops following the update with 130; the agent goes on by itself.
  • os reset, while it writes its request, takes the request back, ends with 130, and the device does not restart.
  • agent configure, once it has begun to change the machine, no longer stops for a lost terminal or SSH session. Ctrl-C and SIGTERM still end it at once.
  • os install behaves differently before and after its question; see ironflock os install.

Exit Codes in a Script

A script gives --yes so that the command does not stop at its question, --json for a result it can read, and checks the exit code:

#!/bin/sh # Let the agent update itself; keep the JSON result, drop the progress on stderr. result=$(sudo ironflock agent update --yes --json 2>/dev/null) code=$? case $code in 0) echo "agent is current: $result" ;; 1) echo "agent update failed: $result" ;; 3) echo "agent update refused on this machine: $result" ;; *) echo "agent update ended with exit code $code: $result" ;; esac

With exit code 0, $result holds the result, whose outcome is updated or current. With exit code 1, it holds either the result, whose outcome and reason say why the agent stays at its version, or an error object. With exit code 3, it holds the error object.

Last updated on