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

Обновлено 9 ноября 2026

cl-remote — административная утилита: она параллельно по SSH выполняет команды и готовые служебные скрипты на множестве машин. Сначала утилита находит активные адреса в сети по открытому порту, затем подключается к каждой откликнувшейся машине и выводит результаты общей таблицей. Страница рассчитана на администраторов, которые обслуживают парк рабочих станций Calculate Linux.

Материал актуален для cl-remote 0.3.2.

Назначение

Потребность в ней возникает, когда одно действие нужно на десятках машин сразу: проверить версии сборок, найти, за какой станцией сидит сотрудник, разослать уведомления на рабочие столы, подготовить обновление из образа. По сравнению с ручным обходом ssh по одной машине cl-remote даёт:

  • отсутствие агента на машинах: всё исполнение идёт по ssh штатными средствами целевой системы, а скрипты после работы на машине не остаются;
  • быстрый отсев недоступных адресов: проверки порта идут параллельно и длятся не дольше таймаута SCAN_TIMEOUT на весь сегмент, поэтому выключенные машины не задерживают обход;
  • параллельное выполнение с управляемой степенью параллелизма — параметром -j;
  • отбор по вошедшим пользователям: выполнить действие там, где кто-то работает, или наоборот только там, где никого нет и перезагрузка безопасна;
  • однократное описание сетей в конфигурационном файле — дальше они вызываются по имени, а не списком адресов;
  • готовый набор скриптов для обслуживания парка: версии систем, пользователи, скорость интерфейсов, уведомления, обновление из образа, настройка точек доступа.

При этом утилита остаётся простым shell-инструментом: один вызов — одна таблица с результатом по каждой машине.

Установка

Утилита ставится из репозитория Calculate как пакет app-admin/cl-remote:

emerge -a cl-remote

Настройки читаются из файла /etc/calculate/remote.env — сразу после установки скопируйте в этот путь пример /etc/calculate/remote.env.example и раскомментируйте нужные строки. Без файла настроек утилита не работает.

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

Подключение по SSH

cl-remote вызывает ssh без указания логина, поэтому учётную запись на целевой машине выбирает ssh-клиент. Саму утилиту на машине администратора может запустить любой пользователь — важно, чтобы системные действия на целевой машине выполнялись от root. Для этого запускайте cl-remote от root либо пропишите директиву User root в ~/.ssh/config клиента. В обоих случаях настройте безпарольный вход в root: сгенерируйте пару ключей (ssh-keygen -t ed25519), добавьте публичный ключ в корневую учётную запись машин (ssh-copy-id root@<адрес>) и укажите путь к закрытому ключу в переменной SSH_KEY.

Если вход по ключу не настроен, запускайте с параметром --ask-pass: утилита один раз запросит SSH-пароль и аутентифицирует им все подключения через sshpass. Без --ask-pass работает только вход по ключу: машина, не принявшая ключ, считается недоступной — дополнительных запросов утилита не делает.

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

Подключение идёт без проверки открытого ключа целевой машины и без записи в known_hosts. Утилита рассчитывает на то, что адресам из ваших настроек доверяет администратор.

Настройка

cl-remote обнаруживает машины по порту: из всего списка адресов подключается к тем, у которых открыт порт-проба. По умолчанию это 22 — подходит, когда sshd работает на всех машинах парка. Чтобы отличить свои машины от прочего оборудования сети, выделите их дополнительным портом: настройте sshd принимать соединения и на нём, а номер укажите в NET_PORT. Обход сегмента из 254 адресов занимает меньше секунды, поэтому кэшировать результат обнаружения не нужно — каждый запуск находит машины заново.

Списки адресов и имена сетей хранятся в конфигурационном файле: NET_ADDR содержит пары «имя — диапазон адресов», NET_NAME — пары «имя — описание» (их показывает cl-remote -t list), а переменная NET задаёт сеть по умолчанию: без параметра -t работают именно с ней. NET_PORT задают в формате probe[:ssh]: первый порт — обнаружения, второй (при пропуске — общий SSH_PORT) — подключения.

Пример настроенного файла:

/etc/calculate/remote.env

# Сеть, используемая по умолчанию
NET="labnet"

# Имена сетей: пару имя — описание покажет cl-remote -t list
NET_NAME=(
    labnet "Лабораторная сеть"
    officens "Офисная сеть"
)

# Адресные диапазоны сетей: пару имя — список адресов
NET_ADDR=(
    labnet "pc1 pc2 pc3"
    officens "192.168.1.{10..20}"
)

