cl-remote: параллельное выполнение команд на рабочих станциях

Updated 9 November 2026

cl-remote is an administration utility: it runs commands and ready-made service scripts on many machines in parallel over SSH. The utility first finds active addresses on the network by an open port, then connects to each responding machine and displays the results in a single table. This page is intended for administrators who maintain a fleet of Calculate Linux workstations.

This page applies to cl-remote 0.3.2.

Purpose

It is needed when a single action must be performed on dozens of machines at once: check build versions, identify which workstation an employee is using, send notifications to desktops, prepare an update from an image. Compared with manually going from machine to machine over ssh, cl-remote provides:

  • no agent on the machines: everything runs over ssh using the target system's standard tools, and scripts do not remain on the machine after the job;
  • fast filtering of unavailable addresses: port checks run in parallel and take no longer than the SCAN_TIMEOUT for the whole segment, so powered-off machines do not delay the sweep;
  • parallel execution with a controllable degree of parallelism — the -j parameter;
  • selection by logged-in users: run an action where someone is working, or, conversely, only where no one is and a reboot is safe;
  • networks are described once in the configuration file — afterwards they are referenced by name rather than by an address list;
  • a ready-made set of scripts for fleet maintenance: system versions, users, interface speeds, notifications, updating from an image, access point setup.

At the same time, the utility remains a simple shell tool: one invocation produces one table with a result for each machine.

Installation

The utility is installed from the Calculate repository as the app-admin/cl-remote package:

emerge -a cl-remote

Settings are read from the /etc/calculate/remote.env file — right after installation, copy the sample /etc/calculate/remote.env.example to this path and uncomment the required lines. Without the settings file, the utility does not work.

cp /etc/calculate/remote.env.example /etc/calculate/remote.env

SSH Connection

cl-remote invokes ssh without specifying a login, so the ssh client selects the account on the target machine. Any user can run the utility itself on the administrator's machine — what matters is that system-level actions on the target machine run as root. To do this, run cl-remote as root or specify the User root directive in the client's ~/.ssh/config. In both cases, set up passwordless login to root: generate a key pair (ssh-keygen -t ed25519), add the public key to the root account of the machines (ssh-copy-id root@<address>), and specify the private key path in the SSH_KEY variable.

If key-based login is not set up, run it with the --ask-pass parameter: the utility requests the SSH password once and uses it to authenticate all connections through sshpass. Without --ask-pass, only key-based login works: a machine that does not accept the key is considered unavailable — the utility issues no further prompts.

Ключи серверов не проверяются

Connections are made without verifying the target machine's public key and without writing to known_hosts. The utility assumes that the administrator trusts the addresses listed in your configuration.

Configuration

cl-remote discovers machines by port: from the entire address list it connects to those with the probe port open. By default this is 22 — suitable when sshd runs on every machine of the fleet. To distinguish your machines from the rest of the network equipment, mark them with an additional port: configure sshd to accept connections on it as well, and specify the number in NET_PORT. Sweeping a segment of 254 addresses takes less than a second, so discovery results do not need caching — each run finds the machines anew.

Address lists and network names are stored in the configuration file: NET_ADDR holds "name — address range" pairs, NET_NAME holds "name — description" pairs (displayed by cl-remote -t list), and the NET variable sets the default network: without the -t parameter, it is this network that is used. NET_PORT is set in the probe[:ssh] format: the first port is for discovery, the second (when omitted, the shared SSH_PORT) is for connecting.

Example of a configured file:

/etc/calculate/remote.env

# Default network for cl-remote
NET="labnet"

# Network names: the name — description pair is shown by cl-remote -t list
NET_NAME=(
    labnet "Lab network"
    officens "Office network"
)

# Network address ranges: the name — address list pair
NET_ADDR=(
    labnet "pc1 pc2 pc3"
    officens "192.168.1.{10..20}"
)

# Network ports in the probe[:ssh] format
NET_PORT=(
    labnet "22"
)

# Number of simultaneous connections
JOBS=10

# Private key for passwordless login
SSH_KEY="/root/.ssh/id_ed25519"

The list query displays the registered networks and the default network:

