LPS:CFEngine3
Inicializace
Instalace
Na stroji není potřeba, aby cfengine přímo běžel, je ale důležitý pro testování:
apt-get install cfengine-community git
Defaultní konfigurace cfenginu není příliš použitelná, proto je třeba pro klienta udělat:
cf-agent --bootstrap --policy-server 147.228.52.124 /etc/init.d/cfengine-community start
Agent je nastavený tak, aby sám upravil /etc/defaults/cfengine a povolil startování agenta.
Nastavení GIT
Na serveru cf.civ.zcu.cz je z /etc/profile.d/git.sh nastaveno jméno a email dle krb5 lístku. Tyto volby je třeba provést, pokud je repozitář jinde (na jiném stroji nebo se přistupuje přímo ke git repozitáři na AFS). Pokud na stroji je rozběhnutý cfengine, pak tento skript spravuje cfengine sam, stejně jako syntax soubor pro editor vim.
Používá se GIT, proto je napřed nutné jej nakonfigurovat. Získat aktuální nastavení lze příkazem:
git config -l
Nastavení reálného jména a emailu pak takto
git config --global user.name "Tvoje Jmeno" git config --global user.email tvuj_email@civ.zcu.cz
Klon repozitáře
Používají se dvě sledovací větve k repozitáří:
- master - vytvoří se automaticky při klonování, slouží jako devel
- production - je třeba jí poprvé nastavit sledování, slouží pro provozní konfiguraci
Naklonování konfigurace, sám vytvoří adresář cfengine:
cd /root git clone file:///afs/zcu.cz/project/software/git/cfengine.git cf cd cf git checkout production git branch --set-upstream production origin/production
Přidání testování syntaxe před commitem (oproti originálu změněno kopírování z git checkout-index na normální cp -r *, protože git takto nezahrnul komitovanou změnu). Pokud se klon vytvoří v /root/cf dle výše uvedeného návodu, přidá skript sám cfengine pokud na stroji běží.
cat > .git/hooks/pre-commit << EOF #!/bin/bash # Author: Nick Anderson <nick@cmdln.org> # git pre-commit hook to check CFEngine policy for syntax errors # List of files to check with cf-promises, this is relative to # masterfiles promises.cf and failsafe.cf are the standard entry # points. You might want to add any other entry points you use. checkfiles="promises.cf update.cf" cfpromises="/var/cfengine/bin/cf-promises" # I try to guess which cf-promises you want to use by looking in the # common locations, but you can manually specify path to cf-promises # cfpromises="/var/cfengine/bin/cf-promises" if [ -z "$cfpromises" ]; then echo "Unable to find cf-promises, please specify the path manually" 1>&2 echo "in $0 or install into one of the common locations ($commoncfbin)" 1>&2 exit 1 fi ERRORS=0 # Directory to create temporary checkout tmp="/tmp" #tmpdir=$(mktemp --directory --dry-run --tmpdir=$tmp) tmpdir=$(mktemp --directory --tmpdir=$tmp) if [ $? -eq 1 ]; then ((ERRORS++)) echo Creation of temporary directory in $tmp FAILED exit $ERRORS fi # Checkout a copy of the current index into a temporary directory for testing #git checkout-index --prefix=$tmpdir/ -af cp -r * $tmpdir/ if [ $? -eq 1 ]; then ((ERRORS++)) echo Checkout to $tmpdir FAILED exit $ERRORS rm -rf $tmpdir fi for file in $checkfiles; do $cfpromises -cf $tmpdir/$file if [ $? -eq 1 ]; then ((ERRORS++)) echo Syntax check on $file FAILED fi done # Cleanup temporary checkout rm -rf $tmpdir if [ $ERRORS -gt 0 ]; then echo Aborting, we dont allow broken commits exit $ERRORS fi EOF
Typická práce
Vzhledem k použití gitu je možné změny vyvíjet přímo na konkrétním stroji, jedinou podmínkou je mít dostupné AFS a platný token.
Cyklus vývoje by měl vypadat přibližně takto:
- přepnutí do větve master git checkout master
- aktualizace větve master git pull
- vytvoření nové lokální větve git branch local
- přepnutí se na lokální větev git checkout local
- provedení úprav
- lokální testování (tečka+lomítko jsou nezbytné), při chybě jdi na bod č. 5 cf-promises -f ./promises.cf; cf-agent -f ./promises.cf -KIv
- commit v lokální větvi, při chybě jdi na bod č. 5 git commit -a
- přepnutí do větve master git checkout master
- sloužení lokální větve s větví master git merge local
- odeslání změn do repozitáře git push
- čekat max. 15 minut na propagaci změn na klienty (lze ručně uspíšit)
- kontrola, jak se projevilo na testovací sadě serverů, při chybě jdi na bod č. 4
- přepnutí do větve production git checkout production
- aktualizace větve production git pull
- sloučení lokální větve s větví production git merge production
- odeslání změn do centrálního repozitáře git push
- čekat max. 15 minut na propagaci změn na klienty
- kontrola, jak se projevilo na serverech, při chybě jdi na bod č. 4
- zrušení lokální větve git branch -d local
Některé operace lze sloučit, jiné přeskočit, jindy může dojít ke konfliktu a bude potřeba nějaké příkazy doplnit. <graphviz> digraph VyvojovyDiagram { graph [splines="ortho"];
- label = "Vývojový diagram";
start [shape="ellipse", label="start"]; checkout_master [shape="box", label="git checkout master"]; pull_master [shape="box", label="git pull"]; branch [shape="box", label="git branch local"]; checkout_branch [shape="box", label="git checkout -b local"]; checkout_local [shape="box", label="git checkout local"]; edit [shape="box", label="editace"]; if_promises [shape="diamond", label="cf-promises -f ./promises.cf"] if_agent [shape="diamond", label="cf-agent -f ./promises.cf -KIv"] if_commit [shape="diamond", label="git commit -a"] checkout_master2 [shape="box", label="git checkout master"]; merge_master [shape="box", label="git merge local"]; {
rank=same; push_master [shape="diamond", label="git push"]; fix [shape="box", label="git pull\noprava"];
} wait [shape="box", label="počkat 15min"]; check_testing [shape="diamond", label="kontrola testing stroju"]; checkout_production [shape="box", label="git checkout production"]; pull_production [shape="box", label="git pull"]; merge_production [shape="box", label="git merge local"]; {
rank=same; push_production [shape="diamond", label="git push"]; fix2 [shape="box", label="git pull\noprava"];
} wait2 [shape="box", label="počkat 15min"]; check_production [shape="diamond", label="kontrola produkčních strojů"]; branch_delete [shape="box", label="git branch -d local"]; konec [shape="ellipse", label="konec"];
start -> checkout_master -> pull_master -> branch -> checkout_local -> edit -> if_promises [weight=1000]; pull_master -> checkout_branch -> edit; if_promises:e -> edit:e [taillabel="error"]; if_promises -> if_agent [taillabel="ok", weight=1000]; if_agent:e -> edit:e [taillabel="error"]; if_agent -> if_commit [taillabel="ok", weight=1000]; if_commit:e -> edit:e [taillabel="error"]; if_commit -> checkout_master2 [taillabel="ok", weight=1000]; checkout_master2 -> merge_master -> push_master [weight=1000]; push_master:e->fix:w [label="konflikt"]; fix:n -> push_master:n; push_master -> wait -> check_testing [weight=1000]; check_testing:e -> checkout_local:e [taillabel="error"]; check_testing -> checkout_production [taillabel="ok", weight=1000]; checkout_production -> pull_production -> merge_production -> push_production [weight=1000]; push_production:e->fix2:w [label="konflikt"]; fix2:n -> push_production:n; push_production -> wait2 -> check_production [weight=1000]; check_production:e -> checkout_local:e [taillabel="error"]; check_production -> branch_delete [taillabel="ok", weight=1000]; branch_delete -> konec [weight=1000];
} </graphviz>
Jak to celé funguje
Hlavní repozitář je v /afs/zcu.cz/project/software/git/cfengine.git/, odtud se přes cron každých 5min přes git stahují jednotlivé větve
- master -> development
- production -> production
do /var/lib/cfengine3/masterfiles/, zde si jej vyzvedává cf-agent na klientech (za klienta se považuje i samotný server) dle konfigurace v update.cf. Agent si kopii udržuje v /etc/cfengine3/ odkud ji testuje a provádí.
Agent se "sám" na základě třídy rozhodne, kterou větev (development vs. production) bude kopírovat. Idea převzata z knihy.
Aktualizace konfigurace CFEnginem
CFEngine používá dvě aktualizační konfigurace
- failsafe.cf - používá se pro inicializaci nebo při startu daemonu, má za úkol načíst aktuální konfiguraci ještě před startem agenta
- update.cf - volá se z promises.cf, zkontroluje změnu souboru (počítá se i datum) /var/lib/cfengine3/masterfiles/cf_promises_validated a pokud se změnil (tzn. na serveru se provedl nový překlad pravidel), pak zkontroluji i data na serveru. Převzato z netu, ale chce to ještě ověřit zda to tak opravdu funguje.
Jazyk CFEngine
Jde o konfigurační jazyk vyšší úrovně a spíše lze mluvit o předpisech (slibech), oproti klasickým programovacím jazykům jsou zde tyto rozdíly:
- vše se řídí na základě tříd (vlastností) a to včetně podmíněných konstrukcí
- předpisy se provádějí paralelně, pokud je potřeba něco udělat dříve, je nutné nastavit závislost mezi nimi
- struktura funkcí připomíná objektové programování, ale to je tak jediná shoda
Na první pohled je to strašný bordel, ale po prostudování to dává smysl. Je to velmi mocný jazyk a hodně složitých věcí lze udělat jednoduše, bohužel některé jednoduché vyžadují trochu více psaní, než by bylo žádoucí.
Další podstránky
Odkazy
- A Case Study in CFEngine Layout - Dynamicke bundle sequence a jine triky
- Automating infrastructure management with Cfengine - Uvod do CF3 a pekne shrnuti vcetne zakladnich pojmu
- Guide to CFEngine 3 Body of Knowledge - hromada příkladů a odkazů k CF3