# Порты сети в формате probe[:ssh]
NET_PORT=(
    labnet "22"
)

# Число одновременных подключений
JOBS=10

# Закрытый ключ для passwordless-входа
SSH_KEY="/root/.ssh/id_ed25519"

Зарегистрированные сети и сеть по умолчанию показывает запрос списка:

cl-remote -t list
Сеть:
  [labnet]              Лабораторная сеть
  [officens]            Офисная сеть

Сеть по умолчанию: labnet
 # Значение по умолчанию можно переопределить в 'remote.env'.

Мишени

Мишенью задают имя сети из настроек, IP-адрес, имя хоста или диапазон в фигурных скобках; параметр -t повторяется несколько раз. Команду можно послать и по всему сегменту — дойдёт только до откликнувшихся машин, а время обхода видно в последней строке таблицы:

cl-remote -t '192.168.1.{1..254}' -- who
ИМЯ ХОСТА       IP              РЕЗУЛЬТАТ
--------------------------------------------------------------------------------
pc1             192.168.1.11    ivan     pts/0        2026-11-09 09:17 (192.168.64.5)
                                petr     pts/1        2026-11-09 09:47 (192.168.64.6)
                                root     tty1         2026-11-09 08:47
pc3             192.168.1.13    ivan     pts/0        2026-11-09 09:17 (192.168.64.5)
                                petr     pts/1        2026-11-09 09:47 (192.168.64.6)
                                root     tty1         2026-11-09 08:47
pc2             192.168.1.12    ivan     pts/0        2026-11-09 09:17 (192.168.64.5)
                                petr     pts/1        2026-11-09 09:47 (192.168.64.6)
                                root     tty1         2026-11-09 08:47

Всего: 3  Успешно: 3  
Время выполнения: 0.1 сек.

В примерах — лабораторная подсеть администратора 192.168.1.0/24: машины pc1—pc3 отвечают на адресах 192.168.1.11—192.168.1.13; в своей сети подставьте рабочие адреса.

Лишние адреса снимаются из выборки параметром -x. Исключайте адрес в том же виде, в каком он попал в мишень: диапазоны — числами, сети — именами:

cl-remote -t '192.168.1.{1..254}' -x 192.168.1.12 -- who
ИМЯ ХОСТА       IP              РЕЗУЛЬТАТ
--------------------------------------------------------------------------------
pc1             192.168.1.11    ivan     pts/0        2026-11-09 09:17 (192.168.64.5)
                                petr     pts/1        2026-11-09 09:47 (192.168.64.6)
                                root     tty1         2026-11-09 08:47
pc3             192.168.1.13    ivan     pts/0        2026-11-09 09:17 (192.168.64.5)
                                petr     pts/1        2026-11-09 09:47 (192.168.64.6)
                                root     tty1         2026-11-09 08:47

Всего: 2  Успешно: 2  
Время выполнения: 0.1 сек.

Если не указывать команду, утилита ограничится проверкой порта — так определяют, какие адреса в сегменте отвечают:

cl-remote -t '192.168.1.{1..254}'
ИМЯ ХОСТА       IP              РЕЗУЛЬТАТ
--------------------------------------------------------------------------------
pc2             192.168.1.12    Порт 22 открыт.
pc1             192.168.1.11    Порт 22 открыт.
pc3             192.168.1.13    Порт 22 открыт.

Всего: 3  
Время выполнения: 0.0 сек.

Отбор машин по вошедшим пользователям

Параметр -u фильтрует машины по статусу входа ещё до выполнения команды: ON — только там, где кто-то работает; OFF — только там, где никого нет (безопасно для перезагрузок); логин — только там, где вошёл указанный пользователь; ALL (значение по умолчанию) — без фильтра. Так ищут, например, машины с незакрытой root-консолью:

cl-remote -t '192.168.1.{1..254}' -u root -- who
ИМЯ ХОСТА       IP              РЕЗУЛЬТАТ
--------------------------------------------------------------------------------
pc1             192.168.1.11    ivan     pts/0        2026-11-09 09:17 (192.168.64.5)
                                petr     pts/1        2026-11-09 09:47 (192.168.64.6)
                                root     tty1         2026-11-09 08:47
pc2             192.168.1.12    ivan     pts/0        2026-11-09 09:17 (192.168.64.5)
                                petr     pts/1        2026-11-09 09:47 (192.168.64.6)
                                root     tty1         2026-11-09 08:47
