LPS:CFEngine3

Z HelpDesk

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:

  1. přepnutí do větve master git checkout master
  2. aktualizace větve master git pull
  3. vytvoření nové lokální větve git branch local
  4. přepnutí se na lokální větev git checkout local
  5. provedení úprav
  6. 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
  7. commit v lokální větvi, při chybě jdi na bod č. 5 git commit -a
  8. přepnutí do větve master git checkout master
  9. sloužení lokální větve s větví master git merge local
  10. odeslání změn do repozitáře git push
  11. čekat max. 15 minut na propagaci změn na klienty (lze ručně uspíšit)
  12. kontrola, jak se projevilo na testovací sadě serverů, při chybě jdi na bod č. 4
  13. přepnutí do větve production git checkout production
  14. aktualizace větve production git pull
  15. sloučení lokální větve s větví production git merge production
  16. odeslání změn do centrálního repozitáře git push
  17. čekat max. 15 minut na propagaci změn na klienty
  18. kontrola, jak se projevilo na serverech, při chybě jdi na bod č. 4
  19. 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"];

  1. 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

TODO

Odkazy