Falling Down the Rabbit Hole: The Story of One Vernish Reload Failure - 1. zatia

ghostinushanka, aurreko 20 minutuetan botoiak mailukatzen aritu ondoren, bere bizitza horren menpe egongo balitz bezala, begietan erdi basati-begirada batekin eta irribarre maltzur batekin bueltatzen zait - "Txo, uste dut lortu dudala".

"Begira hemen", dio, pantailako ikurretako bat seinalatuz, "apustua dut nire kapela gorria: hemen bidali berri dizudana gehitzen badugu", kodearen beste atal bat seinalatuz, "akatsa ez da gehiago izango. bistaratuko da".

Pixka bat harrituta eta nekatuta, pixka bat lantzen ari garen sed adierazpena aldatzen dut, fitxategia gorde eta exekutatu systemctl varnish reload. Errore-mezua desagertu da...

"Hautagaiarekin trukatu nituen mezu elektronikoak", jarraitu zuen lankideak, bere irribarrea pozaren benetako irribarre bihurtu zen bitartean, "bat-batean, hauxe arazo bera dela ulertu nuen!"

Nola hasi zen dena

Artikuluak bash, awk, sed eta systemd-ek nola funtzionatzen duten ulertzen du. Bernizaren ezagutza hobetsi da, baina ez da beharrezkoa.
Zatietako denbora-zigiluak aldatu dira.
-rekin idatzia ghostinushanka.
Testu hau duela bi aste ingelesez argitaratutako jatorrizkoaren itzulpena da; itzulpena boikoden.

Eguzkiak leiho panoramikoetatik distira egiten du udazkeneko beste goiz epel batean, kafeina aberatsa den edari prestatu berri batek teklatutik atseden hartzen du, zure soinuen sinfonia gogokoena entzungailuetan entzuten da, teklatu mekanikoen zarata itotzen du eta lehen sarrera. Kanban taulako atzerapeneko txartelen zerrendan "Ikertu bernishreload" izenburu zoritxarreko distira egiten du sh: echo: I/O error in staging" (Ikertu "varnishreload sh: echo: I/O error" eszenaratzean). Bernizatzeko orduan, akatsetarako tarterik dago eta ezin da egon, kasu honetan bezala arazorik sortzen ez badute ere.

Ezagutzen ez dutenentzat berniza-karga, konfigurazioa berriro kargatzeko erabiltzen den shell script soil bat da berniza - VCL ere deitua.

Txartelaren izenburuak dioen bezala, akatsa eszenatokiko zerbitzarietako batean gertatu da, eta ziur nengoenez eszenatokiko bernizaren bideratzea ondo funtzionatzen zuela, hau errore txiki bat izango zela suposatu nuen. Beraz, jada itxitako irteera-korronte batean amaitutako mezu bat besterik ez. Tiketa neuretzat hartzen dut, 30 minutu baino gutxiagoan prest markatuko dudala ziurtasunez, ohola beste zabor bat kentzeagatik bizkarrean jo eta kontu garrantzitsuagoetara itzultzeko.

200 km/h-ko horma baten kontra talka egitea

Fitxategia irekitzea varnishreload, Debian Stretch exekutatzen ari den zerbitzarietako batean, 200 lerro baino gutxiagoko shell script bat ikusi nuen.

Script-a pasatuta, ez nuen terminaletik zuzenean hainbat aldiz exekutatzean arazoak sor ditzakeen ezer nabaritu.

Azken finean, hau etapa bat da, apurtzen bada ere, ez da inor kexatuko, ba... ez gehiegi. Scripta exekutatu eta terminalean zer idatziko den ikusten dut, baina akatsak jada ez dira ikusten.

Beste exekuzio bat gehiago ziurtatzeko akatsa ezin dudala erreproduzitu ahalegin gehigarririk gabe, eta script hau nola aldatu eta oraindik akats bat botatzeko asmatzen hasi naiz.

Scriptak STDOUT baliogabe al dezake (erabiliz > &-)? Edo STDERR? Ez batak ez besteak ez zuten funtzionatu azkenean.

Antza denez, systemd-ek abiarazte-ingurunea aldatzen du nolabait, baina nola eta zergatik?
Vim ireki eta editatzen dut varnishreload, gehitzen set -x shebang-aren azpian, gidoiaren arazketa-irteerak argi pixka bat emango duelakoan.

