Сорок файлів .ovpn для однієї країни надходять від постачальника, і план здається очевидним: скопіювати випадковий на його місце, потім запустити тунель. Записаний як конвеєр усередині ExecStart, цей план помирає під час завантаження з кодом стану, який нічого не пояснює. Файл юніта — не скрипт, і виправлення полягає або в тому, щоб явно залучити оболонку, або в тому, щоб зовсім відмовитися від вибору файлів.

Симптом: юніт, який запускається і одразу помирає

Статус показує, що служба впала за частку секунди, а рядок журналу називає команду, якої жодна оболонка ніколи б не отримала. Про тунель нічого не з’являється, бо тунель так і не почався.

Читання точної командного рядка з журналу — найшвидший спосіб це підтвердити. systemd повторює те, що виконав, і рядок покаже символи конвеєра як буквальні аргументи, а не як оператори.

Чому ExecStart не може виконати конвеєр

systemd сам розбирає командний рядок, застосовує власні правила лапок і підстановки змінних, а потім виконує результат безпосередньо. Конвеєри, перенаправлення, підстановка шаблонів оболонкою та підстановка команд просто не входять до цієї граматики. Це свідомий вибір, а не недогляд: юніт декларативно каже, що запускати, а логіка оболонки належить скрипту, який юніт викликає. Обидва виправлення випливають із цього, і жодне не вимагає давати юніту більше прав.

Це також пояснює оманливий код виходу. Перший аргумент вважається бінарним файлом, тому неправильний рядок зазнає невдачі ще до того, як запуститься будь-яка частина вашої логіки.

Зробіть вибір у ExecStartPre

Пряме виправлення — це підготовчий крок, який явно викликає оболонку і тримає вибір і запуск в одному юніті, щоб збій в одному не залишив другий працювати сам.

[Service]
Type=notify
ExecStartPre=/bin/bash -c "ls /etc/openvpn/profiles/au* | shuf -n 1 | xargs -r -I{} cp -f {} /etc/openvpn/%i.conf"
ExecStart=/usr/sbin/openvpn --config /etc/openvpn/%i.conf

Три деталі вирішують, чи переживе це зустріч із реальною машиною. Іменування — перша пастка: systemd підставляє %i ще під час розбору юніта, задовго до запуску bash, тому специфікатор має стояти поза одинарними лапками. xargs -r не дає cp запуститися без аргументу, коли шаблон ні з чим не збігається. А невдалий підготовчий крок зупиняє юніт, і це правильний результат: починати з учорашньою конфігурацією гірше, ніж не починати. Випадковий вибір, який завжди бере той самий файл, зазвичай не невдача. Перевірте, чи не перезаписує скопійований файл оновлення пакета, чи не збігається шаблон лише з одним застарілим записом.

Або дозвольте OpenVPN вибрати кінцеву точку

OpenVPN уже може тримати кілька кінцевих точок в одному профілі й випадково вибирати серед них, що повністю прибирає оболонку, копіювання та право запису зі шляху завантаження.

client
remote-random
<connection>
remote au1.example.net 1194 udp
</connection>
<connection>
remote au2.example.net 1194 udp
</connection>

Ця форма тримає вибір сервера всередині файлу, який створив постачальник, тому ротація, що перейменовує файли, не ламає юніт. Вона також робить список кандидатів придатним до аудиту, чим підстановка шаблону по каталогу ніколи не буває. Перемішування все ще виправдане, коли профілі різняться не лише кінцевою точкою: інші сертифікати, інші директиви маршрутизації, інша політика шифрів. У такому разі вибір відбувається між цілими конфігураціями, і крок з оболонкою — чесний спосіб це висловити.

Прочитайте назад екземпляр і файл, який він використав

Перш ніж налагоджувати вміст, переконайтеся, який юніт справді працює. Пакетна мета-служба й шаблон — це інфраструктура; юніти, що відповідають вашим файлам, — це екземпляри, названі на їхню честь.

systemctl list-units 'openvpn*'
systemctl cat [email protected]
journalctl -u openvpn@au -n 30 --no-pager

Екземпляр, який ніхто не пам’ятає, що вмикав, зазвичай веде до загубленого файлу конфігурації в каталозі пакета. Вимкніть саме цей названий екземпляр, а не шаблон, інакше наступне оновлення пакета поверне його. Після зміни запустіть юніт і прочитайте командний рядок, який повідомляє журнал, потім підтвердьте шлях конфігурації, який він справді відкрив. Ця єдина перевірка відокремлює робочий випадковий вибір від служби, що тихо використовує файл минулого місяця.

Схожі статті