/*
* Lokomo OneCMDB - An Open Source Software for Configuration
* Management of Datacenter Resources
*
* Copyright (C) 2006 Lokomo Systems AB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*
* Lokomo Systems AB can be contacted via e-mail: info@lokomo.com or via
* paper mail: Lokomo Systems AB, Sv�rdv�gen 27, SE-182 33
* Danderyd, Sweden.
*
*/
package org.onecmdb.nagios;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.management.modelmbean.XMLParseException;
import org.dom4j.Branch;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.ElementHandler;
import org.dom4j.ElementPath;
import org.dom4j.io.SAXReader;
import org.jgroups.util.GetNetworkInterfaces1_4;
import org.onecmdb.core.utils.MemoryBeanProvider;
import org.onecmdb.core.utils.bean.AttributeBean;
import org.onecmdb.core.utils.bean.CiBean;
import org.onecmdb.core.utils.bean.ValueBean;
import org.onecmdb.core.utils.graph.query.GraphQuery;
import org.onecmdb.core.utils.graph.query.selector.ItemOffspringSelector;
import org.onecmdb.core.utils.graph.result.Graph;
import org.onecmdb.core.utils.wsdl.IOneCMDBWebService;
import org.onecmdb.core.utils.xml.XmlGenerator;
import org.onecmdb.utils.wsdl.AbstractCMDBCommand;
import org.onecmdb.utils.wsdl.CMDBChangeUpload;
/**
* Convert Nagios XML description to OneCMDB Template/Instance Model.
* Special handling:
* use == Derived From
* name == Template name.
* register==0 --> No instance only template
* @author niklas
*
*/
public class Nagios2OneCMDB extends AbstractCMDBCommand {
class NagiosConfigEntry {
public String id;
public String value;
public String description;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
class NagiosConfig {
public String type;
Map<String, NagiosConfigEntry> entries = new HashMap<String, NagiosConfigEntry>();
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Map<String, NagiosConfigEntry> getEntries() {
return entries;
}
public void setEntries(Map<String, NagiosConfigEntry> entries) {
this.entries = entries;
}
public void addEntry(NagiosConfigEntry entry) {
this.entries.put(entry.getId(), entry);
}
public String getValueForAttr(String name) {
NagiosConfigEntry entry = this.entries.get(name);
if (entry == null) {
return(null);
}
return(entry.getValue());
}
}
private String input;
private String output;
private static String ARGS[][] = {
{"input", "Input file/dirctory. If directory files with .cfg are tried.", null},
{"output", "Output file, - stdout", "-"},
};
public static void main(String argv[]) {
Nagios2OneCMDB nagios2cmdb = new Nagios2OneCMDB();
nagios2cmdb.handleArgs(ARGS, argv);
try {
nagios2cmdb.process();
} catch (Throwable t) {
t.printStackTrace();
System.out.println("ERROR:" + t.getMessage());
System.exit(-1);
}
System.exit(0);
}
@Override
public void process() {
List<CiBean> result = new ArrayList<CiBean>();
OutputStream out = System.out;
FileInputStream in = null;
weekDayMap = new HashSet<String>();
weekDayMap.add("sunday");
weekDayMap.add("monday");
weekDayMap.add("tuesday");
weekDayMap.add("wednesday");
weekDayMap.add("thursday");
weekDayMap.add("friday");
weekDayMap.add("saturday");
buildReferenceMap();
File file = new File(input);
if (file.isDirectory()) {
for (File f : file.listFiles()) {
if (f.getName().endsWith(".xml")) {
try {
in = new FileInputStream(f);
result.addAll(parse(in));
} catch (Exception e) {
throw new IllegalArgumentException("Error parsing file " + f.getPath() + "", e);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
}
}
}
}
}
} else {
try {
in = new FileInputStream(file);
result.addAll(parse(in));
} catch (Exception e) {
throw new IllegalArgumentException("Error parsing file " + file.getPath() + "", e);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
}
}
}
}
handleServiceRelations(result, serviceRelations);
try {
if (!output.equals("-")) {
out = new FileOutputStream(output);
}
// Validate....
for (CiBean bean : result) {
for (ValueBean v : bean.getAttributeValues()) {
if (v.isComplexValue()) {
if (!beanExists(result, v.getValue())) {
bean.removeAttributeValue(v);
System.out.println("Missing: " + v.getValue() + " in " + bean.getAlias());
}
}
}
}
XmlGenerator gen = new XmlGenerator();
gen.setBeans(result);
gen.transfer(out);
System.out.println("Generated " + result.size() + " CI:s");
} catch (Exception e) {
throw new IllegalArgumentException("Error writing file " + output + "", e);
} finally {
if (out != null) {
try {
out.close();
} catch (Exception e) {
}
}
}
}
private void handleServiceRelations(List<CiBean> result,
List<ServiceRelation> sR) {
MemoryBeanProvider prov = new MemoryBeanProvider(result.toArray(new CiBean[0]));
System.out.println("ServideRelations counts " + sR.size());
int resolved = 0;
for (ServiceRelation rel : sR) {
String value = rel.getValue();
String values[] = value.split(",");
if (!rel.getType().equals("servicegroup")) {
System.out.println("TODO: Handle " + rel.getType());
continue;
}
if (!((values.length % 2) == 0)) {
System.out.println("Missconfigured service relation: " + value + " in object " + rel.getBean());
continue;
}
System.out.println("Handle SR " + rel.getType() + ":" + rel.getBean());
// Here we have host,service group pair.
for (int i = 0; i < values.length; i += 2) {
String host = values[i];
String descr = values[i+1];
// Need to find a service with this set...
boolean found = false;
for (CiBean bean : result) {
String sDesc = bean.toStringValue("service_description");
if (sDesc == null) {
continue;
}
if (sDesc.equals(descr)) {
for (ValueBean v : bean.fetchAttributeValueBeans("host_name")) {
CiBean hostBean = prov.getBean(v.getValue());
if (host.equals(hostBean.toStringValue("host_name"))) {
System.out.println("Set " + rel.getBean().getAlias() + "[" + rel.getId().getId() + "]=" + bean);
updateCMDBValue(rel.getBean(), rel.getId().getId(), bean.getAlias(), true);
found = true;
break;
}
}
}
if (found) {
resolved++;
break;
}
}
}
}
System.out.println("Service Relations resolved " + resolved + "(" + sR.size() + ")");
}
private boolean beanExists(List<CiBean> result, String value) {
for (CiBean bean : result) {
if (bean.getAlias().equals(value)) {
return(true);
}
}
return(false);
}
private Map<String, String> referenceMap = new HashMap<String, String>();
private Set<String> weekDayMap;
private List<ServiceRelation> serviceRelations = new ArrayList<ServiceRelation>();
public List<CiBean> parse(InputStream in) throws DocumentException {
SAXReader reader = new SAXReader();
Document document = reader.read(in);
Element root = document.getRootElement();
List<CiBean> beans = new ArrayList<CiBean>();
for (Element el : (List<Element>)root.elements()) {
// Handle different types.
NagiosConfig cfg = toNagiosConfig(el);
boolean createTemplate = false;
boolean createInstance = false;
if ("0".equals(cfg.getValueForAttr("register"))) {
createInstance = false;
createTemplate = true;
} else if (cfg.getValueForAttr("name") != null) {
createInstance = true;
createTemplate = true;
} else {
createInstance = true;
createTemplate = false;
}
if (createTemplate) {
beans.add(getBean(cfg, true));
}
if (createInstance) {
CiBean bean = getBean(cfg, false);
if (createTemplate) {
updateCMDBValue(bean, "useName", "true", false);
}
beans.add(bean);
}
}
return(beans);
}
public void transform(InputStream in, OutputStream out) throws DocumentException {
List<CiBean> beans = parse(in);
XmlGenerator gen = new XmlGenerator();
gen.setBeans(beans);
try {
gen.transfer(System.out);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void buildReferenceMap() {
// Call OneCMDB to get referenceMap...
IOneCMDBWebService service = null;
try {
service = getService();
} catch (Exception e) {
throw new IllegalArgumentException("Can't connect to OneCMDB [" + getUrl() + "]" , e);
}
// Load NAGIOS Templates.
GraphQuery q = new GraphQuery();
ItemOffspringSelector sel = new ItemOffspringSelector("nagios", "NAGIOS");
sel.setMatchTemplate(true);
sel.setLimitToChild(false);
sel.setPrimary(true);
q.addSelector(sel);
Graph result = service.queryGraph(getToken(), q);
result.buildMap();
for (CiBean bean : result.fetchAllNodeOffsprings()) {
for (AttributeBean aBean : bean.getAttributes()) {
if (aBean.isComplexType()) {
String key = fromCMDBName(bean.getAlias()) + "/" + aBean.getAlias();
String value = fromCMDBName(aBean.getType());
referenceMap.put(key, value);
System.out.println("ADD: " + key + "->" + value);
}
}
}
/*
referenceMap.put("host/parents", "host");
referenceMap.put("host/hostgroups", "hostgroup");
referenceMap.put("host/check_command", "command");
referenceMap.put("host/check_period", "timeperiod");
referenceMap.put("host/event_handler", "command");
referenceMap.put("host/contact_groups", "contactgroup");
referenceMap.put("host/notification_period", "timeperiod");
referenceMap.put("service/host_name", "host");
referenceMap.put("service/hostgroup_name", "hostgroup");
referenceMap.put("service/servicegroups", "servicegroup");
referenceMap.put("service/check_command", "command");
referenceMap.put("service/check_period", "timeperiod");
referenceMap.put("service/event_handler", "command");
referenceMap.put("service/notification_period", "timeperiod");
referenceMap.put("service/contacts", "contact");
referenceMap.put("service/contact_groups", "contactgroup");
referenceMap.put("hostgroup/members", "host");
referenceMap.put("hostgroup/hostgroup_members", "hostgroup");
referenceMap.put("servicegroup/members", "service");
referenceMap.put("servicegroup/servicegroup_members", "servicegroup");
*/
}
private NagiosConfig toNagiosConfig(Element el) {
NagiosConfig cfg = new NagiosConfig();
cfg.setType(el.getName());
for (Element attr : (List<Element>)el.elements()) {
NagiosConfigEntry entry = new NagiosConfigEntry();
entry.setId(attr.getName());
entry.setValue(getElementValue(attr, "value", true));
entry.setDescription(getElementValue(attr, "description", false));
cfg.addEntry(entry);
}
return(cfg);
}
private void updateBean(CiBean bean, NagiosConfig cfg) {
}
private CiBean getBean(NagiosConfig cfg, boolean template) {
CiBean bean = new CiBean();
// Register == 0, only template.
if (template) {
bean.setTemplate(true);
bean.setAlias(toCMDBName(cfg.getType()) + "_" + cfg.getValueForAttr("name"));
System.out.println("Create Template : " + bean.getAlias());
} else {
bean.setTemplate(false);
bean.setAlias(getAlias(cfg));
updateCMDBValue(bean, "register", "1", false);
}
String uses = cfg.getValueForAttr("use");
if (uses == null) {
bean.setDerivedFrom(toCMDBName(cfg.getType()));
} else {
bean.setDerivedFrom(toCMDBName(cfg.getType()) + "_" + uses);
}
updateValues(bean, cfg);
return(bean);
}
private String fromCMDBName(String type) {
String nagiosType = type.replace("NAGIOS_","");
return(nagiosType.toLowerCase());
}
private String toCMDBName(String type) {
String first = type.substring(0,1);
String rest = type.substring(1);
return("NAGIOS_" + first.toUpperCase() + rest);
}
private String getAlias(NagiosConfig cfg) {
String id = cfg.getValueForAttr(cfg.getType() + "_name");
if (cfg.getType().equals("service")) {
String host = cfg.getValueForAttr("host_name");
String descr = cfg.getValueForAttr("service_description");
id = descr + (host == null ? "" : "_" + host.hashCode());
}
if (cfg.getType().equals("servicedependency")) {
String dHostName = cfg.getValueForAttr("dependent_host_name");
String dServiceDescr = cfg.getValueForAttr("dependent_service_description");
String hostName = cfg.getValueForAttr("host_name");
String serviceDescr = cfg.getValueForAttr("service_description");
if (dHostName == null) {
dHostName = "";
}
if (hostName == null) {
hostName = "";
}
id = dHostName.hashCode() + "_" + dServiceDescr + "_" + hostName.hashCode() + "_" + serviceDescr;
}
id = handleSpace(id);
String alias = "NAGIOS_I_" + cfg.getType() + "_" + id;
return(alias);
}
private void updateValues(CiBean bean, NagiosConfig cfg) {
updateCMDBValue(bean, "objectType", cfg.getType(), false);
// Special handling for Timeperiod.
if (cfg.getType().equals("timeperiod")) {
doTimeperiod(bean, cfg);
return;
}
for (NagiosConfigEntry entry : cfg.getEntries().values()) {
String value = entry.getValue();
// References and multivalues.
String type = getReferenceType(cfg, entry);
if (type != null) {
// Special handling for check_command..
if (type.equals("command")) {
String values[] = value.split("!", 2);
updateCMDBValue(bean, entry.getId(), "NAGIOS_I_" + type + "_" + handleSpace(values[0]), true);
if (values.length > 1) {
updateCMDBValue(bean, entry.getId()+"_arg", handleSpace(values[1]), false);
}
} else if (type.equals("service")) {
System.out.println("Service Relation:" + value);
addServiceToResolve(bean, entry, cfg.getType(), value);
} else {
String values[] = value.split(",");
for (String v : values) {
v = v.trim();
v = handleSpace(v);
updateCMDBValue(bean, entry.getId(), "NAGIOS_I_" + type + "_" + v, true);
}
}
} else {
updateCMDBValue(bean, entry.getId(), value, false);
}
}
}
private void addServiceToResolve(CiBean bean, NagiosConfigEntry id, String type, String value) {
ServiceRelation rel = new ServiceRelation();
rel.setBean(bean);
rel.setId(id);
rel.setValue(value);
rel.setType(type);
serviceRelations .add(rel);
}
private String handleSpace(String value) {
StringBuffer buf = new StringBuffer();
if (value != null) {
for (Character c : value.toCharArray()) {
if (c.isWhitespace(c) || c.equals(':') || c.equals('/')) {
buf.append("_");
} else {
buf.append(c);
}
/*
if (c.isLetterOrDigit(c)) {
buf.append(c);
} else {
buf.append("_");
}
*/
}
}
return(buf.toString());
}
private ValueBean updateCMDBValue(CiBean bean, String alias, String value,
boolean complex) {
// Validate that attribute exists.
ValueBean vBean = new ValueBean();
vBean.setAlias(alias);
vBean.setValue(value);
vBean.setComplexValue(complex);
bean.addAttributeValue(vBean);
return(vBean);
}
/**
* Special handling for timeperiod.
* @param bean
* @param cfg
*/
private void doTimeperiod(CiBean bean, NagiosConfig cfg) {
for (NagiosConfigEntry entry : cfg.getEntries().values()) {
String value = entry.getValue();
String name = entry.getId();
if (name.equals("exclude")) {
String values[] = value.split(",");
for (String v : values) {
updateCMDBValue(bean, entry.getId(), "NAGIOS_I_" + "timeperiod" + "_" + value, true);
}
} else if (name.equals("alias")) {
updateCMDBValue(bean, entry.getId(), value, false);
} else if (name.equals("timeperiod_name")) {
updateCMDBValue(bean, entry.getId(), value, false);
} else if (name.equals("use")) {
updateCMDBValue(bean, entry.getId(), value, false);
} else if (name.equals("use")) {
updateCMDBValue(bean, entry.getId(), value, false);
} else if (name.equals("name")) {
updateCMDBValue(bean, entry.getId(), value, false);
} else {
// Weekdays or exceptions.
if (weekDayMap.contains(name)) {
updateCMDBValue(bean, "weekday", name + " " + value, false);
} else {
updateCMDBValue(bean, "exception", name + " " + value, false);
}
}
}
}
private String getReferenceType(NagiosConfig cfg, NagiosConfigEntry entry) {
String type = referenceMap .get(cfg.getType() + "/" + entry.getId());
return(type);
}
private String getElementValue(Element sel,
String elementName, boolean requiered) {
Element el = sel.element(elementName);
if (el == null) {
if (requiered) {
throw new IllegalArgumentException("Element <" + elementName + "> is missing in <" +
sel.getName() + "> [" + sel.getPath() + "]");
}
return(null);
}
String text = el.getTextTrim();
return(text);
}
public String getInput() {
return input;
}
public void setInput(String input) {
this.input = input;
}
public String getOutput() {
return output;
}
public void setOutput(String output) {
this.output = output;
}
class ServiceRelation {
CiBean bean;
NagiosConfigEntry id;
String value;
String type;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public CiBean getBean() {
return bean;
}
public void setBean(CiBean bean) {
this.bean = bean;
}
public NagiosConfigEntry getId() {
return id;
}
public void setId(NagiosConfigEntry id) {
this.id = id;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}