خرگوش کے سوراخ سے نیچے گرنا: ایک وارنش دوبارہ لوڈ کرنے میں ناکامی کی کہانی - حصہ 1

بھوتنوشنکاپچھلے 20 منٹوں سے بٹنوں پر ہتھوڑا مارتے ہوئے گویا اس کی زندگی اس پر منحصر ہے، اپنی آنکھوں میں نیم جنگلی نظر اور ایک دھیمی مسکراہٹ کے ساتھ میری طرف متوجہ ہوا - "یار، مجھے لگتا ہے کہ میں سمجھ گیا ہوں۔"

"یہاں دیکھو،" وہ اسکرین پر موجود علامتوں میں سے ایک کی طرف اشارہ کرتے ہوئے کہتا ہے، "میں اپنی سرخ ٹوپی پر شرط لگاتا ہوں کہ اگر ہم یہاں وہی شامل کریں جو میں نے آپ کو ابھی بھیجا ہے،" کوڈ کے دوسرے حصے کی طرف اشارہ کرتے ہوئے، "غلطی اب نہیں رہے گی۔ دکھایا جائے گا۔"

تھوڑا سا پریشان اور تھکا ہوا، میں نے سیڈ ایکسپریشن میں ترمیم کی جس پر ہم تھوڑی دیر سے کام کر رہے ہیں، فائل کو محفوظ کریں اور چلائیں systemctl varnish reload. غلطی کا پیغام غائب ہو گیا ہے...

"میں نے امیدوار کے ساتھ ای میلز کا تبادلہ کیا،" میرے ساتھی نے جاری رکھا، جب اس کی مسکراہٹ خوشی کی حقیقی مسکراہٹ میں بدل گئی، "یہ اچانک مجھ پر آشکار ہوا کہ یہ بالکل وہی مسئلہ ہے!"

یہ سب کیسے شروع ہوا۔

مضمون اس بات کو سمجھتا ہے کہ bash، awk، sed اور systemd کیسے کام کرتے ہیں۔ وارنش کے علم کو ترجیح دی جاتی ہے، لیکن اس کی ضرورت نہیں ہے۔
ٹکڑوں میں ٹائم سٹیمپس کو تبدیل کر دیا گیا ہے۔
کے ساتھ لکھا گیا۔ بھوتنوشنکا.
یہ متن دو ہفتے قبل انگریزی میں شائع ہونے والے اصل کا ترجمہ ہے۔ ترجمہ بوکوڈن.

موسم خزاں کی ایک اور گرم صبح کو سورج کی چمک کھڑکیوں سے چمکتی ہے، تازہ تیار کیفین سے بھرپور مشروب کا ایک کپ کی بورڈ سے دور رہتا ہے، آپ کے ہیڈ فونز میں آوازوں کی آپ کی پسندیدہ سمفنی، مکینیکل کی بورڈز کی سرسراہٹ کو غرق کرتی ہے، اور پہلا داخلہ۔ کنبن بورڈ پر بیک لاگ ٹکٹوں کی فہرست میں "انویسٹی گیٹ وارنش ریلوڈ" sh: echo: I/O error in staging" (اسٹیجنگ میں "varnishreload sh: echo: I/O error" کی تحقیقات کریں)۔ جب وارنش کی بات آتی ہے، تو غلطیوں کے لیے کوئی گنجائش موجود ہے اور نہیں ہو سکتی، چاہے ان کے نتیجے میں اس معاملے کی طرح کوئی مسئلہ نہ ہو۔

ان لوگوں کے لیے جو واقف نہیں ہیں۔ وارنش لوڈ، یہ ایک سادہ شیل اسکرپٹ ہے جسے کنفیگریشن کو دوبارہ لوڈ کرنے کے لیے استعمال کیا جاتا ہے۔ وارنش - VCL بھی کہا جاتا ہے۔