Fitxategia zuzenduta dago, beraz, berniza berriro kargatu eta aldaketak dena hautsi zuela ikusten dut... Ihesak erabateko nahastea da, eta bertan C moduko kode pila daude. Terminalean mugitzea ere ez da nahikoa non hasten den aurkitzeko. Erabat nahastuta nago. Arazketa moduak eragin al dezake script batean abiarazitako programen funtzionamenduan? Ez, zentzugabekeria da. Akatsa maskorrean? Hainbat eszenatoki posible ari dira nire buruan zehar labezomorroak bezala norabide ezberdinetan. Kafeinadun edariaren kopa berehala hustu da, sukaldera bidaia azkar bat salda betetzeko eta... hara. Gidoia ireki eta shebang-ari hurbilagotik begiratzen diot: #!/bin/sh.

/bin/sh - hau bash-erako esteka sinbolikoa besterik ez da, beraz script-a POSIX-ekin bateragarria den moduan interpretatzen da, ezta? Ez da horrela! Debian-en shell lehenetsia dash da, eta horixe da hain zuzen. aipatzen du /bin/sh.

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

Proba gisa, shebang-ra aldatu nuen #!/bin/bash, ezabatu set -x eta berriro saiatu. Azkenik, bernizaren ondorengo berrabiaraztean, akats jasangarri bat agertu zen irteeran:

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. linea, hemen dago!

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 }

Baina ikusten denez, 124. linea nahiko hutsik dago eta ez du interesik. Errorea 116. lerroan hasten den lerro anitzeko kate baten zati gisa gertatu dela suposatu nezake.
Zer idazten da azkenean aldagaian? VCL_FILE goiko azpi-shell exekutazioaren ondorioz?

Hasieran, aldagaiaren edukia bidaltzen du VLC_SHOW, 115. lerroan sortua, hodiaren bidez komandoari jarraituz. Eta orduan zer gertatzen da hor?

Lehenik eta behin, bertan erabiltzen da varnishadm, bernizaren instalazio paketearen parte dena, berniza berrabiarazi gabe konfiguratzeko.

Azpitaldea vcl.show -v atalean zehaztutako VCL konfigurazio osoa ateratzeko erabiltzen da ${VCL_NAME}, STDOUT-i.

Uneko VCL konfigurazio aktiboa bistaratzeko, baita oraindik memorian dauden berniza bideratze-konfigurazioen aurreko hainbat bertsio bistaratzeko, komandoa erabil dezakezu. varnishadm vcl.list, zeinaren irteera behekoaren antzekoa izango da:

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

Balio aldakorra ${VCL_NAME} script-aren beste zati batean instalatuta dago varnishreload unean aktibo dagoen VCL izenari, halakorik badago. Kasu honetan “reload_20190101_120000_12397” izango da.

Bikaina, aldakorra ${VCL_SHOW} bernizarako konfigurazio osoa dauka, oraingoz garbi. Orain azkenean ulertzen dut zergatik den marratxoaren irteera set -x hain hautsita zegoen - ondoriozko konfigurazioaren edukia barne hartzen zuen.

Garrantzitsua da ulertzea VCL konfigurazio osoa sarritan hainbat fitxategitatik bildu daitekeela. C estiloko iruzkinak konfigurazio-fitxategi batzuk beste batzuetan non sartu diren identifikatzeko erabiltzen dira, eta horixe da kode zatiaren hurrengo lerroa.
Sartutako fitxategiak deskribatzen dituzten iruzkinen sintaxia formatu honetan dago:

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

Zenbakiak ez dira garrantzitsuak testuinguru honetan, fitxategiaren izena interesatzen zaigu.

Zer gertatzen da azkenean 116. lerroan hasten diren komandoen zingira?
Irudikatu.
Taldeak lau zati ditu:

  1. erraz echo, aldagaiaren balioa inprimatzen duena ${VCL_SHOW}
    echo "$VCL_SHOW"
  2. awk, lehen eremua, testua hautsi ondoren, “//” den lerroa (erregistroa) bilatzen duena, eta bigarrena “VCL.SHOW”.
    Awk-ek eredu hauekin bat datorren lehen lerroa idatziko du eta gero prozesatzeari utziko dio berehala.

    awk '$1 == "//" && $2 == "VCL.SHOW" {print; exit}'
  3. Eremuen balioak bost aldagaitan gordetzen dituen kode bloke bat, zuriunez bereizita. Bosgarren FILE aldagaiak lerroaren gainerakoa jasotzen du. Azkenik, azken oihartzunak aldagaiaren edukia idazten du ${FILE}.
    { read -r DELIM VCL_SHOW INDEX SIZE FILE; echo "$FILE" }
  4. 1etik 3ra bitarteko urrats guztiak azpishell batean sartuta daudenez, balioa ateraz $FILE aldagai batean idatziko da VCL_FILE.

119. lerroko iruzkinak iradokitzen duen bezala, honek VCL-k beren izenetan zuriuneak dituzten fitxategiak erreferentzia egingo dituen kasuak modu fidagarrian kudeatzeko balio du.

