Bốn mươi tệp .ovpn cho một quốc gia đến từ một nhà cung cấp, và kế hoạch có vẻ hiển nhiên: sao chép một tệp ngẫu nhiên vào vị trí của nó, rồi khởi động đường hầm. Viết dưới dạng một pipeline bên trong ExecStart, kế hoạch đó chết ngay khi khởi động với một mã trạng thái không giải thích được gì. Tệp unit không phải là script, và cách sửa là hoặc đưa một shell vào một cách rõ ràng hoặc thôi chọn tệp hoàn toàn.

Triệu chứng: một unit khởi động và chết ngay lập tức

Trạng thái cho thấy dịch vụ đã thất bại trong một phần của giây, và dòng nhật ký nêu tên một lệnh mà không shell nào từng nhận được. Không có gì về đường hầm xuất hiện, vì đường hầm chưa bao giờ bắt đầu.

Đọc dòng lệnh chính xác từ nhật ký là cách nhanh nhất để xác nhận điều này. systemd lặp lại những gì nó đã thực thi, và chuỗi sẽ hiển thị các ký tự pipeline như đối số nguyên văn thay vì toán tử.

Vì sao ExecStart không thể chạy một pipeline

systemd tự tách dòng lệnh, áp dụng cách đặt dấu ngoặc và thay thế biến của riêng nó, rồi thực thi kết quả trực tiếp. Pipe, chuyển hướng, mở rộng mẫu bởi shell và thay thế lệnh đơn giản là không thuộc ngữ pháp đó. Đây là một lựa chọn thiết kế chứ không phải thiếu sót: một unit tuyên bố những gì cần chạy, và logic của shell thuộc về một script mà unit gọi. Cả hai cách sửa đều xuất phát từ đó, và không cách nào đòi cấp thêm quyền cho unit.

Điều này cũng giải thích mã thoát gây nhầm lẫn. Đối số đầu tiên được coi là tệp nhị phân, nên một dòng sai định dạng thất bại trước khi bất kỳ phần nào trong logic của bạn chạy.

Hãy chọn trong ExecStartPre

Cách sửa trực tiếp là một bước chuẩn bị gọi shell một cách rõ ràng, giữ việc chọn và khởi động trong cùng một unit để lỗi ở bên này không thể khiến bên kia chạy một mình.

[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

Ba chi tiết quyết định liệu điều này có sống sót khi tiếp xúc với một cỗ máy thật. Đặt tên là cái bẫy đầu tiên: systemd thay thế %i ngay khi phân tích unit, rất lâu trước khi bash chạy, nên bộ chỉ định phải nằm ngoài dấu nháy đơn. xargs -r ngăn cp chạy mà không có đối số khi mẫu không khớp với gì cả. Và một bước chuẩn bị thất bại sẽ dừng unit, và đó là kết quả đúng: khởi động với cấu hình của hôm qua còn tệ hơn là không khởi động. Một lựa chọn ngẫu nhiên luôn lấy cùng một tệp thường không phải là vận rủi. Hãy kiểm tra xem tệp được sao chép có bị ghi đè bởi bản cập nhật gói hay không, hoặc mẫu chỉ khớp với một mục cũ duy nhất.

Hoặc để OpenVPN chọn điểm cuối

OpenVPN đã có thể giữ nhiều điểm cuối trong một hồ sơ và chọn ngẫu nhiên giữa chúng, điều này loại bỏ hoàn toàn shell, bản sao và quyền ghi khỏi đường khởi động.

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

Dạng này giữ việc chọn máy chủ bên trong tệp do nhà cung cấp viết, nên một vòng xoay đổi tên tệp không làm hỏng unit. Nó cũng làm cho danh sách ứng viên có thể kiểm tra được, điều mà một mẫu trên thư mục không bao giờ có. Việc xáo trộn vẫn có chỗ đứng khi các hồ sơ khác nhau ở nhiều thứ hơn một điểm cuối: chứng chỉ khác nhau, chỉ thị định tuyến khác nhau, chính sách mã hóa khác nhau. Trong trường hợp đó, lựa chọn là giữa toàn bộ cấu hình, và một bước shell là cách trung thực để diễn đạt điều đó.

Đọc lại phiên bản và tệp mà nó đã dùng

Xác nhận unit nào thực sự đang chạy trước khi gỡ lỗi nội dung của nó. Dịch vụ meta được đóng gói và mẫu là hạ tầng; các unit tương ứng với tệp của bạn là những phiên bản được đặt tên theo chúng.

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

Một phiên bản mà không ai nhớ đã bật thường dẫn ngược về một tệp cấu hình lạc trong thư mục gói. Hãy tắt chính phiên bản có tên đó thay vì mẫu, nếu không bản nâng cấp gói tiếp theo sẽ mang nó trở lại. Sau khi thay đổi, hãy khởi động unit và đọc dòng lệnh mà nhật ký báo cáo, rồi xác nhận đường dẫn cấu hình mà nó thực sự đã mở. Chính lần kiểm tra đó phân biệt một lựa chọn ngẫu nhiên đang hoạt động với một dịch vụ lặng lẽ dùng lại tệp từ tháng trước.

Bài viết liên quan