جیسا کہ ٹکٹ کے عنوان سے پتہ چلتا ہے، اسٹیج پر موجود سرورز میں سے ایک پر خرابی پیدا ہوئی، اور چونکہ مجھے یقین تھا کہ اسٹیج پر وارنش روٹنگ ٹھیک سے کام کر رہی ہے، اس لیے میں نے سمجھا کہ یہ ایک معمولی غلطی ہوگی۔ لہذا، صرف ایک پیغام جو پہلے سے بند آؤٹ پٹ اسٹریم میں ختم ہوا۔ میں اپنے لیے ٹکٹ لیتا ہوں، پورے اعتماد کے ساتھ کہ میں اسے 30 منٹ سے بھی کم وقت میں تیار کردوں گا، ایک اور کوڑے کے بورڈ کو صاف کرنے کے لیے اپنی پیٹھ تھپتھپاتا ہوں اور مزید اہم معاملات کی طرف لوٹتا ہوں۔

200 کلومیٹر فی گھنٹہ کی رفتار سے دیوار سے ٹکرا جانا

فائل کھول رہا ہے۔ varnishreload، ڈیبین اسٹریچ چلانے والے سرورز میں سے ایک پر، میں نے 200 لائنوں سے کم لمبی شیل اسکرپٹ دیکھی۔

اسکرپٹ سے گزرنے کے بعد، میں نے ایسی کوئی چیز نہیں دیکھی جس کے نتیجے میں اسے ٹرمینل سے براہ راست متعدد بار چلانے میں پریشانی کا سامنا کرنا پڑ سکتا ہے۔

آخر یہ ایک مرحلہ ہے، اگر ٹوٹ بھی جائے تو کوئی شکایت نہیں کرے گا، ٹھیک ہے... زیادہ نہیں۔ میں اسکرپٹ چلاتا ہوں اور دیکھتا ہوں کہ ٹرمینل پر کیا لکھا جائے گا، لیکن غلطیاں اب نظر نہیں آتیں۔

اس بات کو یقینی بنانے کے لیے کچھ اور دوڑتے ہیں کہ میں بغیر کسی اضافی کوشش کے غلطی کو دوبارہ پیش نہیں کر سکتا، اور میں یہ جاننا شروع کر رہا ہوں کہ اس اسکرپٹ کو کیسے تبدیل کیا جائے اور اسے اب بھی غلطی سے دوچار کیا جائے۔

کیا اسکرپٹ STDOUT کو اوور رائیڈ کر سکتا ہے (استعمال کرتے ہوئے > &-)؟ یا STDERR؟ ان میں سے کسی نے بھی آخر کار کام نہیں کیا۔

بظاہر سسٹمڈ کسی نہ کسی طرح اسٹارٹ اپ ماحول کو تبدیل کرتا ہے، لیکن کیسے، اور کیوں؟
میں vim کھولتا ہوں اور ترمیم کرتا ہوں۔ varnishreloadشامل کر رہا ہے۔ set -x شیبانگ کے بالکل نیچے، امید ہے کہ اسکرپٹ کی ڈیبگ آؤٹ پٹ کچھ روشنی ڈالے گی۔

فائل کو درست کر دیا گیا ہے، لہذا میں وارنش کو دوبارہ لوڈ کرتا ہوں اور دیکھتا ہوں کہ اس تبدیلی نے سب کچھ مکمل طور پر توڑ دیا ہے... ایگزاسٹ ایک مکمل گڑبڑ ہے، جس میں سی کی طرح کا کوڈ موجود ہے۔ یہاں تک کہ ٹرمینل میں اسکرول کرنا کافی نہیں ہے کہ یہ کہاں سے شروع ہوتا ہے۔ میں مکمل طور پر الجھن میں ہوں. کیا ڈیبگنگ موڈ اسکرپٹ میں شروع کیے گئے پروگراموں کے آپریشن کو متاثر کر سکتا ہے؟ نہیں، یہ بکواس ہے۔ شیل میں بگ؟ کئی ممکنہ منظرنامے میرے سر سے کاکروچ کی طرح مختلف سمتوں میں دوڑ رہے ہیں۔ کیفین والے مشروب کا کپ فوری طور پر خالی کر دیا جاتا ہے، سٹاک کو بھرنے کے لیے باورچی خانے کا ایک تیز سفر اور... ہم چلتے ہیں۔ میں اسکرپٹ کو کھولتا ہوں اور شیبانگ کو قریب سے دیکھتا ہوں: #!/bin/sh.