cl-remote -t list
Network:
  [labnet]              Lab network
  [officens]            Office network

Default network: labnet
 # The default value can be overridden in 'remote.env'.

Targets

A target is set as a network name from the configuration, an IP address, a hostname, or a brace-expanded range; the -t parameter may be repeated several times. The command can also be sent to an entire segment — it reaches only the machines that respond, and the sweep time is shown in the last table row:

cl-remote -t '192.168.1.{1..254}' -- who
HOSTNAME        IP              OUTPUT
--------------------------------------------------------------------------------
pc1             192.168.1.11    ivan     pts/0        2026-11-09 14:10 (192.168.64.5)
                                petr     pts/1        2026-11-09 14:40 (192.168.64.6)
                                root     tty1         2026-11-09 13:40
pc2             192.168.1.12    ivan     pts/0        2026-11-09 14:10 (192.168.64.5)
                                petr     pts/1        2026-11-09 14:40 (192.168.64.6)
                                root     tty1         2026-11-09 13:40
pc3             192.168.1.13    ivan     pts/0        2026-11-09 14:10 (192.168.64.5)
                                petr     pts/1        2026-11-09 14:40 (192.168.64.6)
                                root     tty1         2026-11-09 13:40

Total: 3  Success: 3  
Execution time: 0.0 sec.

The examples use the administrator's lab subnet 192.168.1.0/24: machines pc1—pc3 answer at 192.168.1.11—192.168.1.13; substitute your own working addresses.

Extra addresses are removed from the selection with the -x parameter. Exclude an address in the same form in which it entered the target: ranges as numbers, networks as names:

cl-remote -t '192.168.1.{1..254}' -x 192.168.1.12 -- who
HOSTNAME        IP              OUTPUT
--------------------------------------------------------------------------------
pc1             192.168.1.11    ivan     pts/0        2026-11-09 14:10 (192.168.64.5)
                                petr     pts/1        2026-11-09 14:40 (192.168.64.6)
                                root     tty1         2026-11-09 13:40
pc3             192.168.1.13    ivan     pts/0        2026-11-09 14:10 (192.168.64.5)
                                petr     pts/1        2026-11-09 14:40 (192.168.64.6)
                                root     tty1         2026-11-09 13:40

Total: 2  Success: 2  
Execution time: 0.0 sec.

If no command is specified, the utility limits itself to a port check — this is how you determine which addresses in a segment are responsive:

cl-remote -t '192.168.1.{1..254}'
HOSTNAME        IP              OUTPUT
--------------------------------------------------------------------------------
pc3             192.168.1.13    Port 22 is open.
pc1             192.168.1.11    Port 22 is open.
pc2             192.168.1.12    Port 22 is open.

Total: 3  
Execution time: 0.0 sec.

Selecting Machines by Logged-In Users

The -u parameter filters machines by login status before the command runs: ON — only machines where someone is working; OFF — only machines where no one is logged in (safe for reboots); a login — only machines where the specified user is logged in; ALL (the default value) — no filter. This is how, for example, machines with an open root console are found:

cl-remote -t '192.168.1.{1..254}' -u root -- who
HOSTNAME        IP              OUTPUT
--------------------------------------------------------------------------------
pc3             192.168.1.13    ivan     pts/0        2026-11-09 14:10 (192.168.64.5)
                                petr     pts/1        2026-11-09 14:40 (192.168.64.6)
                                root     tty1         2026-11-09 13:40
pc1             192.168.1.11    ivan     pts/0        2026-11-09 14:10 (192.168.64.5)
                                petr     pts/1        2026-11-09 14:40 (192.168.64.6)
                                root     tty1         2026-11-09 13:40
pc2             192.168.1.12    ivan     pts/0        2026-11-09 14:10 (192.168.64.5)
                                petr     pts/1        2026-11-09 14:40 (192.168.64.6)
                                root     tty1         2026-11-09 13:40

Total: 3  Success: 3  
Execution time: 0.1 sec.

A machine that fails the filter is omitted from the output: running with a login that no one has used yields an empty table:

cl-remote -t pc1 -u natalia -- who
HOSTNAME        IP              OUTPUT
--------------------------------------------------------------------------------

