package org.batfish.question;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import org.batfish.common.Answerer;
import org.batfish.common.BatfishException;
import org.batfish.common.plugin.IBatfish;
import org.batfish.datamodel.answers.ConvertConfigurationAnswerElement;
import org.batfish.datamodel.answers.ParseVendorConfigurationAnswerElement;
import org.batfish.datamodel.answers.Problem;
import org.batfish.datamodel.answers.ProblemsAnswerElement;
import org.batfish.datamodel.questions.Question;
import com.fasterxml.jackson.annotation.JsonProperty;
public class UndefinedReferencesQuestionPlugin extends QuestionPlugin {
public static class UndefinedReferencesAnswerElement
extends ProblemsAnswerElement {
private SortedMap<String, SortedMap<String, SortedMap<String, SortedMap<String, SortedSet<Integer>>>>> _undefinedReferences;
public UndefinedReferencesAnswerElement() {
_undefinedReferences = new TreeMap<>();
}
public SortedMap<String, SortedMap<String, SortedMap<String, SortedMap<String, SortedSet<Integer>>>>> getUndefinedReferences() {
return _undefinedReferences;
}
@Override
public String prettyPrint() {
final StringBuilder sb = new StringBuilder();
_undefinedReferences.forEach((hostname, byType) -> {
sb.append(hostname + ":\n");
byType.forEach((type, byName) -> {
sb.append(" " + type + ":\n");
byName.forEach((name, byUsage) -> {
sb.append(" " + name + ":\n");
byUsage.forEach((usage, lines) -> {
sb.append(" " + usage + ": lines " + lines.toString()
+ "\n");
});
});
});
});
return sb.toString();
}
public void setUndefinedReferences(
SortedMap<String, SortedMap<String, SortedMap<String, SortedMap<String, SortedSet<Integer>>>>> undefinedReferences) {
_undefinedReferences = undefinedReferences;
}
}
public static class UndefinedReferencesAnswerer extends Answerer {
public UndefinedReferencesAnswerer(Question question, IBatfish batfish) {
super(question, batfish);
}
@Override
public UndefinedReferencesAnswerElement answer() {
UndefinedReferencesQuestion question = (UndefinedReferencesQuestion) _question;
Pattern nodeRegex;
try {
nodeRegex = Pattern.compile(question.getNodeRegex());
}
catch (PatternSyntaxException e) {
throw new BatfishException(
"Supplied regex for nodes is not a valid java regex: \""
+ question.getNodeRegex() + "\"",
e);
}
_batfish.checkConfigurations();
UndefinedReferencesAnswerElement answerElement = new UndefinedReferencesAnswerElement();
ConvertConfigurationAnswerElement ccae = _batfish
.loadConvertConfigurationAnswerElement();
ccae.getUndefinedReferences().forEach((hostname, byType) -> {
if (nodeRegex.matcher(hostname).matches()) {
answerElement.getUndefinedReferences().put(hostname, byType);
}
});
ParseVendorConfigurationAnswerElement pvcae = _batfish
.loadParseVendorConfigurationAnswerElement();
SortedMap<String, String> hostnameFilenameMap = pvcae.getFileMap();
answerElement.getUndefinedReferences().forEach((hostname, byType) -> {
String filename = hostnameFilenameMap.get(hostname);
if (filename != null) {
byType.forEach((type, byName) -> {
byName.forEach((name, byUsage) -> {
byUsage.forEach((usage, lines) -> {
String problemShort = "undefined:" + type + ":usage:"
+ usage + ":" + name;
Problem problem = answerElement.getProblems()
.get(problemShort);
if (problem == null) {
problem = new Problem();
String problemLong = "Undefined reference to structure of type: '"
+ type + "' with usage: '" + usage
+ "' named '" + name + "'";
problem.setDescription(problemLong);
answerElement.getProblems().put(problemShort,
problem);
}
problem.getFiles().put(filename, lines);
});
});
});
}
});
return answerElement;
}
}
// <question_page_comment>
/**
* Outputs cases where undefined structures (e.g., ACL, routemaps) are
* referenced.
* <p>
* Such occurrences indicate configuration errors and can have serious
* consequences with some vendors.
*
* @type UndefinedReferences onefile
*
* @param nodeRegex
* Regular expression for names of nodes to include. Default value
* is '.*' (all nodes).
*
* @example bf_answer("Nodes", nodeRegex="as1.*") Analyze all nodes whose
* names begin with "as1".
*/
public static class UndefinedReferencesQuestion extends Question {
private static final String NODE_REGEX_VAR = "nodeRegex";
private String _nodeRegex;
public UndefinedReferencesQuestion() {
_nodeRegex = ".*";
}
@Override
public boolean getDataPlane() {
return false;
}
@Override
public String getName() {
return "undefinedreferences";
}
@JsonProperty(NODE_REGEX_VAR)
public String getNodeRegex() {
return _nodeRegex;
}
@Override
public boolean getTraffic() {
return false;
}
@JsonProperty(NODE_REGEX_VAR)
public void setNodeRegex(String nodeRegex) {
_nodeRegex = nodeRegex;
}
}
@Override
protected Answerer createAnswerer(Question question, IBatfish batfish) {
return new UndefinedReferencesAnswerer(question, batfish);
}
@Override
protected Question createQuestion() {
return new UndefinedReferencesQuestion();
}
}