/bin/sh - یہ bash کے لیے صرف ایک symlink ہے، تو اسکرپٹ کی تشریح POSIX-compatible موڈ میں کی جاتی ہے، ٹھیک ہے؟ نہیں تو! ڈیبیان پر ڈیفالٹ شیل ڈیش ہے، اور بالکل ایسا ہی لگتا ہے۔ حوالہ دیتا ہے /bin/sh.

# ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Jan 24  2017 /bin/sh -> dash

ایک امتحان کے طور پر، میں نے شیبانگ کو تبدیل کر دیا۔ #!/bin/bash، حذف کر دیا گیا۔ set -x اور دوبارہ کوشش کی. آخر کار، وارنش کے بعد میں دوبارہ شروع ہونے پر، آؤٹ پٹ میں ایک قابل برداشت غلطی نمودار ہوئی:

Jan 01 12:00:00 hostname varnishreload[32604]: /usr/sbin/varnishreload: line 124: echo: write error: Broken pipe
Jan 01 12:00:00 hostname varnishreload[32604]: VCL 'reload_20190101_120000_32604' compiled

لائن 124، یہ یہاں ہے!

114 find_vcl_file() {
115         VCL_SHOW=$(varnishadm vcl.show -v "$VCL_NAME" 2>&1) || :
116         VCL_FILE=$(
117                 echo "$VCL_SHOW" |
118                 awk '$1 == "//" && $2 == "VCL.SHOW" {print; exit}' | {
119                         # all this ceremony to handle blanks in FILE
120                         read -r DELIM VCL_SHOW INDEX SIZE FILE
121                         echo "$FILE"
122                 }
123         ) || :
124
125         if [ -z "$VCL_FILE" ]
126         then
127                 echo "$VCL_SHOW" >&2
128                 fail "failed to get the VCL file name"
129         fi
130
131         echo "$VCL_FILE"
132 }

لیکن جیسا کہ پتہ چلتا ہے، لائن 124 بالکل خالی ہے اور کوئی دلچسپی نہیں ہے۔ میں صرف یہ فرض کر سکتا ہوں کہ غلطی لائن 116 سے شروع ہونے والی ملٹی لائن سٹرنگ کے حصے کے طور پر ہوئی ہے۔
آخر متغیر کو کیا لکھا جاتا ہے؟ VCL_FILE مندرجہ بالا ذیلی شیل کو انجام دینے کے نتیجے میں؟

شروع میں، یہ متغیر کے مواد بھیجتا ہے۔ VLC_SHOWپائپ کے ذریعے کمانڈ کی پیروی کرتے ہوئے، لائن 115 پر بنایا گیا۔ اور پھر وہاں کیا ہوتا ہے؟

سب سے پہلے، یہ وہاں استعمال کیا جاتا ہے varnishadmجو کہ وارنش انسٹالیشن پیکج کا حصہ ہے، بغیر دوبارہ شروع کیے وارنش کو ترتیب دینے کے لیے۔

ذیلی ٹیم vcl.show -v میں بیان کردہ پوری VCL کنفیگریشن کو آؤٹ پٹ کرنے کے لیے استعمال کیا جاتا ہے۔ ${VCL_NAME}، STDOUT تک۔

موجودہ فعال VCL کنفیگریشن کو ظاہر کرنے کے ساتھ ساتھ وارنش روٹنگ کنفیگریشن کے کئی پچھلے ورژن جو ابھی تک میموری میں ہیں، آپ کمانڈ استعمال کر سکتے ہیں۔ varnishadm vcl.list، جس کا آؤٹ پٹ نیچے کی طرح ہو گا:

discarded   cold/busy       1 reload_20190101_120000_11903
discarded   cold/busy       2 reload_20190101_120000_12068
discarded   cold/busy       16 reload_20190101_120000_12259
discarded   cold/busy       16 reload_20190101_120000_12299
discarded   cold/busy       28 reload_20190101_120000_12357
active      auto/warm       32 reload_20190101_120000_12397
available   auto/warm       0 reload_20190101_120000_12587

متغیر قدر ${VCL_NAME} اسکرپٹ کے دوسرے حصے میں انسٹال ہے۔ varnishreload موجودہ فعال VCL کے نام پر، اگر کوئی ہے۔ اس صورت میں یہ "reload_20190101_120000_12397" ہوگا۔

