2017-08-08 2 views
0

J'essaye d'analyser une config Nagios/Icinga pour pouvoir continuer le traitement avec Python. Comme je ne pouvais pas trouver une bibliothèque de travail pour le faire (pynag ne semble pas fonctionner du tout), j'essaye d'écrire un simple script Python en utilisant des regexes pour le faire.Parse Nagios/Icinga Config avec Python Regex

Fondamentalement, je veux obtenir de cette configfile (il utilise des onglets pour l'indentation):

define host { 
    address 123.123.123.123 
    passive_checks_enabled 1 
    } 

define service { 
    service_description Crondaemon 
    check_command check_nrpe_1arg!check_crondaemon 
    } 

à quelque chose comme ce tuple Python:

(
('host', ('address', '123.123.123.123'), ('passive_checks_enabled', '1')), 
('service', ('service_description', 'Crondaemon'), ('check_command', 'check_nrpe_1arg!check_crondaemon')) 
) 

Ceci est mon plein script avec la logique d'analyse syntaxique, y compris un exemple à tester:

import re 

# white spaces are tabs! 
TEST_STR = """ 
define host { 
    address 123.123.123.123 
    passive_checks_enabled 1 
    } 

define service { 
    service_description Crondaemon 
    check_command check_nrpe_1arg!check_crondaemon 
    } 
""" 

cfg_all_regex = re.compile(
    r'define\s+(\w+)\s*\{' 
    '(.*?)' 
    '\t}', 
    re.DOTALL 
) 
# basic regex works 
print(re.findall(cfg_all_regex, TEST_STR)) 

cfg_all_regex = re.compile(
    r'define\s+(\w+)\s*{\n' 
    '(\t(.*)?\t(.*)?\n)*' 
    '\t}', 
    re.DOTALL 
) 
# more specific regex to extract all key values fails 
print(re.findall(cfg_all_regex, TEST_STR)) 

Malheureusement, je ne peux pas obtenir l'analyse complète pour travail, il correspond toujours à tout ou rien. Pouvez-vous me donner un indice sur la façon de réparer mon regex afin de pouvoir extraire toutes les paires de valeurs clés de ma config Icinga?

Répondre

1
Module

re ne supporte pas les captures répétées, si

'(\t(.*)?\t(.*)?\n)*' 

ne conserve que la dernière capture du groupe.

De même, je transformerait ce genre

'\t(\w+)\s+([^\n]*)\n\' 

Ainsi, une solution possible, compte tenu de la structure de vos données, peut être crée une expression régulière qui correspond soit modèle:

regex = r'define\s+(\w+)\s+\{\n|\t(\w+)\s+([^\n]*)\n|\t\}' 
matches = re.finditer(regex, TEST_STR, re.DOTALL) 

Avec une boucle for vous pouvez itérer sur les groupes

for match in matches: 
    for groupNum in range(0, len(match.groups())): 
     groupNum = groupNum + 1 
     if match.group(groupNum): 
      print("Group {}: {}".format(groupNum, match.group(groupNum))) 

retour:

Group 1: host 
Group 2: address 
Group 3: 123.123.123.123 
Group 2: passive_checks_enabled 
Group 3: 1 
Group 1: service 
Group 2: service_description 
Group 3: Crondaemon 
Group 2: check_command 
Group 3: check_nrpe_1arg!check_crondaemon 
+0

Wow ne s'attendait pas à ce que cela ne puisse pas être résolu avec une simple regex. Mais votre solution fonctionne comme un charme et je pourrais compléter mon analyseur. La logique finale peut être trouvée ici: https://gist.github.com/ifischer/6e8aa105c5f644fd3803f8b41dcbe4f3 Merci beaucoup pour votre aide, m'a sauvé beaucoup de temps au violon! – ifischer

+1

Nous venons de découvrir que [regex] (https://pypi.python.org/pypi/regex/) prend en charge des captures répétées. Peut-être qu'avec cela la solution pourrait être beaucoup simplifiée. Mais ne vaut pas les efforts pour l'instant – ifischer

+0

Vous avez raison. Si l'installation de bibliothèques tierces est viable dans votre projet, le module regex est une meilleure option. – alvarez