Скапіруйце працоўны радок каманды ў ExecStart, перазагрузіце, і юніт падае або моўчкі выходзіць, разглядаючы аргументы як імёны файлаў. У systemd нічога не зламана. ExecStart — гэта спіс аргументаў, а не shell, таму канвееры, перанакіраванне і ўмовы губляюць сэнс у момант, калі пакідаюць ваш тэрмінал. Вырашыце, дзе павінен быць shell, затым напішыце юніт, які дакладна апісвае, што выконваецца.

Чаму канвеер у ExecStart нічога не робіць

Калі каманда ўводзіцца ў тэрмінале, shell спачатку разбірае яе. Ён будуе канвеер, адкрывае файлы для перанакіравання і разгортвае зменныя перш чым запусціцца любая праграма. systemd нічога з гэтага не робіць: ён разбівае ExecStart паводле ўласных правілаў і выконвае атрыманую праграму з гэтымі аргументамі. Таму > прыходзіць як літаральны аргумент, а | перадаецца праграме замест злучэння двух працэсаў. Юніт не паводзіць сябе няправільна; сінтаксіс меў на ўвазе іншае.

Гэта зроблена наўмысна, а не па няўважлівасці, бо прадказальныя аргументы робяць юніты прыдатнымі да праверкі. Гэта здзіўляе толькі тых, хто мяркуе, што shell прысутнічае.

Напішыце юніт, які дакладна апісвае, што запускаецца

Пачніце з невялікага юніта, прызначэнне якога бачна ў журнале, каб праблемы разбору заставаліся асобна ад праблем тунэля. Гэты толькі паведамляе версію бінарніка.

[Unit]
Description=Report the installed OpenVPN version

[Service]
Type=oneshot
ExecStart=/usr/sbin/openvpn --version
StandardOutput=journal
StandardError=journal

Шлях — гэта запаўняльнік, таму падстаўце бінарнік, які фактычна ўсталяваны. Type=oneshot падыходзіць для каманды, якая працуе да завяршэння, а налады журнала размяшчаюць яе вывад там, дзе вы можаце прачытаць яго без тэрмінала. Секцыі ўстаноўкі наўмысна няма, таму юніт выклікаецца ўручную, а не ўключаецца пры загрузцы. Праверце файл перад запускам, бо друкарская памылка ў назве дырэктывы выяўляецца інакш, чым памылка ў шляху.

systemd-analyze verify /etc/systemd/system/openvpn-version.service
systemctl start openvpn-version.service

Трымайце логіку shell у скрыпце

Калі дапаможнік сапраўды патрабуе ўмоўнай логікі, змясціце гэтую логіку ў скрыпт і выклікайце яго яўна. Скрыпту патрэбны радок інтэрпрэтатара, дазвол на выкананне і коды выхаду, якія служба можа паведаміць. Запуск /bin/sh -c з камандай у лапках сапраўды працуе, але ён хавае правілы цытавання ўнутры юніта і ўскладняе праверку. Названы скрыпт можна праверыць уручную і пазней замяніць, не рэдагуючы юніт. Не спадзявайцеся на профіль shell інтэрактыўнага карыстальніка, бо служба запускаецца са сваім асяроддзем.

Задайце WorkingDirectory, калі важныя адносныя шляхі, і перадавайце асяроддзе праз падтрымліваемыя дырэктывы юніта, а не экспартуйце яго ў тэрмінале. Сакрэты належаць абароненым файлам або ўліковым даным, а не спісам аргументаў, якія журнал можа запісаць.

Праверце юніт, які фактычна існуе

Файлы drop-in змяняюць паводзіны, не закранаючы файл, які вы памятаеце рэдагаваць. Прачытайце, што загрузіў мэнэджар і што паведаміў апошні запуск.

systemctl cat vpn-helper.service
journalctl -u vpn-helper.service -n 20 --no-pager

Дамп юніта ўключае drop-in у парадку загрузкі, і менавіта адтуль звычайна бярэцца нечаканы ExecStart. Пасля любой змены перазагрузіце мэнэджар і пераканайцеся, што новае вызначэнне — гэта тое, што друкуе systemctl cat. Журнал паказвае дакладны радок каманды і статус выхаду, аддзяляючы праблему аргументаў ад адсутнага бінарніка або памылкі правоў. Затым вырашыце, ці належыць дапаможнік існуючаму жыццёваму цыклу VPN, ці ён павінен застацца ручной дыягностыкай, бо другі фонавы працэс тунэля стварае канкуруючага ўладальніка.

Юніт, які патрабаваным чынам друкуе правільны вывад, — добры першы этап. Гэта яшчэ не тунэль, і ён не павінен выдаваць сябе за яго.

Падобныя артыкулы