העתיקו שורת פקודה עובדת אל 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 או צריך להישאר אבחון ידני, כי תהליך מנהרה שני ברקע יוצר בעלים מתחרה.

יחידה שמדפיסה את הפלט הנכון לפי דרישה היא אבן דרך ראשונה טובה. היא עדיין לא מנהרה, והיא לא אמורה להעמיד פנים שהיא כן.

מאמרים קשורים