GauvainOLN&B
Par Gauvain Pocentek
Consultant Senior et expert OpenStack @Objectif Libre
Cet article relate les surprises rencontrées avec l’agent L3 lors d’un upgrade d’OpenStack de Liberty à Mitaka, et expose les solutions trouvées. 

Le contexte

Cette semaine, nous avons effectué la montée de version Liberty -> Mitaka de la plateforme OpenStack de l’un de nos clients. Petite plateforme, pas de contrainte de garder les APIs disponibles. Bref : facile.

La plateforme comporte 3 controller/network nodes et 3 computes. La configuration neutron est assez banale : Open vSwitch ML2, réseaux en self-service, virtual routers et IPs flottantes, L3 HA.

Chez Objectif Libre, nous utilisons un playbook Ansible « maison » pour déployer et mettre à jour les plateformes, et tout s’est bien passé.

Enfin.

Presque.

 

Le problème

Après la mise à niveau et le redémarrage de l’agent L3, les routeurs fonctionnaient toujours, mais l’ajout d’interfaces n’était plus possible.

Donc, nous avons vérifié les logs.

Et nous avons trouvé BEAUCOUP de traces python comme celle-ci :

2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent [-] Failed to process compatible router '8a776bc6-b2e3-4439-b122-45ce7479b0a8'
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent Traceback (most recent call last):
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent   File "/usr/lib/python2.7/site-packages/neutron/agent/l3/agent.py", line 501, in _process_router_update
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent     self._process_router_if_compatible(router)
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent   File "/usr/lib/python2.7/site-packages/neutron/agent/l3/agent.py", line 440, in _process_router_if_compatible
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent     self._process_updated_router(router)
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent   File "/usr/lib/python2.7/site-packages/neutron/agent/l3/agent.py", line 454, in _process_updated_router
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent     ri.process(self)
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent   File "/usr/lib/python2.7/site-packages/neutron/agent/l3/ha_router.py", line 389, in process
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent     self.enable_keepalived()
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent   File "/usr/lib/python2.7/site-packages/neutron/agent/l3/ha_router.py", line 123, in enable_keepalived
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent     self.keepalived_manager.spawn()
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent   File "/usr/lib/python2.7/site-packages/neutron/agent/linux/keepalived.py", line 401, in spawn
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent     keepalived_pm.enable(reload_cfg=True)
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent   File "/usr/lib/python2.7/site-packages/neutron/agent/linux/external_process.py", line 94, in enable
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent     self.reload_cfg()
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent   File "/usr/lib/python2.7/site-packages/neutron/agent/linux/external_process.py", line 97, in reload_cfg
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent     self.disable('HUP')
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent   File "/usr/lib/python2.7/site-packages/neutron/agent/linux/external_process.py", line 109, in disable
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent     utils.execute(cmd, run_as_root=True)
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent   File "/usr/lib/python2.7/site-packages/neutron/agent/linux/utils.py", line 116, in execute
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent     execute_rootwrap_daemon(cmd, process_input, addl_env))
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent   File "/usr/lib/python2.7/site-packages/neutron/agent/linux/utils.py", line 102, in execute_rootwrap_daemon
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent     return client.execute(cmd, process_input)
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent   File "/usr/lib/python2.7/site-packages/oslo_rootwrap/client.py", line 128, in execute
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent     try:
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent   File "<string>", line 2, in run_one_command
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent   File "/usr/lib64/python2.7/multiprocessing/managers.py", line 773, in _callmethod
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent     raise convert_to_error(kind, result)
2017-04-20 14:54:50.371 29021 ERROR neutron.agent.l3.agent NoFilterMatched

 

La trace montre qu’un problème a lieu sur oslo_rootwrap, et génère une exception NoFilterMatched. oslo.rootwrap est la bibliothèque qui permet à des applications non-privilégiées telles que  neutron-l3-agent d’exécuter des commandes root. Cette bibliothèque utilise sudo mais fournit ses propres mécanismes d’autorisation.

L’exception NoFilterMatched est levée par oslo_rootwrap quand la commande à exécuter n’est pas trouvée dans les fichiers de configuration. C’est une bonne piste, mais quelle est cette commande ?

L’activation du debug dans la configuration de l’agent L3 n’a pas aidé, la commande n’est toujours pas apparue dans les logs.

 

Nous avons donc patché oslo pour le faire parler un peu plus.

