Извршавање playbook-а завршава се зелено, WireGuard јединица је активна, руковање ради, а нови peer ипак нигде не стиже. Гледати playbook како извештава о успеху док сервер ради са јучерашњом конфигурацијом посебно је фрустрирајуће, јер у излазу ништа није погрешно. Ansible је урадио тачно оно што је тражено: побринуо се да јединица буде покренута, а она је већ била покренута. Примена преписане конфигурационе датотеке је други задатак и дешава се само ако нешто каже сервису да је поново прочита.

Погледајте шта друго извршавање заиста извештава

Покрените playbook двапут са измењеном конфигурацијом и упоредите резиме. Друго извршавање треба да прикаже задатак јединице као ok, а не changed, јер се сервис који већ ради по дизајну оставља на миру. То је исправно функционисање idempotentnosti и уједно разлог зашто нова датотека никада не стигне до kernel-а.

Додајте пробно извршавање са diff излазом да видите који би задаци уопште нешто дотакли.

ansible-playbook -i inventory site.yml --check --diff
systemctl show wg-quick@wg0 -p ActiveEnterTimestamp -p NRestarts
stat -c '%y %n' /etc/wireguard/wg0.conf

Три временске ознаке испричају причу пре него што прочитате и један ред лога. Ако је конфигурациона датотека новија од тренутка када је јединица постала активна, живи интерфејс је изграђен из старије датотеке и сваки даљи симптом произилази из тога.

Ово није дефект Ansible-а. Исто понашање се јавља код сваког алата за управљање конфигурацијом који раздваја „провери да ради“ од „провери да ради ово“. Разлика изгледа педантно док вас не кошта једног поподнева.

Покренуто је стање, а не поновно учитавање

state: started тврди услов о јединици. Не обећава да ће сервис поново прочитати своје улазе и не може да зна да се датотека коју никада није отворио променила. Код wg-quick постављања улази укључују конфигурацију интерфејса, адресе, руте, DNS записе и све post-up куке.

Зато ажурирана датотека може садржати нови peer, другу адресу или измењену директиву рутирања, док живи интерфејс наставља да служи стари скуп. Руковање и даље успева јер су учитани кључеви и крајње тачке још важећи. Управо то чини квар тешко видљивим и објашњава зашто људи сат времена јуре DNS пре него што провере временску ознаку.

Две друге опције модула често се сматрају решењем. daemon_reload тера systemd да поново прочита датотеке јединица, што је небитно за WireGuard конфигурацију. state: reloaded тражи од јединице да изврши своју радњу поновног учитавања, а да ли она ради оно што вам треба зависи искључиво од јединице. Ниједна не замењује знање које је улазе покренути процес стварно прочитао.

Инсталирајте датотеку, па обавестите handler

Образац који чува idempotentnost и ипак примењује промене је уобичајен: задатак који пише датотеку обавештава handler, а handler се извршава само када се датотека стварно променила. Друго извршавање без измена не ради ништа и то је оно што желите.

- name: write the interface configuration
  ansible.builtin.template:
    src: wg0.conf.j2
    dest: /etc/wireguard/wg0.conf
    owner: root
    mode: "0600"
  notify: apply wg0

- name: ensure the interface unit is enabled
  ansible.builtin.systemd_service:
    name: wg-quick@wg0
    enabled: true
    state: started

- name: apply wg0
  listen: apply wg0
  ansible.builtin.systemd_service:
    name: wg-quick@wg0
    state: restarted

Handler-и се извршавају на крају play-а, после задатака који су их обавестили, па задатак касније у истом play-у може још да види стари интерфејс. Ако је редослед важан, испразните handler-е изричито помоћу meta: flush_handlers пре задатка који зависи од нове конфигурације.

Користите restart, а не reload, осим ако нисте проверили радњу поновног учитавања јединице. Надређена wg-quick јединица је подржава и синхронизује WireGuard конфигурацију, али не понавља подешавање адреса, рута, DNS-а ни кука. Зато reload након додавања рутне директиве изгледа успешно и ништа не мења.

Упоредите живи уређај са датотеком

Провера која затвара ову класу грешака је поређење онога што држи kernel са оним што пише у датотеци. Две команде дају упоредив излаз, а разлика је одступање.

sudo wg showconf wg0
sudo wg-quick strip wg0
sudo diff <(sudo wg showconf wg0) <(sudo wg-quick strip wg0)

wg showconf исписује живи уређај, укључујући приватни кључ, па тај излаз третирајте као тајну и не лепите га у тикет. wg-quick strip исписује датотеку без кључева својствених wg-quick-у, и зато су та два излаза уопште упоредива.

Разлика на листи peer-ова значи да датотека никада није примењена. Разлика само у кључевима или крајњим тачкама које сте очекивали да се промене значи да ју је нешто применило делимично. Никаква разлика значи да је конфигурација актуелна, а квар је негде другде, што је само по себи користан резултат.

Платите цену рестарта свесно

Рестарт интерфејса руши тунел, а ако тај тунел носи вашу административну сесију, рестарт прекида сесију која га је затражила. Ставите handler иза прозора за промене или покрените playbook са путање управљања која не зависи од рестарта интерфејса.

Цена је разлог зашто људи посежу за reload-ом. То је разуман нагон и постаје исправан када знате које промене reload стварно примењује. За промене peer-ова и кључева на надређеној wg-quick јединици довољан је; за адресирање, рутирање и куке није. Једном то разјаснити јефтиније је него открити током прозора за промене.

Документација модула systemd_service објашњава разлику између started, restarted и reloaded и вреди је једном прочитати уместо нагађати из зеленог резимеа. Све у овом водичу произилази из те једне разлике.

Повезани чланци