Moje odkazy
Obsah článku:
vydáno: 26. 4. 2019 19:48, aktualizováno: 13. 1. 2020 17:33
Říká se, že když něco vypustíte na internet, už to nejde vzít zpátky – ostatní to začnou kopírovat a informace/data se nekontrolovatelně šíří. Bohužel to ale platí spíš v případech, kdy byste to vzít zpátky chtěli. A naopak jindy se může stát, že hodnotný obsah zmizí a už jej nedohledáte. Software resp. jeho zdrojové kódy se většinou neztrácejí – alespoň ne ty hojně používané programy – u nich se vždy najde někdo, kdo měl kopii a podělí se o ni s ostatními. Ale u různých menších programů a knihoven se klidně může stát, že je autor smaže a už je nedohledáte.
Tohle je jeden z důvodů, proč mít zálohované zdrojové kódy programů, které používáme. V tomto článku se tedy podíváme na to, jak tyto zálohy systematicky udržovat.
Jak se říká: buď připraven. Pak jen sáhneme do vlastních záloh – třeba až na nás příště vyskočí 404 Page not found na GitHubu (i když tam se to běžně děje i kvůli tomu, že autor jen přešel z této proprietární služby na svobodný a lépe vybavený Gitlab nebo na vlastní hosting – takže dané zdrojáky ztracené nejsou). Dalším důvodem k zálohování je příprava na situaci, že se my sami ocitneme offline nebo dojde k rozpadu globální sítě. O tom si ale povíme zase příště.
Než začneme něco dělat, je dobré si sepsat požadavky, které na dané řešení máme. Chceme něco trochu robustnějšího než když běžně klonujeme cizí zdrojáky do lokálního adresáře na disku své pracovní stanice nebo notebooku. Na druhou stranu by to mělo být jednoduché řešení s minimem závislostí. Chceme tedy:
Samozřejmě se nabízí otázka, zda nepoužít nějaké hotové řešení. Existuje řada nadstaveb nad verzovacími systémy, které jsou určené k tomu, abyste si zprovoznili vlastní hosting se vším všudy (Kallithea, Phabricator, Gitlab, Gitea a další), ale většinou jim něco chybí (např. podporují jen jeden VCS), spousta jim toho přebývá a trpí vysokou komplexitou (stovky tisíc nebo milion řádků kódu).
Proto jsem se vydal minimalistickou cestou, kdy řešení poskládám jen ze samotného verzovacího systému (Mercurial, Git a v budoucnu možná další) a ze základních nástrojů poskytovaných operačním systémem.
Úloha je to v principu jednoduchá: potřebujeme udělat clone
vzádáleného úložiště, a pak v periodických intervalech dělat pull
, abychom si průběžně dotahovali změny. Systém potřebujeme nějak ovládat (přidávat nová úložiště) a zjišťovat, v jakém je stavu.
Operace clone
a pull
zavoláme z bashového skriptu. Přidání nového úložiště se bude dělat vzdáleně přes SSH a periodická aktualizace klasicky přes Cron.
Kromě toho budeme každý den dělat snapshot na úrovni souborového systému (Btrfs), abychom nepřišli o historii. Někomu to možná přijde zbytečně paranoidní – verzovací systém by měl přeci sám o sobě zachovávat historii – ale není tomu tak. Verzovací systémy sice historii uchovávají, ale zároveň ji umožňují přepisovat. Sice by se to dělat nemělo (zvlášť na úložišti, které si někdo jiný stahuje), ale zabránit tomu nelze. Pokud by např. někdo skrize git push --force
dostal na vzdálené úložiště destruktivní změny, historie by se ztratila i u nás na zálohovacím serveru. Pokud se tomu budeme bránit, tak zase hrozí, že se nám stahování aktualizací zasekne a nebudou se nám stahovat nové změny. Mercurial si dává větší pozor na zachování historie než Git, takže u něj bychom o dříve stažené změny přijít neměli, ale jistota je jistota. Snapshoty na úrovni Btrfs nás nestojí prakticky nic. Takže i kdyby se na původním URL objevilo třeba prázdné nebo úplně jiné úložiště, o dříve stažená data nepřijdeme.
Jednotlivé části systému běží pod různými uživateli a musí spolu nějak komunikovat. Potřebujeme tedy nějakou formu IPC (meziprocesové komunikace). Pro jednoduchost jsem vybral unixové doménové sokety (UDS) v jejich datagramové variantě (tzn. bez navazování spojení – jen posílání zpráv). Alternativně bychom mohli použít sudo
nebo SUID bit.
Pro přístup přes HTTP použijeme Apache2, vestavěné webové rozhraní Mercurialu a pro Git rozhraní cgit.
Stručně: napíšeme si jeden skript s pár funkcemi, které budeme volat buď přes SSH nebo z Cronu, a k tomu přidáme už jen nějakou konfiguraci serveru.
Neměli bychom zapomínat na ochranu soukromí.
Když totiž vystavíme svůj zálohovací server na internetu, tak tím zveřejňujeme, co nás zajímá, na čem pracujeme… což nemusí být vždy žádoucí. Na druhou stranu, některé věci zálohujeme, protože na ně chceme odkazovat a chceme je zpřístupnit i ostatním, zvlášť, když je pravděpodobné, že z původního umístění mohou zmizet.
Řešením je nenasměrovat webová rozhraní (hg serve
a cgit
) na adresář, kam zálohujeme vzdálená úložiště, ale na jiný adresář, do kterého budeme dávat pouze symbolické odkazy na úložiště určená ke zveřejnění. Ke všem (veřejným i neveřejným) pak můžeme přistupovat přes SSH (klonování na lokální disk).
Budeme potřebovat:
Vše je samozřejmě svobodný software (jinak bychom tomu nemohli důvěřovat).
Implementace spočívá v nakonfigurování systému a v napsání krátkého shellového skriptu.
Je celkem jedno, jakou distribuci zvolíme. Následující postup je pro distribuce založené na Debianu/Ubuntu, ale nepoužíváme zde nic speciálního, takže obdobně by to mělo fungovat i v jiných distribucích.
Nainstalujeme si potřebné balíčky:
apt install socat mercurial git cgit apache2
Je dobré oddělit disk pro data (časem může zabírat hodně místa – záleží, jak velkou část internetu budeme zálohovat) a pro operační systém (ten zase můžeme chtít časem přeinstalovat). Pro začátek jsem udělal 10 GB systémový disk a 40 GB datový, který budu postupně rozšiřovat (na úrovní hypervizoru je LVM).
Datový disk je připojený v /mnt/data
, což jsem nastavil v /etc/fstab
.
Každé úložiště bude mít svůj vlastní Btrfs pododdíl (subvolume) a každý den svůj vlastní snapshot. Lépe tak uvidíme, kolik místa co zabírá, a když nějaké úložiště budeme chtít vyřadit, jednoduše smažeme příslušné oddíly a nebudeme muset mazat soubor po souboru. Případně si časem můžeme nastavit kvóty pro jednotlivá uložiště, aby nám jedno nevyplýtvalo všechno místo na disku a nenarušilo zálohování ostatních.
Použil jsem systemd, protože je v mé distribuci. Pokud ale používáte jiný init systém, není problém služby spouštět přes něj.
vcs-backup-createSubvolume.service
– tato služba naslouchá na UDS a čeká na požadavky na vytvoření Btrfs oddílů pro nově zakládaná úložiště. Proto musí běžet pod rootem – mohli bychom sice změnit vlastníka disku, ale pak by tentýž uživatel mohl i mazat oddíly, takže mi přišlo vhodnější to takto izolovat a udělat z toho službu:
[Unit]
Description = VCS Backup: createSubvolume
After = network.target
[Service]
ExecStart = /usr/local/bin/vcs-backup.sh serverStartSubvolumeService
[Install]
WantedBy = multi-user.target
vcs-backup-clone.service
– tato služba funguje v principu stejně (taky čeká na požadavky na UDS) a stará se o samotné stažení zdrojových kódů z původního vzdáleného úložiště. Protože stahuje data do složky připravené v přechozím kroku s nastavenými právy, může už běžet pod neprivilegovaným uživatelem:
[Unit]
Description = VCS Backup: clone
After = network.target
[Service]
User=vcs-backup
ExecStart = /usr/local/bin/vcs-backup.sh serverStartCloneService
[Install]
WantedBy = multi-user.target
vcs-backup-web-hg.service
– tato služba zpřístupňuje veřejná mercurialová úložiště přes HTTP:
[Unit]
Description = Mercurial
After = syslog.target network.target
[Service]
User=vcs-backup
ExecStart = /usr/bin/hg serve --web-conf /mnt/data/etc/hg-serve.cfg --address 127.0.0.1 --port 16169
SuccessExitStatus = 255
[Install]
WantedBy = multi-user.target
; Obsah hg-serve.cfg:
; [paths]
; / = /mnt/data/public/hg/*
; [web]
; style = gitweb
Před ní je jako reverzní proxy Apache. Webové rozhraní pro Git je řešeno jako CGI skript, takže v systemd ho nenastavujeme.
HTTP server Apache se používá pouze pro webové rozhraní k veřejným úložištím. Každý typ verzovacího systému má vlastní subdoménu – zatím máme tedy dva virtualhosty:
Mercurial:
<VirtualHost *:80>
ServerName …
ServerAlias …
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
ProxyPass "/" "http://localhost:16169/"
ProxyPassReverse "/" "http://localhost:16169/"
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Git:
<VirtualHost *:80>
ServerName …
ServerAlias …
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
Alias /cgit-css "/usr/share/cgit/"
ScriptAlias / "/usr/lib/cgit/cgit.cgi/"
<Directory "/usr/share/cgit/">
AllowOverride None
Options None
Require all granted
</Directory>
<Directory "/usr/lib/cgit/">
AllowOverride None
Options ExecCGI FollowSymlinks
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
HTTPS jsem zde neřešil, protože na vnitřní síti mám ještě jednu reverzní proxy, která se o šifrování stará.
Pravidelně spouštěné úlohy si naplánujeme klasicky v Cronu. První stahuje nové změny (pull
):
root@zdrojaky:~# crontab -l -u vcs-backup # m h dom mon dow command 10 23 * * * /usr/local/bin/vcs-backup.sh serverPullCronTask > /mnt/data/log/pull.rec
a druhá vytváří snapshoty:
root@zdrojaky:~# crontab -l -u root # m h dom mon dow command 55 23 * * * /usr/local/bin/vcs-backup.sh serverSnapshotCronTask > /mnt/data/log/snapshot.rec
Všechny funkce jsou implementované ve skriptu vcs-backup.sh. Stažení aktuální verze:
hg clone https://hg.frantovo.cz/vcs-backup/
Pro jednoduchost se používá jeden skript na serveru i na klientovi. Při ovládání systému tak volá skript přes SSH svoji kopii nacházející se na serveru. Vše tak máme v jednom souboru (cca 230 řádek kódu), který můžeme snadno upravovat – a pak jen přes scp
nahrajeme na server.
Systém nepotřebuje žádnou databázi. Metadata jsou „zakódovaná“ v adresářové struktuře a případně v jednotlivých textových souborech (url.txt
a state.txt
). Logy periodicky prováděných operací, stejně jako výpis úložišť, jsou ve strojově čitelném textovém formátu recfile.
Jedinou věc, kterou potřebujeme nastavit, je adresa serveru v souboru ~/.config/vcs-backup/client.cfg
. Server má sice taky svůj konfigurační soubor /etc/vcs-backup/server.cfg
, ve kterém lze přepsat výchozí nastavení, ale ten není potřeba upravovat.
Když spustíme skript bez parametrů, vypíše nám funkce/příkazy svého „veřejného API“:
$ ./vcs-backup.sh Unsupported sub-command: Available sub-commands: clientListRepositories clientSubmitBackupRequest serverListRepositories serverPullCronTask serverSnapshotCronTask serverStartCloneService serverStartSubvolumeService serverSubmitBackupRequest
Z jejich názvů je zřejmé, zda se spouštějí na klientovi nebo na serveru a zda se tam volají přes Cron nebo jako služba. Nás budou zajímat hlavně ty dva klientské příkazy. Kromě toho tam jsou pro často používané operace připravené zkratky:
vcs-backup-clone-private-git vcs-backup-clone-private-hg vcs-backup-clone-public-git vcs-backup-clone-public-hg
které volají clientSubmitBackupRequest
s různými parametry. Jsou to symbolické odkazy na tentýž skript (ten se podívá, pod jakým názvem byl spuštěn, a podle toho pokračuje). Do skriptu si můžeme snadno dopsat další zkratky nebo funkce dle potřeby.
Základní operací je přidání nového úložiště.
# přidání mercurialového úložiště:
vcs-backup.sh clientSubmitBackupRequest hg "https://…";
# přidání mercurialového úložiště
# + jeho zveřejnění přes webové rozhraní:
vcs-backup.sh clientSubmitBackupRequest hg "https://…" public;
# přidání mercurialového úložiště
# + jeho zveřejnění přes webové rozhraní
# + stažení na lokální disk z naší nové zálohy:
vcs-backup.sh clientSubmitBackupRequest hg "https://…" public clone;
V případě gitu akorát píšeme git místo hg. Místo public můžeme dát private, ale povinné je to jen v případě, kdy chceme zároveň klonovat na místní disk na klientské straně.
Případně použijeme ty zkratky jako vcs-backup-clone-private-hg
, u kterých zadáme už jen URL. Práce se systémem tak není o nic náročnější než klasické hg clone https://example.com/…
nebo git clone https://example.com/…
. Získáváme ale spolehlivou zálohu, která se automaticky aktualizuje. Lokálně stažené zdrojáky také můžeme po prozkoumání smazat, ale na serveru nám zůstanou a nepřijdeme o ně.
Příkazy by měly být tzv. idempotentní, což znamená, že je můžeme volat opakovaně a výsledek bude pořád stejný – nevadí tedy, pokud nějaké úložiště (totožné URL) přidáme víckrát – přidané bude jen jednou. Hodí se to pro případ, kdy chceme podruhé něco lokálně naklonovat z našeho zálohovacího serveru, nebo když chceme změnit stav veřejný/neveřejný.
Důležité je, aby systém nebyl černá skříňka a abychom věděli, co se uvnitř děje, a mohli se snadno podívat, v jakém je stavu. Skript proto umožňuje vypsat zálohovaná úložiště a jejich stav, velikost a čas poslední změny:
$ ssh vcs-backup@$server vcs-backup.sh serverListRepositories | relpipe-in-recfile | relpipe-out-tabular repository: ╭───────────────┬───────────────────────────────────────────────────────┬────────────────┬─────────────────┬────────────────────────────────────────────────────────────────────┬───────────────┬───────────────────────────╮ │ type (string) │ url (string) │ state (string) │ public (string) │ serverPath (string) │ size (string) │ lastCommit (string) │ ├───────────────┼───────────────────────────────────────────────────────┼────────────────┼─────────────────┼────────────────────────────────────────────────────────────────────┼───────────────┼───────────────────────────┤ │ git │ https://github.com/bafe/gr-pocsag │ cloned │ true │ /mnt/data/current/git/github.com/bafe/gr-pocsag │ 71935 │ 2013-01-06 15:02:46 +0100 │ │ git │ https://github.com/Bystroushaak/clanky │ cloned │ true │ /mnt/data/current/git/github.com/Bystroushaak/clanky │ 98421427 │ 2019-04-18 12:51:25 +0200 │ │ git │ https://github.com/clibs/dumpasn1 │ cloned │ true │ /mnt/data/current/git/github.com/clibs/dumpasn1 │ 55006 │ 2014-06-26 22:57:50 +0900 │ │ git │ https://github.com/FreeSpacenav/libspnav │ cloned │ true │ /mnt/data/current/git/github.com/FreeSpacenav/libspnav │ 99028 │ 2018-08-23 05:26:22 +0300 │ │ git │ https://github.com/JaroslavTulach/sieve │ cloned │ true │ /mnt/data/current/git/github.com/JaroslavTulach/sieve │ 105181 │ 2017-02-16 04:19:33 +0100 │ │ git │ https://github.com/JaroslavTulach/talk2compiler │ cloned │ true │ /mnt/data/current/git/github.com/JaroslavTulach/talk2compiler │ 48963 │ 2019-04-09 11:50:25 +0200 │ │ git │ https://github.com/rvoicilas/inotify-tools │ cloned │ true │ /mnt/data/current/git/github.com/rvoicilas/inotify-tools │ 325646 │ 2018-03-06 10:26:28 +0200 │ │ git │ https://github.com/vlm/asn1c │ cloned │ true │ /mnt/data/current/git/github.com/vlm/asn1c │ 20712839 │ 2019-02-10 01:15:52 -0800 │ │ hg │ https://bitbucket.org/pidgin/main │ cloned │ true │ /mnt/data/current/hg/bitbucket.org/pidgin/main │ 179601587 │ 2019-04-15 07:00:44 +0000 │ │ hg │ https://hg.frantovo.cz/alt2xml │ cloned │ true │ /mnt/data/current/hg/hg.frantovo.cz/alt2xml │ 426611 │ 2014-10-29 02:03:14 +0100 │ │ hg │ https://hg.frantovo.cz/spacenav/spacenav-demo-qt │ cloned │ true │ /mnt/data/current/hg/hg.frantovo.cz/spacenav/spacenav-demo-qt │ 42225 │ 2019-03-07 18:33:22 +0100 │ │ hg │ https://hg.frantovo.cz/spacenav/spacenav-lib-hack │ cloned │ true │ /mnt/data/current/hg/hg.frantovo.cz/spacenav/spacenav-lib-hack │ 31380 │ 2019-03-09 12:30:52 +0100 │ │ hg │ https://hg.frantovo.cz/spacenav/spacenav-simulator-qt │ cloned │ true │ /mnt/data/current/hg/hg.frantovo.cz/spacenav/spacenav-simulator-qt │ 36094 │ 2019-03-15 00:14:25 +0100 │ │ hg │ https://hg.frantovo.cz/sql-api │ cloned │ true │ /mnt/data/current/hg/hg.frantovo.cz/sql-api │ 13638 │ 2014-09-02 10:25:23 +0200 │ │ hg │ https://hg.frantovo.cz/sql-dk │ cloned │ true │ /mnt/data/current/hg/hg.frantovo.cz/sql-dk │ 592699 │ 2019-03-04 22:28:29 +0100 │ │ hg │ https://hg.frantovo.cz/telco-dictionary │ cloned │ true │ /mnt/data/current/hg/hg.frantovo.cz/telco-dictionary │ 185192 │ 2014-04-29 12:16:27 +0200 │ ╰───────────────┴───────────────────────────────────────────────────────┴────────────────┴─────────────────┴────────────────────────────────────────────────────────────────────┴───────────────┴───────────────────────────╯ Record count: 16
Aktualizaci všech úložišť budeme normálně spouštět z Cronu, ale můžeme si ji pustit i ručně a prohlédnout si výsledky:
$ ssh vcs-backup@$server vcs-backup.sh serverPullCronTask | relpipe-in-recfile | relpipe-out-tabular pull: ╭────────────────────────────────────────────────────────────────────┬───────────────┬────────────────┬───────────────────────────┬───────────────────────────┬───────────────────┬─────────────────────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ serverPath (string) │ type (string) │ state (string) │ started (string) │ finished (string) │ duration (string) │ resultCode (string) │ message (string) │ ├────────────────────────────────────────────────────────────────────┼───────────────┼────────────────┼───────────────────────────┼───────────────────────────┼───────────────────┼─────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ /mnt/data/current/git/github.com/bafe/gr-pocsag │ git │ cloned │ 2019-04-24T20:31:04+00:00 │ 2019-04-24T20:31:05+00:00 │ 674 │ 0 │ │ │ /mnt/data/current/git/github.com/Bystroushaak/clanky │ git │ cloned │ 2019-04-24T20:31:05+00:00 │ 2019-04-24T20:31:06+00:00 │ 600 │ 0 │ │ │ /mnt/data/current/git/github.com/clibs/dumpasn1 │ git │ cloned │ 2019-04-24T20:31:06+00:00 │ 2019-04-24T20:31:06+00:00 │ 607 │ 0 │ │ │ /mnt/data/current/git/github.com/FreeSpacenav/libspnav │ git │ cloned │ 2019-04-24T20:31:06+00:00 │ 2019-04-24T20:31:07+00:00 │ 627 │ 0 │ │ │ /mnt/data/current/git/github.com/JaroslavTulach/sieve │ git │ cloned │ 2019-04-24T20:31:07+00:00 │ 2019-04-24T20:31:08+00:00 │ 583 │ 0 │ │ │ /mnt/data/current/git/github.com/JaroslavTulach/talk2compiler │ git │ cloned │ 2019-04-24T20:31:08+00:00 │ 2019-04-24T20:31:08+00:00 │ 615 │ 0 │ │ │ /mnt/data/current/git/github.com/rvoicilas/inotify-tools │ git │ cloned │ 2019-04-24T20:31:08+00:00 │ 2019-04-24T20:31:09+00:00 │ 641 │ 0 │ │ │ /mnt/data/current/git/github.com/vlm/asn1c │ git │ cloned │ 2019-04-24T20:31:09+00:00 │ 2019-04-24T20:31:10+00:00 │ 694 │ 0 │ │ │ /mnt/data/current/hg/bitbucket.org/pidgin/main │ hg │ cloned │ 2019-04-24T20:31:10+00:00 │ 2019-04-24T20:31:11+00:00 │ 1395 │ 0 │ pulling from https://bitbucket.org/pidgin/main↲searching for changes↲no changes found │ │ /mnt/data/current/hg/hg.frantovo.cz/alt2xml │ hg │ cloned │ 2019-04-24T20:31:11+00:00 │ 2019-04-24T20:31:13+00:00 │ 1525 │ 0 │ pulling from https://hg.frantovo.cz/alt2xml↲searching for changes↲no changes found │ │ /mnt/data/current/hg/hg.frantovo.cz/spacenav/spacenav-demo-qt │ hg │ cloned │ 2019-04-24T20:31:13+00:00 │ 2019-04-24T20:31:14+00:00 │ 1318 │ 0 │ pulling from https://hg.frantovo.cz/spacenav/spacenav-demo-qt↲searching for changes↲no changes found │ │ /mnt/data/current/hg/hg.frantovo.cz/spacenav/spacenav-lib-hack │ hg │ cloned │ 2019-04-24T20:31:14+00:00 │ 2019-04-24T20:31:16+00:00 │ 1656 │ 0 │ pulling from https://hg.frantovo.cz/spacenav/spacenav-lib-hack↲searching for changes↲no changes found │ │ /mnt/data/current/hg/hg.frantovo.cz/spacenav/spacenav-simulator-qt │ hg │ cloned │ 2019-04-24T20:31:16+00:00 │ 2019-04-24T20:31:16+00:00 │ 668 │ 0 │ pulling from https://hg.frantovo.cz/spacenav/spacenav-simulator-qt↲searching for changes↲no changes found │ │ /mnt/data/current/hg/hg.frantovo.cz/sql-api │ hg │ cloned │ 2019-04-24T20:31:17+00:00 │ 2019-04-24T20:31:18+00:00 │ 1401 │ 0 │ pulling from https://hg.frantovo.cz/sql-api↲searching for changes↲no changes found │ │ /mnt/data/current/hg/hg.frantovo.cz/sql-dk │ hg │ cloned │ 2019-04-24T20:31:18+00:00 │ 2019-04-24T20:31:19+00:00 │ 1247 │ 0 │ pulling from https://hg.frantovo.cz/sql-dk↲searching for changes↲no changes found │ │ /mnt/data/current/hg/hg.frantovo.cz/telco-dictionary │ hg │ cloned │ 2019-04-24T20:31:19+00:00 │ 2019-04-24T20:31:21+00:00 │ 2003 │ 0 │ pulling from https://hg.frantovo.cz/telco-dictionary↲searching for changes↲no changes found │ ╰────────────────────────────────────────────────────────────────────┴───────────────┴────────────────┴───────────────────────────┴───────────────────────────┴───────────────────┴─────────────────────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────╯ Record count: 16
V terminálu jsou tabulky barevné:
Samotný skript poskytuje data ve strojově čitelném formátu zvaném recfile, který můžeme dále zpracovat pomocí GNU Recutils nebo Relational pipes. Ukázky výše pocházejí z výstupního filtru relpipe-out-tabular
, ale máme i řadu jiných možností, jak si data naformátujeme (např. je můžeme pomocí relpipe-out-ods
převést do formátu ODS a otevřít v LibreOffice Calc) nebo je můžeme různě fitrovat a tranformovat, ať už v GNU Guile (Scheme), XQuery, XSLT (např. z nich generovat XHTML stránku, která bude dostupná přes HTTP) nebo pomocí základních nástrojů jako jsou relační varianty grep, cut nebo sed.
Díky tomuto přístupu můžeme se systémem pracovat jako s relační databází a psát podobné dotazy, přestože tam žádná databáze není a data pocházejí z různých zdrojů – některá jsou zakódovaná v adresářové struktuře, některá uložená v jednoduchých textových souborech, některé se dopočítávají za chodu (např. velikost úložiště nebo čas poslední změny). Je to tedy něco jako databázový pohled (view), přes který se díváme na stav našeho systému.
Můžeme si tak snadno přidat např. kontroly, že všechny aktualizace proběhly v pořádku (resultCode == 0
), sledovat stav v Zabbixu nebo jiném monitorovacím systému (dají se z toho kreslit i grafy velikostí či doby stahování) nebo si nechat posílat e-maily (to umí i Cron).
Jedná se o standardní webové rozhraní Mercurialu a cgit. Z nich se dá klonovat nebo si na nich prohlížet zdrojové kódy. Ukázka z mého úložiště:
Vše ostatní (např. odstranění některého ze zálohovaných úložišť) se zatím řeší ručním zásahem na serveru. Skript obsahuje funkci allRepositories()
, díky které se dá v cyklu iterovat přes všechna úložiště – není tedy problém si tam dopsat libovolnou další operaci, pokud budeme něco potřebovat často a reprodukovatelně.
Cílem tentokrát nebylo vytvářet softwarový produkt, ale nakonfigurovat si systém tak, aby mi zálohoval zdrojové kódy projektů, o které bych nerad přišel. Tak snad to pomůže i někomu dalšímu. Čím více lidí bude zálohovat, tím je menší riziko, že se nějaké zajímavé zdrojáky ztratí. (distribuované verzovací systémy naštěstí takové zálohování skvěle podporují) Většinou programuji v Javě, což je o několik úrovní abstrakce výš – a není od věci si občas něco napsat jen s spoužitím základních prostředků, které jsou dostupné v operačním systému. Časem to možná do té Javy (GraalVM?) přepíši a udělám nějaké robustnější řešení, ale první verzi jsem chtěl pojmout spíš jako konfiguraci systému než vývoj nějakého softwaru, proto je to jen shellový skript.
Témata: [verzovací systémy] [Bash]
Zmínil jste, že použijete virtuální počítač. Zajímalo by mne, jestli mu přidělíte oddíl na disku nebo se všechna data ukládají do soubory s obrazem disku (např. qcow2, VDI, …). S VDI (VirtualBox) a VHD (Windows) mám špatnou zkušenost – při poškození „nadřazeného“ souborového systému během používání (asi něco bylo v cachi) se poškodil.
Já osobně bych virtuálnímu stroji dal jeden či více oddílů s LVM, které dostane jako samostatné disky nebo přes NBD, a bootoval bych s jádrem a initrd v souboru (QEMU volba -kernel
). To samozřejmě potřebuje trochu víc práce (jádro uložené mimo „disk“), ale asi by to mohlo být méně náchylné k selhání.
Na hostitelském počítači mám KVM a disky klasicky v LVM. COW je už uvnitř toho virtuálu (Btrfs) a mít ještě jeden COW pod tím by nebylo optimální. Disky tam mám připojené tak, že jsou uvnitř vidět jako /dev/vda
a vdb
. NBD by šlo taky použít, ale to by mi dávalo smysl spíš, kdyby virtuálky běžely na jiném počítači, než kde jsou disky.
Ta volba -kernel
je zajímavá, ale zatím jsem to ještě nikdy nepoužil – jádro mám normálně uvnitř a aktualizuje se zevnitř z distribučních balíčků.