Execution time: 0.0 sec.

Ready-Made Scripts

The -s parameter runs a script from the /usr/libexec/cl-remote directory: the script is transferred to the machine in full, where its run() function runs; arguments after the script name become its parameters. The list argument shows the scripts themselves, their descriptions, and invocation examples:

cl-remote -s list
System Scripts:
  [aproaming]           Configuring OpenWrt access points with seamless Wi-Fi
                        roaming support (802.11r/k/v).
                        Example: cl-remote -t ap0812 -p 51022 -s aproaming
  [rename-iface]        Renaming the default network interface.
                        Udev in the initramfs assigns unique names to network
                        interfaces, which can be inconvenient to work with. This
                        script allows you to rename a network interface.
                        Warning: It's not recommended to use the name eth0 if
                        you have multiple network interfaces, as proper renaming
                        via systemd-udevd has been removed.
                        Example: 'cl-remote -s rename-iface lan0'
  [users]               Display system users
  [version]             Displaying the installed system version.
                        This script retrieves the installed version of
                        Calculate Linux. If an argument is provided, it compares
                        the version with the given value.
                        Example: 'cl-remote -s version 20250311'
  [upgrade]             Updating Calculate Linux from a system image without
                        modifying the existing installation
                        Example: 'cl-remote -j3 -s upgrade'
  [notify]              Sending Notifications to Users
                        Example: cl-remote -s notify "System Update" Reboot in
                        10 minutes!
  [netspeed]            Network Interface Speed
                        Displays the name and speed of the network interface.
                        If the speed does not match the maximum, an error is
                        displayed. Takes bridges into account.
                        Example: 'cl-remote -s netspeed'
User Scripts:
  [kernel]              Show the running kernel version
                        Measured on the target machine; the output is the
                        kernel version string
                        Example: 'cl-remote -s kernel'

Checking the System Version (version)

The script reads the build number from /var/lib/calculate/calculate.env; if you pass it a reference number, machines that differ are marked with a warning:

cl-remote -t '192.168.1.{1..254}' -s version 20261106
HOSTNAME        IP              OUTPUT
--------------------------------------------------------------------------------
pc3             192.168.1.13    20261030
pc2             192.168.1.12    20261030
pc1             192.168.1.11    20261030

Total: 3  Warnings: 3  
Execution time: 0.0 sec.

The machines have not yet updated to the latest release 20261106: the builds differ from the expected one, and the summary counted those rows as warnings.

Machine Users (users)

The script shows the logged-in users — the full name from the account and the primary group; a root login is marked with a warning:

cl-remote -t pc1 -s users
HOSTNAME        IP              OUTPUT
----------------------------------------------------------------------
                                Name                            Group
pc1             192.168.1.11    Ivan Petrov                     users
                                Petr Sidorov                    users
                                root                            root

Total: 1  Warnings: 1  
Execution time: 0.0 sec.

Desktop Notifications (notify)

The script finds users with an open graphical session and sends each one a notify-send notification; the first argument is the title, the rest is the notification text. The display time and icon are set by the NOTIFY_TIME and NOTIFY_ICON variables in /etc/calculate/remote-client.env.

Network Interface Speed (netspeed)

The script shows the interface of the default route and its current speed; when ethtool is available, it compares the current speed with the maximum supported one and marks the machines running below their limit with a warning. Bridges are taken into account: the physical interface under the bridge is displayed.

Upgrade from an Image (upgrade)

The script runs the upgrade-from-image preparation (cl-install -Uf) and reboots the machine only when no user is active on it. This is a heavy operation, so concurrent runs are limited — as in the example from the list itself: cl-remote -j3 -s upgrade.

Interface Name Unification (rename-iface)

Udev in initramfs assigns interfaces names based on their hardware position (enp19s0 and the like), so the names differ from machine to machine. The script brings local interface names to a form common across the fleet: the interface carrying the default route is renamed to the name passed as an argument (or to the value of RENAME_IFACE), and on every machine it then has the same name — for example, lan0. Besides the rename, the script edits /etc/conf.d/net and the runlevel script symlinks, and writes a rule into /etc/udev/rules.d/70-persistent-net.rules that binds the name to the MAC address, so the name survives a reboot. On machines with several interfaces, avoid choosing eth0 as the standard name.

