blob: a614635ab0f3ad7cff167f432bde431580778567 [file] [log] [blame]
helenyrwu45700842016-06-09 12:01:30 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
helenyrwu45700842016-06-09 12:01:30 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.provider.netconf.alarm;
18
19import com.google.common.collect.ImmutableSet;
20import org.onosproject.incubator.net.faultmanagement.alarm.Alarm;
Ray Milkey0a1a0912018-02-15 11:35:58 -080021import org.onosproject.incubator.net.faultmanagement.alarm.AlarmId;
helenyrwu45700842016-06-09 12:01:30 -070022import org.onosproject.incubator.net.faultmanagement.alarm.AlarmTranslator;
23import org.onosproject.incubator.net.faultmanagement.alarm.DefaultAlarm;
24import org.onosproject.net.DeviceId;
25import org.slf4j.Logger;
26import org.w3c.dom.Document;
27import org.w3c.dom.Node;
28import org.xml.sax.InputSource;
29
30import javax.xml.parsers.DocumentBuilder;
31import javax.xml.parsers.DocumentBuilderFactory;
32import javax.xml.parsers.ParserConfigurationException;
33import javax.xml.transform.OutputKeys;
34import javax.xml.transform.Transformer;
35import javax.xml.transform.TransformerException;
36import javax.xml.transform.TransformerFactory;
37import javax.xml.transform.dom.DOMSource;
38import javax.xml.transform.stream.StreamResult;
39import java.io.IOException;
40import java.io.InputStream;
41import java.io.StringWriter;
Yuta HIGUCHI0c47d532017-08-18 23:16:35 -070042import java.time.Instant;
43import java.time.format.DateTimeFormatter;
helenyrwu45700842016-06-09 12:01:30 -070044import java.util.ArrayList;
45import java.util.Collection;
46
helenyrwu45700842016-06-09 12:01:30 -070047import org.xml.sax.SAXException;
48
49import static org.slf4j.LoggerFactory.getLogger;
50
51/**
52 * Translates NETCONF notification messages to actions on alarms.
53 */
54public class NetconfAlarmTranslator implements AlarmTranslator {
55
56 private final Logger log = getLogger(getClass());
57 private static final String EVENTTIME_TAGNAME = "eventTime";
58
Andrea Campanellad59f36c2018-06-14 14:42:04 +020059 private static final String DISALLOW_DTD_FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
60
61 private static final String DISALLOW_EXTERNAL_DTD =
62 "http://apache.org/xml/features/nonvalidating/load-external-dtd";
63
helenyrwu45700842016-06-09 12:01:30 -070064 @Override
65 public Collection<Alarm> translateToAlarm(DeviceId deviceId, InputStream message) {
66 try {
67 Collection<Alarm> alarms = new ArrayList<>();
68 Document doc = createDocFromMessage(message);
69
70 // parse date element value into long
71 Node eventTime = doc.getElementsByTagName(EVENTTIME_TAGNAME).item(0);
72 String date = eventTime.getTextContent();
73 long timeStamp = parseDate(date);
74
75 // event-specific tag names as alarm descriptions
76 Node descriptionNode = eventTime.getNextSibling();
77 while (descriptionNode != null) {
78 if (descriptionNode.getNodeType() == Node.ELEMENT_NODE) {
79 String description = nodeToString(descriptionNode);
Ray Milkey0a1a0912018-02-15 11:35:58 -080080 alarms.add(new DefaultAlarm.Builder(AlarmId.alarmId(deviceId, Long.toString(timeStamp)),
81 deviceId, description,
helenyrwu45700842016-06-09 12:01:30 -070082 Alarm.SeverityLevel.WARNING,
83 timeStamp).build());
84 descriptionNode = null;
85 } else {
86 descriptionNode = descriptionNode.getNextSibling();
87 }
88 }
89 return alarms;
90 } catch (SAXException | IOException | ParserConfigurationException |
91 UnsupportedOperationException | IllegalArgumentException |
92 TransformerException e) {
Yuta HIGUCHI100b5522017-05-03 14:26:11 -070093 log.error("Exception thrown translating message from {}.", deviceId, e);
helenyrwu45700842016-06-09 12:01:30 -070094 return ImmutableSet.of();
95 }
96 }
97
98 private Document createDocFromMessage(InputStream message)
99 throws SAXException, IOException, ParserConfigurationException {
100 DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
Andrea Campanellad59f36c2018-06-14 14:42:04 +0200101 //Disabling DTDs in order to avoid XXE xml-based attacks.
102 disableFeature(dbfactory, DISALLOW_DTD_FEATURE);
103 disableFeature(dbfactory, DISALLOW_EXTERNAL_DTD);
104 dbfactory.setXIncludeAware(false);
105 dbfactory.setExpandEntityReferences(false);
helenyrwu45700842016-06-09 12:01:30 -0700106 DocumentBuilder builder = dbfactory.newDocumentBuilder();
107 return builder.parse(new InputSource(message));
108 }
109
Andrea Campanellad59f36c2018-06-14 14:42:04 +0200110 private void disableFeature(DocumentBuilderFactory dbfactory, String feature) {
111 try {
112 dbfactory.setFeature(feature, true);
113 } catch (ParserConfigurationException e) {
114 // This should catch a failed setFeature feature
115 log.info("ParserConfigurationException was thrown. The feature '" +
116 feature + "' is probably not supported by your XML processor.");
117 }
118 }
119
helenyrwu45700842016-06-09 12:01:30 -0700120 private long parseDate(String timeStr)
121 throws UnsupportedOperationException, IllegalArgumentException {
Yuta HIGUCHI0c47d532017-08-18 23:16:35 -0700122 return DateTimeFormatter.ISO_DATE_TIME.parse(timeStr, Instant::from).getEpochSecond();
helenyrwu45700842016-06-09 12:01:30 -0700123 }
124
125 private static String nodeToString(Node rootNode) throws TransformerException {
126 TransformerFactory tf = TransformerFactory.newInstance();
127 Transformer transformer = tf.newTransformer();
128 transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
129 StringWriter writer = new StringWriter();
130 DOMSource source = new DOMSource(rootNode);
131 transformer.transform(source, new StreamResult(writer));
132 return writer.getBuffer().toString();
133 }
Andrea Campanellad59f36c2018-06-14 14:42:04 +0200134}