بہت اچھا، متغیر ${VCL_SHOW} وارنش کے لیے مکمل کنفیگریشن پر مشتمل ہے، ابھی کے لیے صاف۔ اب میں آخر کار سمجھ گیا کہ ڈیش آؤٹ پٹ کیوں ہے۔ set -x اتنا ٹوٹا ہوا نکلا - اس میں نتیجے کی ترتیب کے مواد شامل تھے۔

یہ سمجھنا ضروری ہے کہ ایک مکمل VCL کنفیگریشن کو اکثر کئی فائلوں سے اکٹھا کیا جا سکتا ہے۔ سی طرز کے تبصرے اس بات کی نشاندہی کرنے کے لیے استعمال کیے جاتے ہیں کہ بعض کنفیگریشن فائلوں کو دوسروں میں کہاں شامل کیا گیا ہے، اور کوڈ کے ٹکڑوں کی درج ذیل لائن اسی کے بارے میں ہے۔
شامل فائلوں کو بیان کرنے والے تبصروں کا نحو درج ذیل فارمیٹ میں ہے:

// VCL.SHOW <NUM> <NUM> <FILENAME>

اس تناظر میں نمبر اہم نہیں ہیں، ہمیں فائل کے نام میں دلچسپی ہے۔

لائن 116 سے شروع ہونے والے کمانڈز کی دلدل میں آخر کیا ہوتا ہے؟
آئیے اس کا پتہ لگائیں۔
ٹیم چار حصوں پر مشتمل ہے:

  1. سادہ echo، جو متغیر کی قدر پرنٹ کرتا ہے۔ ${VCL_SHOW}
    echo "$VCL_SHOW"
  2. awk، جو ایک لائن (ریکارڈ) کی تلاش کرتا ہے جہاں متن کو توڑنے کے بعد پہلا فیلڈ "//" ہے، اور دوسرا "VCL.SHOW" ہے۔
    اوک ان نمونوں سے مماثل پہلی لائن لکھے گا اور پھر فوری طور پر کارروائی روک دے گا۔

    awk '$1 == "//" && $2 == "VCL.SHOW" {print; exit}'
  3. کوڈ کا ایک بلاک جو فیلڈ ویلیوز کو خالی جگہوں سے الگ کرکے پانچ متغیرات میں محفوظ کرتا ہے۔ پانچواں FILE متغیر باقی لائن وصول کرتا ہے۔ آخر میں، آخری بازگشت متغیر کے مواد کو لکھتی ہے۔ ${FILE}.
    { read -r DELIM VCL_SHOW INDEX SIZE FILE; echo "$FILE" }
  4. چونکہ تمام مراحل 1 سے 3 سب شیل میں بند ہیں، قدر کو آؤٹ پٹ کرتے ہیں۔ $FILE متغیر پر لکھا جائے گا۔ VCL_FILE.

جیسا کہ لائن 119 پر تبصرہ تجویز کرتا ہے، اس کا واحد مقصد ایسے معاملات کو قابل اعتماد طریقے سے ہینڈل کرنا ہے جہاں VCL فائلوں کو ان کے ناموں میں خالی جگہوں کے ساتھ حوالہ دے گا۔

میں نے اصل پروسیسنگ منطق پر تبصرہ کیا ہے۔ ${VCL_FILE} اور کمانڈ کی ترتیب کو تبدیل کرنے کی کوشش کی، لیکن اس سے کچھ حاصل نہیں ہوا۔ میرے لیے سب کچھ ٹھیک کام کر رہا تھا، لیکن جب میں نے سروس شروع کی تو اس میں غلطی ہو گئی۔

