package com.intrbiz.bergamot.config; import java.io.File; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import com.intrbiz.Util; import com.intrbiz.bergamot.compat.command.NagiosCommandString; import com.intrbiz.bergamot.compat.config.builder.NagiosConfigBuilder; import com.intrbiz.bergamot.compat.config.model.NagiosCommandCfg; import com.intrbiz.bergamot.compat.config.model.NagiosContactCfg; import com.intrbiz.bergamot.compat.config.model.NagiosContactgroupCfg; import com.intrbiz.bergamot.compat.config.model.NagiosHostCfg; import com.intrbiz.bergamot.compat.config.model.NagiosHostgroupCfg; import com.intrbiz.bergamot.compat.config.model.NagiosServiceCfg; import com.intrbiz.bergamot.compat.config.model.NagiosServicegroupCfg; import com.intrbiz.bergamot.compat.config.model.NagiosTimeperiodCfg; import com.intrbiz.bergamot.compat.macro.MacroFrame; import com.intrbiz.bergamot.compat.macro.MacroProcessor; import com.intrbiz.bergamot.config.model.BergamotCfg; import com.intrbiz.bergamot.config.model.CheckCommandCfg; import com.intrbiz.bergamot.config.model.CommandCfg; import com.intrbiz.bergamot.config.model.ContactCfg; import com.intrbiz.bergamot.config.model.GroupCfg; import com.intrbiz.bergamot.config.model.HostCfg; import com.intrbiz.bergamot.config.model.NotificationsCfg; import com.intrbiz.bergamot.config.model.NotifyCfg; import com.intrbiz.bergamot.config.model.ScheduleCfg; import com.intrbiz.bergamot.config.model.ServiceCfg; import com.intrbiz.bergamot.config.model.StateCfg; import com.intrbiz.bergamot.config.model.TeamCfg; import com.intrbiz.bergamot.config.model.TimePeriodCfg; import com.intrbiz.bergamot.timerange.TimeRangeParser; import com.intrbiz.bergamot.util.TimeInterval; import com.intrbiz.configuration.CfgParameter; public class NagiosConfigConverter { private boolean withDebug = false; private BergamotCfg config; private NagiosConfigBuilder nagiosConfig; /** * Host templates of services applied by host group */ private Map<String, HostCfg> hostgroupTemplates = new HashMap<String, HostCfg>(); /** * Short names for host templates */ private AtomicInteger hostTemplateId = new AtomicInteger(); /** * A mapping of flattened hosts to host template */ private Map<String, String> hostsToHostTemplate = new HashMap<String, String>(); /** * Host templates of services applied by host */ private Map<String, HostCfg> hostTemplates = new HashMap<String, HostCfg>(); /** * Site parameters in use we need to add */ private Set<String> siteParameters = new HashSet<String>(); /** * MacroFrame used to translate command lines */ private MacroFrame macroFrame; /** * Map probable NRPE commands to our auto generated NRPE commands */ private Map<String, String> nrpeCommands = new HashMap<String, String>(); private File baseDir; public NagiosConfigConverter() { // setup the macro frame we will use to translate commands this.macroFrame = new MacroFrame(); this.macroFrame.clearPrototypes(); // we don't parse resources.cfg // map user macros to site parameters // assume that USER1 == plugin path this.macroFrame.put("USER1", "#{nagios.path}"); for (int i = 2; i < 257; i++) { this.macroFrame.put("USER" + i, "#{nagios.user" + i + "}"); } // default stuff this.macroFrame.put("HOSTADDRESS", "#{host.address}"); this.macroFrame.put("HOSTNAME", "#{host.name}"); this.macroFrame.put("SERVICEDESCRIPTION", "#{service.name}"); // args for (int i = 1; i < 33; i++) { this.macroFrame.put("ARG" + i, "#{arg" + i + "}"); } } public NagiosConfigConverter debugOn() { this.withDebug = true; return this; } public NagiosConfigConverter site(String site) { this.config = new BergamotCfg(); this.config.setSite(site); return this; } public NagiosConfigConverter baseDir(File baseDir) { this.baseDir = baseDir; return this; } public NagiosConfigConverter nagiosConfig(NagiosConfigBuilder nagiosConfig) { this.nagiosConfig = nagiosConfig; return this; } public BergamotCfg convert() { // teams and contacts this.convertContactGroups(); this.convertContacts(); // commands this.convertCommands(); // time periods this.convertTimePeriods(); // groups this.convertGroups(); // services this.convertServices(); // hosts this.convertHosts(); // link this.config.index(true); this.linkContacts(); this.linkServices(); this.linkHostgroups(); this.linkServicegroups(); // handle site parameters this.config.addParameter(new CfgParameter("nagios.path", null, null, "/usr/lib/nagios/plugins")); for (String parameter : this.siteParameters) { this.config.addParameter(new CfgParameter(parameter, null, null, "")); } // return this.config; } private void linkHostgroups() { for (NagiosHostgroupCfg cfg : this.nagiosConfig.getHostgroups()) { GroupCfg group = this.config.lookup(GroupCfg.class, cfg.getHostgroupName()); if (group != null) { // child hostgroups if (cfg.getHostgroupMembers() != null) { for (String child : cfg.getHostgroupMembers()) { GroupCfg childGroup = this.config.lookup(GroupCfg.class, child); if (childGroup != null) { childGroup.addGroup(group.getName()); childGroup.removeGroup("hosts"); } } } // hosts if (cfg.getMembers() != null) { for (String hostName : cfg.getMembers()) { HostCfg host = this.config.lookup(HostCfg.class, hostName); if (host != null) { host.addGroup(group.getName()); } } } } } } private void linkServicegroups() { for (NagiosServicegroupCfg cfg : this.nagiosConfig.getServicegroups()) { GroupCfg group = this.config.lookup(GroupCfg.class, cfg.getServicegroupName()); if (group != null) { // child service if (cfg.getServicegroupMembers() != null) { for (String child : cfg.getServicegroupMembers()) { GroupCfg childGroup = this.config.lookup(GroupCfg.class, child); if (childGroup != null) { childGroup.addGroup(group.getName()); childGroup.removeGroup("hosts"); } } } // services if (cfg.getMembers() != null) { for (Iterator<String> i = cfg.getMembers().iterator(); i.hasNext();) { String hostName = i.next(); String serviceDescription = i.next(); // HostCfg host = this.config.lookup(HostCfg.class, hostName); if (host != null) { ServiceCfg service = host.lookupService(serviceDescription); if (service != null) { service.addGroup(group.getName()); } } } } } } } private void linkContacts() { for (NagiosContactgroupCfg contactgroup : this.nagiosConfig.getContactgroups()) { TeamCfg team = this.config.lookup(TeamCfg.class, contactgroup.getContactgroupName()); if (team != null) { if (contactgroup.getMembers() != null) { for (String contactName : contactgroup.getMembers()) { ContactCfg contact = this.config.lookup(ContactCfg.class, contactName); if (contact != null) { contact.getTeams().add(team.getName()); } } } if (contactgroup.getContactgroupMembers() != null) { for (String childName : contactgroup.getContactgroupMembers()) { TeamCfg childTeam = this.config.lookup(TeamCfg.class, childName); if (childTeam != null) { childTeam.addTeam(team.getName()); } } } } } } private void convertContacts() { for (NagiosContactCfg cfg : this.nagiosConfig.getContacts()) { // convert the contact ContactCfg contact = new ContactCfg(); contact.setLoadedFrom(convertFile(cfg.getLoadedFrom())); contact.setTemplate(cfg.isRegister() == null || cfg.isRegister() == false ? true : null); contact.setName(contact.getTemplateBooleanValue() ? cfg.getName() : cfg.getContactName()); if (cfg.getInherits() != null) contact.getInheritedTemplates().addAll(cfg.getInherits()); if (!Util.isEmpty(cfg.getEmail())) contact.setEmail(cfg.getEmail()); if (!Util.isEmpty(cfg.getPager())) contact.setPager(cfg.getPager()); if (!Util.isEmpty(cfg.getAlias())) contact.setSummary(cfg.getAlias()); // notifications if (cfg.isNotificationsEnabled() != null || cfg.getNotificationPeriod() != null) { NotificationsCfg notifications = new NotificationsCfg(); notifications.setEnabled(cfg.isNotificationsEnabled()); if (cfg.getNotificationPeriod() != null) { notifications.setNotificationPeriod(Util.coalesce(cfg.getNotificationPeriod(), cfg.getServiceNotificationPeriod(), cfg.getHostNotificationPeriod(), "24x7")); } contact.setNotifications(notifications); } // teams if (cfg.getContactgroups() != null) contact.getTeams().addAll(cfg.getContactgroups()); // add this.config.getContacts().add(contact); } } private void convertContactGroups() { for (NagiosContactgroupCfg cfg : this.nagiosConfig.getContactgroups()) { // convert the contact TeamCfg team = new TeamCfg(); team.setLoadedFrom(convertFile(cfg.getLoadedFrom())); team.setTemplate(cfg.isRegister() == null || cfg.isRegister() == false ? true : null); team.setName(team.getTemplateBooleanValue() ? cfg.getName() : cfg.getContactgroupName()); if (cfg.getInherits() != null) team.getInheritedTemplates().addAll(cfg.getInherits()); if (!Util.isEmpty(cfg.getAlias())) team.setSummary(cfg.getAlias()); // add this.config.getTeams().add(team); } } private void convertCommands() { for (NagiosCommandCfg cfg : this.nagiosConfig.getCommands()) { if ("check_nrpe".equalsIgnoreCase(cfg.getCommandName())) { // override the default nagios command with a bergamot specific command CommandCfg command = new CommandCfg(); command.setLoadedFrom(new File(this.baseDir, "nrpe_commands.xml")); command.setName("check_nrpe"); command.setEngine("nrpe"); command.setSummary("Check NRPE"); command.setDescription("Check NRPE using the Bergamot NRPE worker"); // parameters command.addParameter(new CfgParameter("command", "The NRPE command name", null, "#{arg1}")); command.addParameter(new CfgParameter("host", "The NRPE host", null, "#{host.address}")); // add this.config.addObject(command); } else { // convert the command CommandCfg command = new CommandCfg(); command.setLoadedFrom(convertFile(cfg.getLoadedFrom())); command.setTemplate(cfg.isRegister() == null || cfg.isRegister() == false ? true : null); command.setName(command.getTemplateBooleanValue() ? cfg.getName() : cfg.getCommandName()); command.setEngine("nagios"); // command_line parameter String commandLine = cfg.getCommandLine(); if (commandLine != null) { // extract the macros used Set<String> macros = MacroProcessor.extractMacros(commandLine); // add any args we found as parameters // collate any site parameters we need for (String macro : macros) { if (macro.startsWith("ARG")) { command.addParameter(new CfgParameter(macro.toLowerCase(), null, null, "")); } else if (macro.startsWith("USER") && (! "USER1".equals(macro))) { this.siteParameters.add("nagios." + macro.toLowerCase()); } } // build the command line // apply the macros to convert the Nagios expression to a Bergamot expression commandLine = MacroProcessor.applyMacros(commandLine, this.macroFrame); // add the param command.addParameter(new CfgParameter("command_line", null, null, Util.coalesce(commandLine, ""))); } // add this.config.getCommands().add(command); } } } private void convertTimePeriods() { for (NagiosTimeperiodCfg cfg : this.nagiosConfig.getTimeperiods()) { // convert TimePeriodCfg timePeriod = new TimePeriodCfg(); timePeriod.setLoadedFrom(convertFile(cfg.getLoadedFrom())); timePeriod.setTemplate((cfg.isRegister() == null || cfg.isRegister() == false) ? true : false); timePeriod.setName(timePeriod.getTemplateBooleanValue() ? cfg.getName() : cfg.getTimeperiodName()); if (cfg.getInherits() != null) timePeriod.getInheritedTemplates().addAll(cfg.getInherits()); if (cfg.getExclude() != null) timePeriod.getExcludes().addAll(cfg.getExclude()); if (!Util.isEmpty(cfg.getAlias())) timePeriod.setSummary(cfg.getAlias()); // time ranges for (String period : cfg.getPeriods()) { timePeriod.getTimeRanges().add(TimeRangeParser.parseTimeRange(period)); } // add this.config.getTimePeriods().add(timePeriod); } } private void convertGroups() { // defacto groups GroupCfg hosts = new GroupCfg("hosts", "Hosts"); GroupCfg services = new GroupCfg("services", "Services"); hosts.setLoadedFrom(new File(this.baseDir, "bergamot_groups.xml")); services.setLoadedFrom(new File(this.baseDir, "bergamot_groups.xml")); this.config.getGroups().add(hosts); this.config.getGroups().add(services); // for (NagiosHostgroupCfg cfg : this.nagiosConfig.getHostgroups()) { // convert GroupCfg group = new GroupCfg(); group.setLoadedFrom(convertFile(cfg.getLoadedFrom())); group.setName(Util.coalesce(cfg.getHostgroupName(), cfg.getName())); if (!Util.isEmpty(cfg.getAlias())) group.setSummary(cfg.getAlias()); group.addGroup(hosts.getName()); // add this.config.getGroups().add(group); } for (NagiosServicegroupCfg cfg : this.nagiosConfig.getServicegroups()) { // convert GroupCfg group = new GroupCfg(); group.setLoadedFrom(convertFile(cfg.getLoadedFrom())); group.setName(Util.coalesce(cfg.getServicegroupName(), cfg.getName())); if (!Util.isEmpty(cfg.getAlias())) group.setSummary(cfg.getAlias()); group.addGroup(services.getName()); // add this.config.getGroups().add(group); } } private void convertServices() { for (NagiosServiceCfg cfg : this.nagiosConfig.getServices()) { if (cfg.isRegister() != null && cfg.isRegister() == false) { // convert the service template this.config.getServices().add(this.convertService(cfg)); } else { // build host templates // by host group if (cfg.getHostgroupName() != null) { for (String hostgroup : cfg.getHostgroupName()) { // get the template HostCfg template = this.hostgroupTemplates.get(hostgroup); if (template == null) { template = new HostCfg(); template.setName(hostgroup + "-template"); template.setSummary("Generic template for " + hostgroup); template.setTemplate(true); template.setLoadedFrom(new File(new File(this.baseDir, "templates"), "bergamot_host_" + hostgroup + "_template.xml")); this.hostgroupTemplates.put(hostgroup, template); this.config.addObject(template); } // add the service template.getServices().add(this.convertService(cfg)); } } // by host if (cfg.getHostName() != null && (! cfg.getHostName().isEmpty())) { // get a flat hosts name String hosts = cfg.getHostName().stream().sorted().collect(Collectors.joining("_")); // map to a short template name String templateName = this.hostsToHostTemplate.get(hosts); if (templateName == null) { templateName = "host-template-" + this.hostTemplateId.incrementAndGet(); this.hostsToHostTemplate.put(hosts, templateName); } // get the template HostCfg template = this.hostTemplates.get(templateName); if (template == null) { template = new HostCfg(); template.setName(templateName); template.setSummary("Generic template for " + cfg.getHostName().stream().sorted().collect(Collectors.joining(", "))); template.setTemplate(true); template.setLoadedFrom(new File(new File(this.baseDir, "templates"), "bergamot_host_" + templateName + "_template.xml")); this.hostTemplates.put(templateName, template); this.config.addObject(template); } template.getServices().add(this.convertService(cfg)); } } } } private ServiceCfg convertService(NagiosServiceCfg cfg) { // convert ServiceCfg service = new ServiceCfg(); service.setLoadedFrom(convertFile(cfg.getLoadedFrom())); service.setTemplate(cfg.isRegister() == null || cfg.isRegister() == false ? true : null); service.setName(cfg.getName()); service.setSummary(cfg.getServiceDescription()); if (cfg.getInherits() != null) service.getInheritedTemplates().addAll(cfg.getInherits()); // notifications if (cfg.isNotificationsEnabled() != null || cfg.getNotificationPeriod() != null) { service.setNotifications(new NotificationsCfg()); service.getNotifications().setEnabled(cfg.isNotificationsEnabled()); if (cfg.getNotificationPeriod() != null) { service.getNotifications().setNotificationPeriod(Util.coalesce(cfg.getNotificationPeriod(), "24x7")); } } // notify if ((cfg.getContactGroups() != null && (!cfg.getContactGroups().isEmpty())) || (cfg.getContacts() != null && (!cfg.getContacts().isEmpty()))) { service.setNotify(new NotifyCfg()); if (cfg.getContactGroups() != null && (!cfg.getContactGroups().isEmpty())) { service.getNotify().getTeams().addAll(cfg.getContactGroups()); } if (cfg.getContacts() != null && (!cfg.getContacts().isEmpty())) { service.getNotify().getContacts().addAll(cfg.getContacts()); } } // schedule if (cfg.getCheckInterval() != null || cfg.getRetryInterval() != null) { service.setSchedule(new ScheduleCfg()); service.getSchedule().setEvery(new TimeInterval(cfg.getCheckInterval(), TimeUnit.MINUTES).toString()); service.getSchedule().setRetryEvery(new TimeInterval(cfg.getRetryInterval(), TimeUnit.MINUTES).toString()); if (cfg.getCheckPeriod() != null) { service.getSchedule().setTimePeriod(cfg.getCheckPeriod()); } } // state if (cfg.getMaxCheckAttempts() != null) { service.setState(new StateCfg()); service.getState().setFailedAfter(cfg.getMaxCheckAttempts()); service.getState().setRecoversAfter(cfg.getMaxCheckAttempts()); } // groups if (cfg.getServicegroups() != null) { service.getGroups().addAll(cfg.getServicegroups()); } // for debugging parameters for hostgroups and hosts if (this.withDebug) { if (cfg.getHostgroupName() != null && (!cfg.getHostgroupName().isEmpty())) { service.addParameter(new CfgParameter("nagios.hostgroups", null, null, Util.join(", ", cfg.getHostgroupName()))); } if (cfg.getHostName() != null && (!cfg.getHostName().isEmpty())) { service.addParameter(new CfgParameter("nagios.hosts", null, null, Util.join(", ", cfg.getHostName()))); } } // check command if (cfg.getCheckCommand() != null) { // parse the check command NagiosCommandString command = NagiosCommandString.parse(cfg.getCheckCommand()); // special case likely NRPE commands if ("check_nrpe".equalsIgnoreCase(command.getCommandName()) && command.getArguments().size() == 1) { String nrpeCommand = command.getArguments().get(0); // pull out the NRPE command and create a command definition for it String commandName = this.nrpeCommands.get(nrpeCommand); if (commandName == null) { // command name commandName = command.getCommandName() + "_" + nrpeCommand; // build the command def CommandCfg generatedCommand = new CommandCfg(); generatedCommand.setLoadedFrom(new File(this.baseDir, "nrpe_commands.xml")); generatedCommand.getInheritedTemplates().add("check_nrpe"); generatedCommand.setName(commandName); generatedCommand.setSummary("Check NRPE: " + nrpeCommand); // the command parameter generatedCommand.addParameter(new CfgParameter("command", null, null, nrpeCommand)); // add the command def this.config.addObject(generatedCommand); // map this.nrpeCommands.put(nrpeCommand, commandName); } // use the command service.setCheckCommand(new CheckCommandCfg()); service.getCheckCommand().setCommand(commandName); } else { // generic command service.setCheckCommand(new CheckCommandCfg()); service.getCheckCommand().setCommand(command.getCommandName()); // parameters int i = 1; for (String arg : command.getArguments()) { service.getCheckCommand().addParameter(new CfgParameter("arg" + i++, null, null, arg)); } } } return service; } private void convertHosts() { for (NagiosHostCfg cfg : this.nagiosConfig.getHosts()) { // convert HostCfg host = new HostCfg(); host.setLoadedFrom(convertFile(cfg.getLoadedFrom())); host.setTemplate(cfg.isRegister() == null || cfg.isRegister() == false ? true : null); host.setName(host.getTemplateBooleanValue() ? cfg.getName() : cfg.getHostName()); host.setSummary(Util.coalesceEmpty(cfg.getAlias(), cfg.getDisplayName())); host.setAddress(cfg.getAddress()); if (cfg.getInherits() != null) host.getInheritedTemplates().addAll(cfg.getInherits()); // notifications if (cfg.isNotificationsEnabled() != null || cfg.getNotificationPeriod() != null) { host.setNotifications(new NotificationsCfg()); host.getNotifications().setEnabled(cfg.isNotificationsEnabled()); if (cfg.getNotificationPeriod() != null) { host.getNotifications().setNotificationPeriod(Util.coalesce(cfg.getNotificationPeriod(), "24x7")); } } // notify if ((cfg.getContactGroups() != null && (!cfg.getContactGroups().isEmpty())) || (cfg.getContacts() != null && (!cfg.getContacts().isEmpty()))) { host.setNotify(new NotifyCfg()); if (cfg.getContactGroups() != null && (!cfg.getContactGroups().isEmpty())) { host.getNotify().getTeams().addAll(cfg.getContactGroups()); } if (cfg.getContacts() != null && (!cfg.getContacts().isEmpty())) { host.getNotify().getContacts().addAll(cfg.getContacts()); } } // schedule if (cfg.getCheckInterval() != null || cfg.getRetryInterval() != null) { host.setSchedule(new ScheduleCfg()); host.getSchedule().setEvery(new TimeInterval(cfg.getCheckInterval(), TimeUnit.MINUTES).toString()); host.getSchedule().setRetryEvery(new TimeInterval(cfg.getRetryInterval(), TimeUnit.MINUTES).toString()); if (cfg.getCheckPeriod() != null) { host.getSchedule().setTimePeriod(cfg.getCheckPeriod()); } } // state if (cfg.getMaxCheckAttempts() != null) { host.setState(new StateCfg()); host.getState().setFailedAfter(cfg.getMaxCheckAttempts()); host.getState().setRecoversAfter(cfg.getMaxCheckAttempts()); } // groups if (cfg.getHostgroups() != null) { host.getGroups().addAll(cfg.getHostgroups()); } // check command if (cfg.getCheckCommand() != null) { // parse the check command NagiosCommandString command = NagiosCommandString.parse(cfg.getCheckCommand()); host.setCheckCommand(new CheckCommandCfg()); host.getCheckCommand().setCommand(command.getCommandName()); // parameters int i = 1; for (String arg : command.getArguments()) { host.getCheckCommand().addParameter(new CfgParameter("arg" + i++, null, null, arg)); } } // add this.config.getHosts().add(host); } } private void linkServices() { for (NagiosServiceCfg cfg : this.nagiosConfig.getServices()) { if (cfg.isRegister() == null || cfg.isRegister() == true) { // by host group if (cfg.getHostgroupName() != null) { for (String hostgroupName : cfg.getHostgroupName()) { for (HostCfg host : this.config.getHosts()) { if (host.containsGroup(hostgroupName)) { host.getInheritedTemplates().add(hostgroupName + "-template"); } } } } // by host if (cfg.getHostName() != null && (! cfg.getHostName().isEmpty())) { // get the template name String hosts = cfg.getHostName().stream().sorted().collect(Collectors.joining("_")); // map to a short template name String templateName = this.hostsToHostTemplate.get(hosts); // add for (String hostName : cfg.getHostName()) { HostCfg host = this.config.lookup(HostCfg.class, hostName); if (host != null) { host.getInheritedTemplates().add(templateName); } } } } } } private static File convertFile(File orig) { String name = orig.getName(); name = name.substring(0, name.length() - 4); name += ".xml"; return new File(orig.getParentFile(), name); } }