Jatorrizko prozesatzeko logika komentatu dut ${VCL_FILE} eta komando-sekuentzia aldatzen saiatu zen, baina ez zuen ezer ekarri. Dena ondo funtzionatu zidan, baina zerbitzua martxan jarri nuenean errore bat eman zuen.

Badirudi errorea ez dela errepikatzen scripta eskuz exekutatzen denean, ustezko 30 minutuak dagoeneko sei aldiz iraungi diren bitartean eta, gainera, lehentasun handiagoko zeregin bat agertu da, beste kontu batzuk alde batera utziz. Gainontzeko astea hainbat zereginez bete zen eta apur bat diluitu zuten sedari buruzko txosten batek eta hautagai bati egindako elkarrizketak. Errore batekin arazoa varnishreload denboraren hareetan ezinbestean galdu zen.

Zure sed-fu delakoa... benetan... zaborra da

Hurrengo astean nahiko egun libre izan nuen, horregatik berriro txartel honi aurre egitea erabaki nuen. Espero nuen nire burmuinean atzeko prozesuren bat arazo honi irtenbidea bilatzen egon izana denbora honetan guztian, eta oraingoan behin betiko ulertuko nuela zer gertatzen ari zen.

Kodea aldatzeak azken aldian lagundu ez zuenez, 116. lerrotik hasita berridaztea erabaki nuen. Nolanahi ere, zegoen kodea astakeria zen. Eta ez dago guztiz erabili beharrik read.

Erroreari berriro begiratuz:
sh: echo: broken pipe — oihartzuna bi lekutan agertzen da komando honetan, baina susmoa dut lehenengoa dela errudun (edo, gutxienez, konplize bat). Awk-ek ere ez du konfiantzarik sortzen. Eta benetan hala bada awk | {read; echo} diseinuak arazo guzti hauek ekartzen ditu, zergatik ez ordezkatu? Lerro bakarreko komando honek ez ditu awk-ren ezaugarri guztiak erabiltzen, ezta gehigarri honek ere read gainera.

Joan den asteaz geroztik txosten bat zegoen sed, Nire trebetasunak probatu eta sinplifikatu nahi nuen echo | awk | { read; echo} ulergarriago batean echo | sed. Zalantzarik gabe, hau akatsa identifikatzeko hurbilketarik onena ez den arren, nire sed-fu gutxienez probatuko nuela pentsatu nuen eta agian arazoari buruz zerbait berria ikasiko nuela. Bide horretan, sed hitzaldiaren egileari, sed gidoi eraginkorrago bat egiten laguntzeko eskatu nion.

Edukia bota nuen varnishadm vcl.show -v "$VCL_NAME" fitxategi batera, eta, beraz, sed script-a idazten zentratu ahal izango nintzen zerbitzua berrabiarazteko arazorik gabe.

Sed-ek sarrera nola prozesatzen duen jakiteko deskribapen laburra aurki daiteke bere GNU eskuliburua. Sed iturrietan ikurra n lerro-bereizle gisa esplizituki zehaztuta.

Hainbat pasetan eta nire lankidearen gomendioekin, 116 jatorrizko lerro osoaren emaitza bera ematen zuen sed script bat idatzi genuen.

Jarraian, sarrerako datuekin lagin fitxategi bat dago:

> 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

Baliteke hau goiko deskribapenetik agerikoa ez izatea, baina lehen iruzkinean bakarrik interesatzen zaigu // VCL.SHOW, eta horietako hainbat izan daitezke sarrerako datuetan. Horregatik amaitzen da jatorrizko awk lehen partidaren ostean.

# шаг первый, вывести только строки с комментариями
# используя возможности 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

Beraz, varnishreload script-aren edukiak honelako itxura izango du:

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

Aurreko logika labur-labur honela adieraz daiteke:
Katea adierazpen erregular batekin bat badator // VCL.SHOW, gero irentsi gogoz lerro honetan bi zenbakiak biltzen dituen testua, eta gorde eragiketa honen ondoren geratzen dena. Igorri gordetako balioa eta amaitu programa.

Sinplea, ezta?

Pozik geunden sed scriptarekin eta jatorrizko kode guztia ordezkatu zuelako. Nire proba guztiek nahi zituzten emaitzak eman zituzten, beraz, zerbitzarian "barnishreload" aldatu eta berriro exekutatu nuen systemctl reload varnish. Akats txarra echo: write error: Broken pipe barre egin zigun berriro aurpegira. Keinuka egiten ari den kurtsorea komando berri bat sartzeko zain zegoen terminalaren hutsune ilunean...

Iturria: www.habr.com

Gehitu iruzkin berria