#!/usr/bin/env python3 import re from enum import Enum, auto from nag_object import NagObject, NagObjectType class ParserState(Enum): COMMENT = auto() DEFINE = auto() DIRECTIVE = auto() MULTILINE = auto() class NagParse: def __init__(self, config_files: list[str]): self.m_config_files: list[str] = config_files self.m_commands: list[NagObject] = list() self.m_contacts: list[NagObject] = list() self.m_contactgroups: list[NagObject] = list() self.m_hosts: list[NagObject] = list() self.m_hostdependencies: list[NagObject] = list() self.m_hostescalations: list[NagObject] = list() self.m_hostgroups: list[NagObject] = list() self.m_services: list[NagObject] = list() self.m_servicedependencies: list[NagObject] = list() self.m_serviceescalations: list[NagObject] = list() self.m_servicegroups: list[NagObject] = list() self.m_timeperiods: list[NagObject] = list() for config_file in self.m_config_files: for object in self.parse_config(config_file): match object.m_type: case NagObjectType.Command: self.m_commands.append(object) case NagObjectType.Contact: self.m_contacts.append(object) case NagObjectType.ContactGroup: self.m_contactgroups.append(object) case NagObjectType.Host: self.m_hosts.append(object) case NagObjectType.HostDependency: self.m_hostdependencies.append(object) case NagObjectType.HostEscalation: self.m_hostescalations.append(object) case NagObjectType.HostGroup: self.m_hostgroups.append(object) case NagObjectType.Service: self.m_services.append(object) case NagObjectType.ServiceDependency: self.m_servicedependencies.append(object) case NagObjectType.ServiceEscalation: self.m_serviceescalations.append(object) case NagObjectType.ServiceGroup: self.m_servicegroups.append(object) case NagObjectType.TimePeriod: self.m_timeperiods.append(object) def __str__(self): string = str() for fragment in self.m_commands: string += str(fragment) + "\n" for fragment in self.m_contacts: string += str(fragment) + "\n" for fragment in self.m_contactgroups: string += str(fragment) + "\n" for fragment in self.m_hosts: string += str(fragment) + "\n" for fragment in self.m_hostdependencies: string += str(fragment) + "\n" for fragment in self.m_hostescalations: string += str(fragment) + "\n" for fragment in self.m_hostgroups: string += str(fragment) + "\n" for fragment in self.m_services: string += str(fragment) + "\n" for fragment in self.m_servicedependencies: string += str(fragment) + "\n" for fragment in self.m_serviceescalations: string += str(fragment) + "\n" for fragment in self.m_servicegroups: string += str(fragment) + "\n" for fragment in self.m_timeperiods: string += str(fragment) + "\n" return string def parse_config(self,config_file: str) -> list[NagObject]: state = ParserState.DEFINE objects: list[NagObject] = list() with open(config_file, 'r') as file_handle: line_no = 0 cur_object = NagObject(config_file=config_file) for rawline in file_handle.readlines(): # Clean up the config line = re.sub(r'([a-z]){', r'\1 {',rawline.strip()) #line = re.sub(r'([a-zA-Z0-9])}', r'\1\n}',line.strip()) #line = re.sub(r'([a-zA-Z0-9]) }', r'\1\n}',line.strip()) line_no += 1 # This means it is a comment, we might want to save those later on if len(line) == 0 or re.match('^[\t ]*[#]+', line): continue # This means we are done parsing and should reset for new object if re.match(r'}', line): objects.append(cur_object) del cur_object state = ParserState.DEFINE continue #if we get here it is not a comment and not the end of an object fragments: list[str] = re.sub(' +', ' ', line.strip()).split() # This is a new object and we should see what type it is, and what line number it is on if state == ParserState.DEFINE: if fragments[0] == 'define': cur_object = NagObject(config_file=config_file, directives=list()) cur_object.m_line_no = line_no cur_object.m_type = NagObjectType(fragments[1]) # For the next line we should be in DIRECTIVE state state = ParserState.DIRECTIVE else: print("It's fucked up man") break # This is the DIRECTIVE state, where we want to collect key, values and find out if we should go to multiline mode elif state == ParserState.DIRECTIVE: if fragments[-1][-1] == '\\': state = ParserState.MULTILINE if re.match('^[a-z]+', fragments[0]): cur_object.m_directives.append( [fragments[0], " ".join(fragments[1:])]) # This is the MULTILINE state, directives can be on many lines if the '\n' is escaped with '\' elif state == ParserState.MULTILINE: cur_object.m_directives[-1][1] = cur_object.m_directives[-1][1].strip('\\') + ' ' + " ".join(fragments) if fragments[-1][-1] != '\\': state = ParserState.DIRECTIVE else: print("It's fucked up man") break return objects