traceback מופיע כאשר פקודת ניהול VPN מתחילה, והדחף הראשון הוא להתקין Python אחר או להפנות את ברירת המחדל של המערכת למקום אחר. הדחף הזה מערבב שתי סביבות הרצה שאין ביניהן שום קשר. האחת שייכת למערכת ההפעלה ולכלים הארוזים שלה; האחרת שייכת לכל פרויקט שאתם בונים. שינוי הראשונה כדי לספק את השנייה הוא הדרך שבה שולחן עבודה מתפקד מאבד את מנהל החבילות שלו.

ההשוואה שכדאי לעשות היא בין הרכיב שנכשל בפועל לבין סביבת ההרצה שמותר לכם לשנות. הם כמעט אף פעם לא אותו אובייקט.

שתי שאלות Python שנראות כאחת

השאלה הראשונה היא: איזה מפרש הריץ את התוכנית שהדפיסה את ה-traceback? השנייה היא: באיזה מפרש הפרויקט שלי צריך להשתמש? הן נראות זהות במסוף כי על שתיהן עונים בהקלדת python3, ויש להן בעלים שונים, נתיבי שדרוג שונים ורדיוס השפעה שונים.

כלי מערכת כרוך למפרש שאיתו נשלחה ההפצה שלו, יחד עם המודולים המקומפלים שנבנו כנגד ה-ABI של אותו מפרש. פרויקט כרוך לכל סביבה שתיצרו עבורו. העברת ברירת המחדל של המערכת משנה את הראשונה עבור כל כלי במכונה בבת אחת; יצירת סביבה משנה את השנייה עבור תיקייה אחת.

רק אחת מהפעולות האלה הפיכה בתוך דקה. היא לא הראשונה.

איזה רכיב יצר את השגיאה

קראו את השורה הראשונה של ה-traceback ואת הקובץ ההרצה שיצר אותו לפני שתקראו כל דבר אחר. חזית שורת הפקודה, השירות בעל ההרשאות וקשרי ה-API הם חלקים נפרדים, ורק חלקם Python בכלל.

command -v openvpn3
head -n 1 "$(command -v openvpn3)"
dpkg -S "$(command -v openvpn3)" 2>/dev/null
systemctl status openvpn3-service-client --no-pager

השורה הראשונה של סקריפט מציינת את המפרש שבו ישתמש, וממפרש זה הגיע ה-traceback. שאילתת החבילה אומרת לכם למי שייך הקובץ, וזה קובע למי מותר לשנות אותו. מצב השירות עונה על שאלה שונה לגמרי: אם ה-backend בעל ההרשאות שאכן מקים הפעלות פועל.

שגיאת ייבוא מודול, סירוב הפעלה דרך D-Bus ואישור שנדחה הם שלושה שלבים שונים. שגיאת ייבוא מתרחשת לפני שקיימת הפעלה כלשהי, כך ששום תצורת VPN לא תתקן אותה, וגם שירות פעיל לא יתקן אותה. סיווג ההודעה לאחד משלושת השלבים הוא הצעד הראשון האמיתי.

מה סביבת פרויקט יכולה לתקן ומה לא

סביבת פרויקט פותרת בעיית פרויקט: הגרסאות המדויקות של הספריות שאפליקציה אחת צריכה, מבודדות מכל השאר. זה באמת שימושי, וזה הכלי הנכון כשהתוכנית שנכשלה היא סקריפט שלכם.

uv run --python 3.11 app.py
python3 -c 'import openvpn3; print(openvpn3.__file__)'

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

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

למה הפניית מפרש המערכת היא מלכודת

שינוי מפרש ברירת המחדל מושך כי נראה שהוא מתקן את ה-traceback בפקודה אחת. הוא גם שובר את ההנחה שעליה נבנה כל כלי Python ארוז במארח, והכשלים מופיעים מאוחר יותר ובמקומות לא קשורים.

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

יש גם מלכודת שמות בעצה שאנשים מוצאים. לפקודה python ללא גרסה אין משמעות אוניברסלית אחת בין הפצות וסביבות, והתייחסות אליה כאל מילה נרדפת קבועה לגרסה ראשית מסוימת מייצרת תיקונים שעובדים רק במכונה שבה נכתבו. קראו את המדיניות של המערכת שלפניכם ולא זו שבפוסט הבלוג.

מבחני קבלה נפרדים

בסוף צריכים להיות שני מבחנים, ומעבר של האחד לא אומר דבר על האחר. הראשון הוא שפקודת הלקוח הנתמכת עובדת עם המפרש שלו נארזה. השני הוא שהשירות בעל ההרשאות מקים הפעלה והמנהרה נושאת תעבורה.

openvpn3 sessions-list
openvpn3-service-client --help 2>/dev/null | head -n 3
ip -4 addr show tun0

שמרו על דרך עצמאית אל המכונה בזמן שאתם עובדים, במיוחד אם ה-VPN נושא את הגישה הניהולית היחידה שלכם. שינוי במפרש מערכת הוא בדיוק סוג העריכה שיכול להסיר את הגישה הזו באמצע הדרך.

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

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