ایسا لگتا ہے کہ اسکرپٹ کو دستی طور پر چلاتے وقت غلطی دوبارہ پیدا کرنے کے قابل نہیں ہے، جبکہ قیاس شدہ 30 منٹ پہلے ہی چھ بار ختم ہو چکے ہیں اور، اس کے علاوہ، ایک اعلی ترجیحی کام ظاہر ہوا ہے، جس سے دیگر معاملات کو ایک طرف دھکیل دیا گیا ہے۔ بقیہ ہفتہ مختلف قسم کے کاموں سے بھرا ہوا تھا اور صرف sed پر ایک رپورٹ اور امیدوار کے ساتھ انٹرویو کے ذریعے تھوڑا سا گھٹا ہوا تھا۔ میں غلطی کے ساتھ مسئلہ varnishreload وقت کی ریت میں ناقابل واپسی کھو گیا تھا۔

آپ کا نام نہاد sed-fu... دراصل... کوڑا کرکٹ ہے۔

اگلے ہفتے میرے پاس ایک کافی مفت دن تھا، لہذا میں نے دوبارہ اس ٹکٹ سے نمٹنے کا فیصلہ کیا۔ مجھے امید تھی کہ میرے دماغ میں اس سارے عرصے میں کوئی نہ کوئی پس منظر کا عمل اس مسئلے کا حل تلاش کرتا رہا ہے اور اس بار میں ضرور سمجھوں گا کہ کیا ہو رہا ہے۔

چونکہ آخری بار صرف کوڈ کو تبدیل کرنے سے کوئی فائدہ نہیں ہوا تھا، اس لیے میں نے اسے 116 لائن سے شروع کرتے ہوئے دوبارہ لکھنے کا فیصلہ کیا۔ کسی بھی صورت میں، موجودہ کوڈ بیوقوف تھا. اور اسے استعمال کرنے کی قطعاً ضرورت نہیں ہے۔ read.

غلطی کو دوبارہ دیکھنا:
sh: echo: broken pipe - اس کمانڈ میں دو جگہوں پر بازگشت ظاہر ہوتی ہے، لیکن مجھے شبہ ہے کہ پہلا مجرم (یا کم از کم ایک ساتھی) ہے۔ اوک بھی اعتماد کو متاثر نہیں کرتا ہے۔ اور اگر یہ واقعی ہے۔ awk | {read; echo} ڈیزائن ان تمام مسائل کی طرف جاتا ہے، کیوں اسے تبدیل نہیں؟ یہ ون لائن کمانڈ awk کی تمام خصوصیات اور یہاں تک کہ اس اضافی کو استعمال نہیں کرتی ہے۔ read اس کے علاوہ.

گزشتہ ہفتے سے ایک رپورٹ تھی sedمیں اپنی نئی حاصل کردہ مہارتوں کو آزمانا اور آسان بنانا چاہتا تھا۔ echo | awk | { read; echo} ایک زیادہ قابل فہم میں echo | sed. اگرچہ یہ یقینی طور پر بگ کی نشاندہی کرنے کا بہترین طریقہ نہیں ہے، لیکن میں نے سوچا کہ میں کم از کم اپنے sed-fu کو آزماؤں گا اور شاید اس مسئلے کے بارے میں کچھ نیا سیکھوں گا۔ راستے میں، میں نے اپنے ساتھی، سیڈ ٹاک کے مصنف سے کہا کہ وہ زیادہ موثر سیڈ اسکرپٹ کے ساتھ آنے میں میری مدد کرے۔

میں نے مواد گرا دیا۔ varnishadm vcl.show -v "$VCL_NAME" ایک فائل میں، تاکہ میں سروس ریبوٹس کی کسی پریشانی کے بغیر sed اسکرپٹ لکھنے پر توجہ مرکوز کر سکوں۔

بالکل اس کی ایک مختصر وضاحت کہ کس طرح sed پروسیس ان پٹ میں پایا جا سکتا ہے۔ اس کا GNU دستی. sed ذرائع میں علامت n واضح طور پر ایک لائن الگ کرنے والے کے طور پر بیان کیا گیا ہے۔

کئی پاسوں میں اور میرے ساتھی کی سفارشات کے ساتھ، ہم نے ایک سیڈ اسکرپٹ لکھا جس نے پوری اصل لائن 116 جیسا ہی نتیجہ دیا۔

ذیل میں ان پٹ ڈیٹا کے ساتھ ایک نمونہ فائل ہے:

> cat vcl-example.vcl
Text
// VCL.SHOW 0 1578 file with 3 spaces.vcl
More text
// VCL.SHOW 0 1578 file.vcl
Even more text
// VCL.SHOW 0 1578 file with TWOspaces.vcl
Final text

