@Override public String prettyPrint() { StringBuffer sb = new StringBuffer(); for (OutlierSet<?> answer : _answers) { sb.append(" Hypothesis: every node in role "); sb.append(answer.getRole().orElse("<unknown role>")); sb.append(" should have the following definition for property "); sb.append(answer.getName() + ": " + answer.getDefinition() + "\n"); sb.append(" Outliers: "); sb.append(answer.getOutliers() + "\n"); sb.append(" Conformers: "); sb.append(answer.getConformers() + "\n\n"); } return sb.toString(); }
private List<AbstractRoleConsistencyQuestion> serverConsistencyPolicies() { OutliersHypothesis hypothesis = OutliersHypothesis.SAME_SERVERS; SortedMap<String, AnswerElement> roleAnswers = perRoleOutlierInfo(hypothesis); Multimap<String, OutlierSet<NavigableSet<String>>> outliersPerPropertyName = outliersByProperty( roleAnswers.values(), OutliersAnswerElement::getServerOutliers, OutlierSet::getName); // remove outlier sets where no nodes declare any servers List<String> undeclared = new LinkedList<>(); for (String name : outliersPerPropertyName.keySet()) { Collection<OutlierSet<NavigableSet<String>>> outlierSets = outliersPerPropertyName.get(name); if (outlierSets.stream() .allMatch(oset -> oset.getDefinition().isEmpty() && oset.getOutliers().isEmpty())) { undeclared.add(name); } } for (String name : undeclared) { outliersPerPropertyName.removeAll(name); } return policiesAboveThreshold(outliersPerPropertyName, hypothesis); }
@Override public boolean equals(Object o) { if (o == this) { return true; } else if (!(o instanceof OutlierSet)) { return false; } OutlierSet<?> rhs = (OutlierSet<?>) o; return super.equals(rhs) && _name.equals(rhs.getName()); }
@Override public RoleConsistencyAnswerElement answer() { RoleConsistencyQuestion question = (RoleConsistencyQuestion) _question; _answerElement = new RoleConsistencyAnswerElement(); OutliersQuestion innerQ = new OutliersQuestionPlugin().createQuestion(); innerQ.setHypothesis(OutliersHypothesis.SAME_SERVERS); SortedSet<String> serverSets = new TreeSet<>(); serverSets.add(question.getPropertyName()); innerQ.setServerSets(serverSets); innerQ.setVerbose(true); PerRoleQuestion outerQ = new PerRoleQuestion(null, innerQ, question.getRoleDimension(), null); // find all outliers for protocol-specific servers, on a per-role basis PerRoleQuestionPlugin outerPlugin = new PerRoleQuestionPlugin(); PerRoleAnswerElement roleAE = outerPlugin.createAnswerer(outerQ, _batfish).answer(); List<OutlierSet<NavigableSet<String>>> answers = new LinkedList<>(); for (Map.Entry<String, AnswerElement> entry : roleAE.getAnswers().entrySet()) { String role = entry.getKey(); OutliersAnswerElement ae = (OutliersAnswerElement) entry.getValue(); for (OutlierSet<NavigableSet<String>> answer : ae.getServerOutliers()) { answer.setRole(role); answers.add(answer); } } _answerElement.setAnswers(answers); return _answerElement; } }
private <T> void addPropertyOutliers( String name, Function<Configuration, T> accessor, SortedSet<OutlierSet<T>> rankedOutliers) { // partition the nodes into equivalence classes based on their values for the // property of interest Map<T, SortedSet<String>> equivSets = new HashMap<>(); for (String node : _nodes) { T definition = accessor.apply(_configurations.get(node)); SortedSet<String> matchingNodes = equivSets.getOrDefault(definition, new TreeSet<>()); matchingNodes.add(node); equivSets.put(definition, matchingNodes); } // the equivalence class of the largest size is treated as the one whose value is // hypothesized to be the correct one Map.Entry<T, SortedSet<String>> max = equivSets.entrySet().stream() .max(Comparator.comparingInt(e -> e.getValue().size())) .orElseThrow( () -> new BatfishException("Set " + name + " has no equivalence classes")); SortedSet<String> conformers = max.getValue(); T definition = max.getKey(); equivSets.remove(definition); SortedSet<String> outliers = new TreeSet<>(); for (SortedSet<String> nodes : equivSets.values()) { outliers.addAll(nodes); } if (_verbose || isWithinThreshold(conformers, outliers)) { rankedOutliers.add(new OutlierSet<>(name, definition, conformers, outliers)); } }
private SortedSet<OutlierSet<NavigableSet<String>>> serverOutliers(OutliersQuestion question) { SortedSet<String> serverSets = new TreeSet<>(question.getServerSets()); SortedMap<String, Function<Configuration, NavigableSet<String>>> serverSetAccessors = new TreeMap<>(); serverSetAccessors.put("DnsServers", Configuration::getDnsServers); serverSetAccessors.put("LoggingServers", Configuration::getLoggingServers); serverSetAccessors.put("NtpServers", Configuration::getNtpServers); serverSetAccessors.put("SnmpTrapServers", Configuration::getSnmpTrapServers); serverSetAccessors.put("TacacsServers", Configuration::getTacacsServers); if (serverSets.isEmpty()) { serverSets.addAll(serverSetAccessors.keySet()); } SortedSet<OutlierSet<NavigableSet<String>>> rankedOutliers = new TreeSet<>(); for (String serverSet : serverSets) { Function<Configuration, NavigableSet<String>> accessorF = serverSetAccessors.get(serverSet); if (accessorF != null) { addPropertyOutliers(serverSet, accessorF, rankedOutliers); } } if (!_verbose) { // remove outlier sets where the hypothesis is that a particular server set // should be empty. such hypotheses do not seem to be useful in general. rankedOutliers.removeIf(oset -> oset.getDefinition().isEmpty()); } return rankedOutliers; }
@Override // sort in reverse order of zScore, which is a measure of how likely it is that // our hypothesis is correct public int compareTo(OutlierSet<T> other) { int superScore = super.compareTo(other); if (superScore != 0) { return superScore; } return _name.compareTo(other.getName()); }
os.setRole(role); serverOutliers.add(os);
Optional<String> role = outlier.getRole(); role.ifPresent(s -> sb.append(" for role " + s)); sb.append(":\n"); sb.append(" every node should have the following set of "); sb.append(outlier.getName() + ": " + outlier.getDefinition() + "\n"); sb.append(" Outliers: "); sb.append(outlier.getOutliers() + "\n"); sb.append(" Conformers: "); sb.append(outlier.getConformers() + "\n\n");
sb.append(outlier.getName() + ": " + outlier.getDefinition() + "\n"); sb.append(" Outliers: "); sb.append(outlier.getOutliers() + "\n"); sb.append(" Conformers: "); sb.append(outlier.getConformers() + "\n\n");