/usr/lib/python2.7/site-packages/oslo_rootwrap/client.py a été modifié comme ceci :

--- client.py.orig 2017-04-22 08:19:16.463450594 +0200
+++ client.py 2017-04-22 08:21:51.590386941 +0200
@@ -121,6 +121,7 @@
        return self._proxy

    def execute(self, cmd, stdin=None):
+      LOG.info('CMD: %s' % cmd)
        self._ensure_initialized()
        proxy = self._proxy
        retry = False

Les logs de l’agent L3 sont devenus plus intéressants après son redémarrage :

2017-04-20 14:57:28.602 10262 INFO oslo_rootwrap.client [req-f6dc5751-96e3-41b8-86bc-f7f98ff26f12 - 3ce2f82bc46b429285ba0e17840e6cf7 - - -] CMD: ['kill', '-HUP', '14410']
2017-04-20 14:57:28.604 10262 ERROR neutron.agent.l3.agent [req-f6dc5751-96e3-41b8-86bc-f7f98ff26f12 - 3ce2f82bc46b429285ba0e17840e6cf7 - - -] Failed to process compatible router 'eb356f30-98c9-4641-9f99-2ad91a6a7223'
2017-04-20 14:57:28.604 10262 ERROR neutron.agent.l3.agent Traceback (most recent call last):
2017-04-20 14:57:28.604 10262 ERROR neutron.agent.l3.agent   File "/usr/lib/python2.7/site-packages/neutron/agent/l3/agent.py", line 501, in _process_router_update
2017-04-20 14:57:28.604 10262 ERROR neutron.agent.l3.agent     self._process_router_if_compatible(router)
[...]
2017-04-20 14:57:28.604 10262 ERROR neutron.agent.l3.agent   File "/usr/lib/python2.7/site-packages/oslo_rootwrap/client.py", line 129, in execute
2017-04-20 14:57:28.604 10262 ERROR neutron.agent.l3.agent     res = proxy.run_one_command(cmd, stdin)
2017-04-20 14:57:28.604 10262 ERROR neutron.agent.l3.agent   File "<string>", line 2, in run_one_command
2017-04-20 14:57:28.604 10262 ERROR neutron.agent.l3.agent   File "/usr/lib64/python2.7/multiprocessing/managers.py", line 773, in _callmethod
2017-04-20 14:57:28.604 10262 ERROR neutron.agent.l3.agent     raise convert_to_error(kind, result)
2017-04-20 14:57:28.604 10262 ERROR neutron.agent.l3.agent NoFilterMatched

L’agent L3 essayait d’envoyer un signal au processus de PID 14410. ps nous a donné quelques détails sur ce processus :

root     14410  0.0  0.0 111640  1324 ?        Ss   mars01   3:28 keepalived -P [...]

keepalived est utilisé par l’agent L3 pour fournir la haute disponibilité des routeurs. Pour chacun d’entre eux, un processus VRRP/keepalived gère la bascule si un nœud réseau vient à disparaître.

Neutron n’était donc pas autorisé à envoyer de signal à ce processus.

La solution

Ayant pris conscience du problème d’autorisation dans le paramétrage de oslo_rootwrap, nous avons fouillé ses fichiers de configuration :

$ grep keepalived /usr/share/neutron/rootwrap/*.filters
/usr/share/neutron/rootwrap/l3.filters:keepalived: CommandFilter, keepalived, root
/usr/share/neutron/rootwrap/l3.filters:kill_keepalived: KillFilter, root, /usr/sbin/keepalived, -HUP, -15, -9

La configuration autorisait neutron à envoyer des signaux aux processus /usr/sbin/keepalived , mais notre processus s’appelait keepalived (sans chemin absolu). Nous avons donc ajouté une nouvelle entrée pour gérer les processus existants :

kill_keepalived_no_path: KillFilter, root, keepalived, -HUP, -15, -9

L’agent L3 a retrouvé sont comportement normal après un redémarrage.

Conclusion

Mitaka n’est pas une version des plus récentes d’OpenStack, elle est d’ailleurs arrivée en fin de vie. Mais nous n’avions pas rencontré ce problème en mettant à jour des versions plus récentes.

Pouvoir comprendre les traces python, et savoir comment creuser le code OpenStack restent des points forts pour appréhender des situations comme celle-ci (Google n’a pas été d’une grande aide).

rootwrap est un composant qui fonctionne généralement sans souci, mais ce problème a été l’occasion pour nous de mieux comprendre ce composant et sa configuration.