कोई काम करने वाली कमांड लाइन 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 जीवनचक्र का हिस्सा है या हाथ से किया जाने वाला निदान रहना चाहिए, क्योंकि दूसरी पृष्ठभूमि टनल प्रक्रिया एक प्रतिस्पर्धी स्वामी बनाती है।

माँग पर सही आउटपुट प्रिंट करने वाली यूनिट अच्छा पहला पड़ाव है। यह अभी टनल नहीं है, और टनल होने का दिखावा नहीं करना चाहिए।

संबंधित लेख