pc3             192.168.1.13    ivan     pts/0        2026-11-09 09:17 (192.168.64.5)
                                petr     pts/1        2026-11-09 09:47 (192.168.64.6)
                                root     tty1         2026-11-09 08:47

Всего: 3  Успешно: 3  
Время выполнения: 0.1 сек.

Машина, не прошедшая фильтр, в вывод не попадает: запуск с логином, под которым никто не входил, даёт пустую таблицу:

cl-remote -t pc1 -u natalia -- who
ИМЯ ХОСТА       IP              РЕЗУЛЬТАТ
--------------------------------------------------------------------------------

Время выполнения: 0.0 сек.

Готовые скрипты

Параметр -s выполняет скрипт из каталога /usr/libexec/cl-remote: скрипт целиком передаётся на машину, где запускается его функция run(); аргументы после имени скрипта становятся её параметрами. Аргумент list показывает сами скрипты, их описания и примеры вызова:

cl-remote -s list
Системные скрипты:
  [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'
Пользовательские скрипты:
  [kernel]              Отображение версии работающего ядра
                        Замеряется на целевой машине, вывод — строка uname -r
                        Пример: 'cl-remote -s kernel'

Проверка версии системы (version)

Скрипт читает номер сборки из /var/lib/calculate/calculate.env; если передать ему эталонный номер, отличившиеся машины будут помечены предупреждением:

cl-remote -t '192.168.1.{1..254}' -s version 20261106
ИМЯ ХОСТА       IP              РЕЗУЛЬТАТ
--------------------------------------------------------------------------------
pc3             192.168.1.13    20261030
pc2             192.168.1.12    20261030
pc1             192.168.1.11    20261030

Всего: 3  Предупреждения: 3  
Время выполнения: 0.1 сек.

Машины ещё не обновились до свежего релиза 20261106: сборки отличаются от ожидаемой, и итог отнёс строки к предупреждениям.

Пользователи машины (users)

Скрипт показывает вошедших пользователей — полное имя из учётной записи и основную группу; вход root помечается предупреждением:

cl-remote -t pc1 -s users
ИМЯ ХОСТА       IP              РЕЗУЛЬТАТ
----------------------------------------------------------------------
                                Name                            Group
pc1             192.168.1.11    Ivan Petrov                     users
                                Petr Sidorov                    users
                                root                            root

Всего: 1  Предупреждения: 1  
Время выполнения: 0.0 сек.

Уведомления на рабочие столы (notify)

Скрипт находит пользователей с открытым графическим сеансом и посылает каждому уведомление notify-send; заголовок — первый аргумент, остальное — текст уведомления. Время показа и значок задаются переменными NOTIFY_TIME и NOTIFY_ICON в /etc/calculate/remote-client.env.

Скорость сетевого интерфейса (netspeed)

Скрипт показывает интерфейс маршрута по умолчанию и его рабочую скорость; при наличии ethtool сравнивает её с максимально поддерживаемой и помечает предупреждением машины, работающие ниже своего лимита. Мосты учитываются: выводится физический интерфейс под мостом.

Обновление из образа (upgrade)

Скрипт запускает подготовку обновления из образа (cl-install -Uf) и перезагружает машину, только если на ней никто не работает. Операция тяжёлая, поэтому параллельные запуски ограничивают — как в примере из самого списка: cl-remote -j3 -s upgrade.

Унификация имён интерфейсов (rename-iface)

Udev в initramfs даёт интерфейсам имена по аппаратному расположению (enp19s0 и подобные), и на разных машинах они различаются. Смысл скрипта — привести имена локальных интерфейсов к общим для всего парка: интерфейс маршрута по умолчанию переименовывается в переданное имя (или в значение RENAME_IFACE), и на всех машинах он начинает называться одинаково — например, lan0. Кроме переименования скрипт правит /etc/conf.d/net и ссылки скриптов уровня запуска и записывает в /etc/udev/rules.d/70-persistent-net.rules правило, привязывающее имя к MAC-адресу, — имя сохраняется и после перезагрузки. На машинах с несколькими интерфейсами стандартным именем лучше не выбирать eth0.

Настройка точек доступа (aproaming)

Скрипт готовит точку доступа OpenWrt к бесшовному роумингу 802.11r/k/v. Имена сетей обоих диапазонов, Wi-Fi-пароль, регуляторный домен, ширину каналов, NTP и часовой пояс задают переменными с префиксом AP_ в /etc/calculate/remote-client.env; недостающий Wi-Fi-пароль утилита запрашивает при запуске.

Свои скрипты

Свой скрипт — обычный shell-файл. Основную часть кода выполняет функция run(), получающая аргументы, указанные после имени скрипта; необязательная функция prepare() запускается на машине администратора до рассылки и может, например, задать заголовок дополнительной колонки таблицы — для этого служит переменная CLIENT_TABLE_HEADER. Строки описания, начинающиеся с ##, попадают в список cl-remote -s list. Свои скрипты ищутся в первую очередь в пользовательском каталоге — по умолчанию это /var/calculate/remote-scripts, а путь к нему переопределяется переменной USER_SCRIPTS_DIR в /etc/calculate/remote.env; затем скрипт ищется среди системных в /usr/libexec/cl-remote. Готовые скрипты из этого каталога можно брать за основу при написании своих. Значения из /etc/calculate/remote-client.env и то, что собрала prepare(), передаются на целевую машину вместе со скриптом; на самой машине от скрипта ничего не остаётся.

Пример скрипта, показывающего версию ядра:

/var/calculate/remote-scripts/kernel

## Отображение версии работающего ядра
## Замеряется на целевой машине, вывод — строка uname -r
## Пример: 'cl-remote -s kernel'

run() {
    uname -r
}

Запуск своего скрипта на машине:

cl-remote --nocolor -t pc1 -s kernel
ИМЯ ХОСТА       IP              РЕЗУЛЬТАТ
--------------------------------------------------------------------------------
pc1             192.168.1.11    6.18.57-calculate

Всего: 1  Успешно: 1  
Время выполнения: 0.0 сек.

Вывод результатов

Каждая обработанная машина — строка таблицы из колонок ИМЯ ХОСТА, IP и РЕЗУЛЬТАТ; многострочный вывод команды выравнивается по третьей колонке. Строки окрашиваются по исходу: зелёным — успех, жёлтым — предупреждение, красным — ошибка; готовый скрипт помечает результат предупреждением кодом выхода 73. Порядок строк — по мере готовности, не по алфавиту. В конце — счётчики итогов и время выполнения.

Фильтр по уровню -r оставляет в выводе строки только нужного класса:

cl-remote -t pc1 -r error -s version 20261106
ИМЯ ХОСТА       IP              РЕЗУЛЬТАТ
--------------------------------------------------------------------------------

Время выполнения: 0.0 сек.

Параметр --nocolor отключает цвета (при перенаправлении в файл утилита делает это сама).

Параметры

Параметр Значение Действие
--ask-pass — Спросить SSH-пароль и аутентифицироваться через sshpass
-x, --exclude сеть / адрес / имя Исключить из выборки; повторяется
-h, --help — Показать справку
-j, --jobs число (10) Количество одновременных подключений
--nocolor — Отключить цветной вывод
-p, --probe-port порт (22) Порт для проверки доступности машины
-P, --ssh-port порт (22) Порт подключения по SSH
-r, --report all / success / warning / error Оставлять в выводе строки только этого уровня
-s, --script имя или list Выполнить готовый скрипт; list — показать список
-t, --target сеть / адрес / имя Задать мишень; повторяется
-u, --using ALL / ON / OFF / логин Выполнять с учётом вошедших пользователей

Полный список с примерами — справка cl-remote --help.

Переменные настройки

Значения задаются в /etc/calculate/remote.env (кроме переменных для готовых скриптов — они живут в /etc/calculate/remote-client.env).

Переменная По умолчанию Назначение
EXEC_TIMEOUT 1200 Ограничение времени выполнения команды на машине, секунды
JOBS 10 Количество одновременных подключений
NET — Сеть по умолчанию для запуска без -t
NET_ADDR — Пары «имя сети — список адресов»
NET_NAME — Пары «имя сети — описание» для -t list
NET_PORT — Пары «имя сети — probe[:ssh]»
PROBE_PORT 22 Порт проверки доступности машины
SCAN_TIMEOUT 1.5 Таймаут проверки порта, секунды
SSH_KEY — Путь к закрытому SSH-ключу
SSH_PORT 22 Порт подключения по SSH
USING ALL Фильтр по вошедшим пользователям по умолчанию
USER_SCRIPTS_DIR /var/calculate/remote-scripts Каталог своих скриптов

Исходный репозиторий и дополнительные примеры: git.calculate-linux.org/calculate/cl-remote

Другие руководства по администрированию — на странице Работа с Calculate.