یہ اوپر کی وضاحت سے واضح نہیں ہوسکتا ہے، لیکن ہم صرف پہلے تبصرہ میں دلچسپی رکھتے ہیں // VCL.SHOW، اور ان پٹ ڈیٹا میں ان میں سے کئی ہو سکتے ہیں۔ یہی وجہ ہے کہ اصل awk پہلے میچ کے بعد ختم ہو جاتا ہے۔

# шаг первый, вывести только строки с комментариями
# используя возможности sed, определяется символ-разделитель с помощью конструкции '#' вместо обычно используемого '/', за счёт этого не придётся экранировать косые в искомом комментарии
# определяется регулярное выражение “// VCL.SHOW”, для поиска строк с определенным шаблоном
# флаг -n позаботится о том, чтобы sed не выводил все входные данные, как он это делает по умолчанию (см. ссылку выше)
# -E позволяет использовать расширенные регулярные выражения
> cat vcl-processor-1.sed
#// VCL.SHOW#p
> sed -En -f vcl-processor-1.sed vcl-example.vcl
// VCL.SHOW 0 1578 file with 3 spaces.vcl
// VCL.SHOW 0 1578 file.vcl
// VCL.SHOW 0 1578 file with TWOspaces.vcl

# шаг второй, вывести только имя файла
# используя команду “substitute”, с группами внутри регулярных выражений, отображается только нужная группa
# и это делается только для совпадений, ранее описанного поиска
> cat vcl-processor-2.sed
#// VCL.SHOW# {
    s#.* [0-9]+ [0-9]+ (.*)$#1#
    p
}
> sed -En -f vcl-processor-2.sed vcl-example.vcl
file with 3 spaces.vcl
file.vcl
file with TWOspaces.vcl

# шаг третий, получить только первый из результатов
# как и в случае с awk, добавляется немедленное завершения после печати первого найденного совпадения
> cat vcl-processor-3.sed
#// VCL.SHOW# {
    s#.* [0-9]+ [0-9]+ (.*)$#1#
    p
    q
}
> sed -En -f vcl-processor-3.sed vcl-example.vcl
file with 3 spaces.vcl

# шаг четвертый, схлопнуть всё в однострочник, используя двоеточия для разделения команд
> sed -En -e '#// VCL.SHOW#{s#.* [0-9]+ [0-9]+ (.*)$#1#p;q;}' vcl-example.vcl
file with 3 spaces.vcl

لہذا، varnishreload اسکرپٹ کے مندرجات کچھ اس طرح نظر آئیں گے:

VCL_FILE="$(echo "$VCL_SHOW" | sed -En '#// VCL.SHOW#{s#.*[0-9]+ [0-9]+ (.*)$#1#p;q;};')"

مندرجہ بالا منطق کو مختصراً اس طرح بیان کیا جا سکتا ہے:
اگر سٹرنگ ریگولر ایکسپریشن سے میل کھاتی ہے۔ // VCL.SHOW، پھر لالچ کے ساتھ اس متن کو کھا لیں جس میں اس لائن میں دونوں نمبر شامل ہیں، اور اس آپریشن کے بعد جو کچھ باقی رہ جاتا ہے اسے محفوظ کر لیں۔ ذخیرہ شدہ قدر کو خارج کریں اور پروگرام کو ختم کریں۔

سادہ، ہے نا؟

ہم sed اسکرپٹ اور اس حقیقت سے خوش تھے کہ اس نے تمام اصل کوڈ کی جگہ لے لی۔ میرے تمام ٹیسٹوں نے مطلوبہ نتائج دیے، اس لیے میں نے سرور پر "varnishreload" کو تبدیل کیا اور اسے دوبارہ چلایا systemctl reload varnish. بری غلطی echo: write error: Broken pipe ہمارے چہروں پر پھر ہنسی آگئی۔ آنکھ مارتا کرسر ٹرمینل کے اندھیرے خالی پن میں کسی نئی کمانڈ کے داخل ہونے کا انتظار کر رہا تھا...

ماخذ: www.habr.com

نیا تبصرہ شامل کریں