Access Point Setup (aproaming)

The script prepares an OpenWrt access point for seamless 802.11r/k/v roaming. The network names of both bands, the Wi-Fi password, the regulatory domain, the channel width, NTP and the time zone are set by variables prefixed with AP_ in /etc/calculate/remote-client.env; if the Wi-Fi password is missing, the utility asks for it at startup.

Custom Scripts

A custom script is an ordinary shell file. The main part of the code runs in the run() function, which receives the arguments specified after the script name; the optional prepare() function runs on the administrator's machine before distribution and can, for example, set the heading of an extra table column — the CLIENT_TABLE_HEADER variable serves this purpose. Description lines starting with ## appear in the cl-remote -s list output. Custom scripts are searched for first in the user directory — by default /var/calculate/remote-scripts, and its path is overridden by the USER_SCRIPTS_DIR variable in /etc/calculate/remote.env; the script is then searched for among the system ones in /usr/libexec/cl-remote. The ready-made scripts from this directory can serve as a basis for writing your own. Values from /etc/calculate/remote-client.env and whatever prepare() has collected are delivered to the target machine together with the script; no trace of the script remains on the machine.

Example of a script that prints the kernel version:

/var/calculate/remote-scripts/kernel

## Show the running kernel version
## Measured on the target machine; the output is the kernel version string
## Example: 'cl-remote -s kernel'

run() {
    uname -r
}

Running a custom script on a machine:

cl-remote --nocolor -t pc1 -s kernel
HOSTNAME        IP              OUTPUT
--------------------------------------------------------------------------------
pc1             192.168.1.11    6.18.57-calculate

Total: 1  Success: 1  
Execution time: 0.0 sec.

Displaying Results

Each processed machine becomes a table row with the HOSTNAME, IP and OUTPUT columns; multi-line command output is aligned to the third column. Rows are colored by outcome: green for success, yellow for a warning, red for an error; a ready-made script marks its result as a warning with exit code 73. Rows appear in the order results arrive, not alphabetically. The summary counters and the execution time are printed at the end.

The level filter -r keeps in the output only the rows of the requested level:

cl-remote -t pc1 -r error -s version 20261106
HOSTNAME        IP              OUTPUT
--------------------------------------------------------------------------------

Execution time: 0.0 sec.

The --nocolor option disables colors (the utility does this automatically when output is redirected to a file).

Options

Option Value Action
--ask-pass — Prompt for the SSH password and authenticate via sshpass
-x, --exclude network / address / name Exclude from the selection; repeatable
-h, --help — Show help
-j, --jobs number (10) Number of simultaneous connections
--nocolor — Disable colored output
-p, --probe-port port (22) Port for checking host availability
-P, --ssh-port port (22) SSH connection port
-r, --report all / success / warning / error Keep only rows of this level in the output
-s, --script name or list Run a ready-made script; list displays the script list
-t, --target network / address / name Set the target; repeatable
-u, --using ALL / ON / OFF / login Run, taking logged-in users into account

The full list with examples is in the cl-remote --help output.

Configuration Variables

Values are set in /etc/calculate/remote.env (except the variables for ready-made scripts, which are stored in /etc/calculate/remote-client.env).

Variable Default Purpose
EXEC_TIMEOUT 1200 Time limit for command execution on the host, seconds
JOBS 10 Number of simultaneous connections
NET — Default network for a run without -t
NET_ADDR — Pairs of "network name — address list"
NET_NAME — Pairs of "network name — description" for -t list
NET_PORT — Pairs of "network name — probe[:ssh]"
PROBE_PORT 22 Port for checking host availability
SCAN_TIMEOUT 1.5 Port check timeout, seconds
SSH_KEY — Path to the private SSH key
SSH_PORT 22 SSH connection port
USING ALL Default filter by logged-in users
USER_SCRIPTS_DIR /var/calculate/remote-scripts Directory for custom scripts

Source repository and additional examples: git.calculate-linux.org/calculate/cl-remote

Other administration guides are on the Working with Calculate page.