[tor-commits] [metrics-web/master] Move the warning-generating code its own class.

karsten at torproject.org karsten at torproject.org
Thu Nov 10 19:51:08 UTC 2011


commit 1be161bb80559d23203b2b522bf8bdf33dfaebc3
Author: Karsten Loesing <karsten.loesing at gmx.net>
Date:   Thu Nov 10 18:50:31 2011 +0100

    Move the warning-generating code its own class.
---
 src/org/torproject/chc/Checker.java              |  288 ++++++++++++++++++++++
 src/org/torproject/chc/Main.java                 |   15 +-
 src/org/torproject/chc/MetricsWebsiteReport.java |    6 +
 src/org/torproject/chc/NagiosReport.java         |    5 +
 src/org/torproject/chc/Report.java               |    4 +
 src/org/torproject/chc/StdOutReport.java         |  282 +++++-----------------
 src/org/torproject/chc/Warning.java              |   46 ++++
 7 files changed, 421 insertions(+), 225 deletions(-)

diff --git a/src/org/torproject/chc/Checker.java b/src/org/torproject/chc/Checker.java
new file mode 100644
index 0000000..d095da4
--- /dev/null
+++ b/src/org/torproject/chc/Checker.java
@@ -0,0 +1,288 @@
+/* Copyright 2011 The Tor Project
+ * See LICENSE for licensing information */
+package org.torproject.chc;
+
+import java.io.*;
+import java.text.*;
+import java.util.*;
+
+/* Check a given consensus and votes for irregularities and write results
+ * to a warnings map consisting of warning type and details. */
+public class Checker {
+
+  /* Warning messages consisting of type and details. */
+  private SortedMap<Warning, String> warnings =
+      new TreeMap<Warning, String>();
+
+  public SortedMap<Warning, String> getWarnings() {
+    return this.warnings;
+  }
+
+  /* Date-time format to format timestamps. */
+  private static SimpleDateFormat dateTimeFormat;
+  static {
+    dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+    dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+  }
+
+  /* Downloaded consensus and corresponding votes for later
+   * processing. */
+  private SortedMap<String, Status> downloadedConsensuses;
+  private Status downloadedConsensus;
+  private SortedSet<Status> downloadedVotes;
+  public void processDownloadedConsensuses(
+      SortedMap<String, Status> downloadedConsensuses) {
+    this.downloadedConsensuses = downloadedConsensuses;
+  }
+
+  /* Check consensuses and votes for irregularities. */
+  public void checkConsensus() {
+    this.findMostRecentConsensus();
+    this.checkMissingConsensuses();
+    this.checkAllConsensusesFresh();
+    if (this.downloadedConsensus != null) {
+      if (this.isConsensusFresh(this.downloadedConsensus)) {
+        this.checkConsensusMethods();
+        this.checkRecommendedVersions();
+        this.checkConsensusParameters();
+        this.checkAuthorityKeys();
+        this.checkMissingVotes();
+        this.checkBandwidthScanners();
+      }
+    } else {
+      this.warnings.put(Warning.NoConsensusKnown, "");
+    }
+  }
+
+  /* Find most recent consensus and corresponding votes. */
+  private void findMostRecentConsensus() {
+    long mostRecentValidAfterMillis = -1L;
+    for (Status downloadedConsensus : downloadedConsensuses.values()) {
+      if (downloadedConsensus.getValidAfterMillis() >
+          mostRecentValidAfterMillis) {
+        this.downloadedConsensus = downloadedConsensus;
+        mostRecentValidAfterMillis =
+            downloadedConsensus.getValidAfterMillis();
+      }
+    }
+    if (this.downloadedConsensus != null) {
+      this.downloadedVotes = this.downloadedConsensus.getVotes();
+    }
+  }
+
+  /* Check if any directory authority didn't tell us a consensus. */
+  private void checkMissingConsensuses() {
+    SortedSet<String> missingConsensuses = new TreeSet<String>(
+        Arrays.asList(("gabelmoo,tor26,ides,maatuska,dannenberg,urras,"
+        + "moria1,dizum").split(",")));
+    missingConsensuses.removeAll(this.downloadedConsensuses.keySet());
+    if (!missingConsensuses.isEmpty()) {
+      StringBuilder sb = new StringBuilder();
+      for (String nickname : missingConsensuses) {
+        sb.append(", " + nickname);
+      }
+      this.warnings.put(Warning.ConsensusDownloadTimeout,
+          sb.toString().substring(2));
+    }
+  }
+
+  /* Check if all consensuses are fresh. */
+  private void checkAllConsensusesFresh() {
+    long fresh = System.currentTimeMillis() - 60L * 60L * 1000L;
+    SortedSet<String> nonFresh = new TreeSet<String>();
+    for (Map.Entry<String, Status> e : downloadedConsensuses.entrySet()) {
+      String nickname = e.getKey();
+      Status downloadedConsensus = e.getValue();
+      if (downloadedConsensus.getValidAfterMillis() < fresh) {
+        nonFresh.add(nickname);
+      }
+    }
+    if (!nonFresh.isEmpty()) {
+      StringBuilder sb = new StringBuilder();
+      for (String nickname : nonFresh) {
+        sb.append(", " + nickname);
+      }
+      this.warnings.put(Warning.ConsensusNotFresh,
+          sb.toString().substring(2));
+    }
+  }
+
+  /* Check if the most recent consensus is older than 1 hour. */
+  private boolean isConsensusFresh(Status consensus) {
+    return (consensus.getValidAfterMillis() >=
+        System.currentTimeMillis() - 60L * 60L * 1000L);
+  }
+
+  /* Check supported consensus methods of all votes. */
+  private void checkConsensusMethods() {
+    SortedSet<String> dirs = new TreeSet<String>();
+    for (Status vote : this.downloadedVotes) {
+      if (!vote.getConsensusMethods().contains(
+          this.downloadedConsensus.getConsensusMethods().last())) {
+        dirs.add(vote.getNickname());
+      }
+    }
+    if (!dirs.isEmpty()) {
+      StringBuilder sb = new StringBuilder();
+      for (String dir : dirs) {
+        sb.append(", " + dir);
+      }
+      this.warnings.put(Warning.ConsensusMethodNotSupported,
+          sb.toString().substring(2));
+    }
+  }
+
+  /* Check if the recommended versions in a vote are different from the
+   * recommended versions in the consensus. */
+  private void checkRecommendedVersions() {
+    SortedSet<String> unrecommendedClientVersions = new TreeSet<String>(),
+        unrecommendedServerVersions = new TreeSet<String>();
+    for (Status vote : this.downloadedVotes) {
+      if (vote.getRecommendedClientVersions() != null &&
+          !downloadedConsensus.getRecommendedClientVersions().equals(
+          vote.getRecommendedClientVersions())) {
+        StringBuilder message = new StringBuilder();
+        message.append(vote.getNickname());
+        for (String version : vote.getRecommendedClientVersions()) {
+          message.append(" " + version);
+        }
+        unrecommendedClientVersions.add(message.toString());
+      }
+      if (vote.getRecommendedServerVersions() != null &&
+          !downloadedConsensus.getRecommendedServerVersions().equals(
+          vote.getRecommendedServerVersions())) {
+        StringBuilder message = new StringBuilder();
+        message.append(vote.getNickname());
+        for (String version : vote.getRecommendedServerVersions()) {
+          message.append(" " + version);
+        }
+        unrecommendedServerVersions.add(message.toString());
+      }
+    }
+    if (!unrecommendedServerVersions.isEmpty()) {
+      StringBuilder sb = new StringBuilder();
+      for (String dir : unrecommendedServerVersions) {
+        sb.append(", " + dir);
+      }
+      this.warnings.put(Warning.DifferentRecommendedServerVersions,
+          sb.toString().substring(2));
+    }
+    if (!unrecommendedClientVersions.isEmpty()) {
+      StringBuilder sb = new StringBuilder();
+      for (String dir : unrecommendedClientVersions) {
+        sb.append(", " + dir);
+      }
+      this.warnings.put(Warning.DifferentRecommendedClientVersions,
+          sb.toString().substring(2));
+    }
+  }
+
+  /* Check if a vote contains conflicting or invalid consensus
+   * parameters. */
+  private void checkConsensusParameters() {
+    Set<String> validParameters = new HashSet<String>(Arrays.asList(
+        ("circwindow,CircuitPriorityHalflifeMsec,refuseunknownexits,"
+        + "cbtdisabled,cbtnummodes,cbtrecentcount,cbtmaxtimeouts,"
+        + "cbtmincircs,cbtquantile,cbtclosequantile,cbttestfreq,"
+        + "cbtmintimeout,cbtinitialtimeout,bwauthpid").split(",")));
+    SortedSet<String> conflicts = new TreeSet<String>();
+    for (Status vote : this.downloadedVotes) {
+      Map<String, String> voteConsensusParams =
+          vote.getConsensusParams();
+      boolean conflictOrInvalid = false;
+      if (voteConsensusParams != null) {
+        for (Map.Entry<String, String> e :
+            voteConsensusParams.entrySet()) {
+          if (!downloadedConsensus.getConsensusParams().containsKey(
+              e.getKey()) ||
+              !downloadedConsensus.getConsensusParams().get(e.getKey()).
+              equals(e.getValue()) ||
+              !validParameters.contains(e.getKey())) {
+            StringBuilder message = new StringBuilder();
+            message.append(vote.getNickname());
+            for (Map.Entry<String, String> p :
+                voteConsensusParams.entrySet()) {
+              message.append(" " + p.getKey() + "=" + p.getValue());
+            }
+            conflicts.add(message.toString());
+            break;
+          }
+        }
+      }
+    }
+    if (!conflicts.isEmpty()) {
+      StringBuilder sb = new StringBuilder();
+      for (String dir : conflicts) {
+        sb.append(", " + dir);
+      }
+      this.warnings.put(Warning.ConflictingOrInvalidConsensusParams,
+          sb.toString().substring(2));
+    }
+  }
+
+  /* Check whether any of the authority keys expire in the next 14
+   * days. */
+  private void checkAuthorityKeys() {
+    SortedMap<String, String> expiringCertificates =
+        new TreeMap<String, String>();
+    long now = System.currentTimeMillis();
+    for (Status vote : this.downloadedVotes) {
+      long voteDirKeyExpiresMillis = vote.getDirKeyExpiresMillis();
+      if (voteDirKeyExpiresMillis - 14L * 24L * 60L * 60L * 1000L < now) {
+        expiringCertificates.put(vote.getNickname(),
+            dateTimeFormat.format(voteDirKeyExpiresMillis));
+      }
+    }
+    if (!expiringCertificates.isEmpty()) {
+      StringBuilder sb = new StringBuilder();
+      for (Map.Entry<String, String> e :
+          expiringCertificates.entrySet()) {
+        String dir = e.getKey();
+        String timestamp = e.getValue();
+        sb.append(", " + dir + " " + timestamp);
+      }
+      this.warnings.put(Warning.CertificateExpiresSoon,
+          sb.toString().substring(2));
+    }
+  }
+
+  /* Check if any votes are missing. */
+  private void checkMissingVotes() {
+    SortedSet<String> knownAuthorities = new TreeSet<String>(
+        Arrays.asList(("dannenberg,dizum,gabelmoo,ides,maatuska,moria1,"
+        + "tor26,urras").split(",")));
+    SortedSet<String> missingVotes =
+        new TreeSet<String>(knownAuthorities);
+    for (Status vote : this.downloadedVotes) {
+      missingVotes.remove(vote.getNickname());
+    }
+    if (!missingVotes.isEmpty()) {
+      StringBuilder sb = new StringBuilder();
+      for (String missingDir : missingVotes) {
+        sb.append(", " + missingDir);
+      }
+      this.warnings.put(Warning.VotesMissing,
+          sb.toString().substring(2));
+    }
+  }
+
+  /* Check if any bandwidth scanner results are missing. */
+  private void checkBandwidthScanners() {
+    SortedSet<String> missingBandwidthScanners = new TreeSet<String>(
+        Arrays.asList("ides,urras,moria1,gabelmoo,maatuska".split(",")));
+    for (Status vote : this.downloadedVotes) {
+      if (vote.getBandwidthWeights() > 0) {
+        missingBandwidthScanners.remove(vote.getNickname());
+      }
+    }
+    if (!missingBandwidthScanners.isEmpty()) {
+      StringBuilder sb = new StringBuilder();
+      for (String dir : missingBandwidthScanners) {
+        sb.append(", " + dir);
+      }
+      this.warnings.put(Warning.BandwidthScannerResultsMissing,
+          sb.toString().substring(2));
+    }
+  }
+}
+
diff --git a/src/org/torproject/chc/Main.java b/src/org/torproject/chc/Main.java
index aa25e57..cdc65c3 100644
--- a/src/org/torproject/chc/Main.java
+++ b/src/org/torproject/chc/Main.java
@@ -21,16 +21,21 @@ public class Main {
     Downloader downloader = new Downloader();
     downloader.downloadFromAuthorities();
 
-    /* Parse consensus and votes and pass them to the reports. */
+    /* Parse consensus and votes. */
     Parser parser = new Parser();
     SortedMap<String, Status> parsedDownloadedConsensuses = parser.parse(
         downloader.getConsensusStrings(), downloader.getVoteStrings());
-    for (Report report : reports) {
-      report.processDownloadedConsensuses(parsedDownloadedConsensuses);
-    }
 
-    /* Finish writing reports. */
+    /* Check consensus and votes for possible problems. */
+    Checker checker = new Checker();
+    checker.processDownloadedConsensuses(parsedDownloadedConsensuses);
+    SortedMap<Warning, String> warnings = checker.getWarnings();
+
+    /* Pass warnings, consensuses, and votes to the reports, and finish
+     * writing them. */
     for (Report report : reports) {
+      report.processWarnings(warnings);
+      report.processDownloadedConsensuses(parsedDownloadedConsensuses);
       report.writeReport();
     }
 
diff --git a/src/org/torproject/chc/MetricsWebsiteReport.java b/src/org/torproject/chc/MetricsWebsiteReport.java
index e1adc57..8aa52b5 100644
--- a/src/org/torproject/chc/MetricsWebsiteReport.java
+++ b/src/org/torproject/chc/MetricsWebsiteReport.java
@@ -25,6 +25,12 @@ public class MetricsWebsiteReport implements Report {
     this.htmlOutputFile = new File(htmlOutputFilename);
   }
 
+  /* Process warnings. */
+  public void processWarnings(SortedMap<Warning, String> warnings) {
+    /* We could use these warnings instead of running all checks
+     * ourselves.  But we're not doing that yet. */
+  }
+
   /* Store the downloaded consensus and corresponding votes for later
    * processing. */
   private Status downloadedConsensus;
diff --git a/src/org/torproject/chc/NagiosReport.java b/src/org/torproject/chc/NagiosReport.java
index e7f5d03..6394c98 100644
--- a/src/org/torproject/chc/NagiosReport.java
+++ b/src/org/torproject/chc/NagiosReport.java
@@ -28,6 +28,11 @@ public class NagiosReport implements Report {
     this.downloadedConsensuses = downloadedConsensuses;
   }
 
+  /* Process warnings. */
+  public void processWarnings(SortedMap<Warning, String> warnings) {
+    /* Don't use these warnings.  This class will go away soon anyway. */
+  }
+
   /* Lists of output messages sorted by warnings, criticals, and
    * unknowns (increasing severity). */
   private List<String> nagiosWarnings = new ArrayList<String>(),
diff --git a/src/org/torproject/chc/Report.java b/src/org/torproject/chc/Report.java
index 0f1a306..48015eb 100644
--- a/src/org/torproject/chc/Report.java
+++ b/src/org/torproject/chc/Report.java
@@ -13,6 +13,10 @@ public interface Report {
   public abstract void processDownloadedConsensuses(
       SortedMap<String, Status> downloadedConsensuses);
 
+  /* Process warnings consisting of warning type and details. */
+  public abstract void processWarnings(
+      SortedMap<Warning, String> warnings);
+
   /* Finish writing report. */
   public abstract void writeReport();
 }
diff --git a/src/org/torproject/chc/StdOutReport.java b/src/org/torproject/chc/StdOutReport.java
index 3512480..afdaba3 100644
--- a/src/org/torproject/chc/StdOutReport.java
+++ b/src/org/torproject/chc/StdOutReport.java
@@ -10,10 +10,6 @@ import java.util.*;
  * to stdout while rate-limiting warnings based on severity. */
 public class StdOutReport implements Report {
 
-  /* Warning messages and the time in millis that should have passed
-   * since sending them out. */
-  private Map<String, Long> warnings = new HashMap<String, Long>();
-
   /* Date-time format to format timestamps. */
   private static SimpleDateFormat dateTimeFormat;
   static {
@@ -31,25 +27,16 @@ public class StdOutReport implements Report {
     this.downloadedConsensuses = downloadedConsensuses;
   }
 
+  /* Warnings obtained from checking the current consensus and votes. */
+  private SortedMap<Warning, String> warnings;
+  public void processWarnings(SortedMap<Warning, String> warnings) {
+    this.warnings = warnings;
+  }
+
   /* Check consensuses and votes for irregularities and write output to
    * stdout. */
   public void writeReport() {
     this.readLastWarned();
-    this.findMostRecentConsensus();
-    this.checkMissingConsensuses();
-    this.checkAllConsensusesFresh();
-    if (this.downloadedConsensus != null) {
-      if (this.isConsensusFresh(this.downloadedConsensus)) {
-        this.checkConsensusMethods();
-        this.checkRecommendedVersions();
-        this.checkConsensusParameters();
-        this.checkAuthorityKeys();
-        this.checkMissingVotes();
-        this.checkBandwidthScanners();
-      }
-    } else {
-      this.warnings.put("No consensus known", 0L);
-    }
     this.prepareReport();
     this.writeReportToStdOut();
     this.writeLastWarned();
@@ -91,211 +78,66 @@ public class StdOutReport implements Report {
     }
   }
 
-  /* Find most recent consensus and corresponding votes. */
-  private void findMostRecentConsensus() {
-    long mostRecentValidAfterMillis = -1L;
-    for (Status downloadedConsensus : downloadedConsensuses.values()) {
-      if (downloadedConsensus.getValidAfterMillis() >
-          mostRecentValidAfterMillis) {
-        this.downloadedConsensus = downloadedConsensus;
-        mostRecentValidAfterMillis =
-            downloadedConsensus.getValidAfterMillis();
-      }
-    }
-    if (this.downloadedConsensus != null) {
-      this.downloadedVotes = this.downloadedConsensus.getVotes();
-    }
-  }
-
-  /* Check if any directory authority didn't tell us a consensus. */
-  private void checkMissingConsensuses() {
-    SortedSet<String> missingConsensuses = new TreeSet<String>(
-        Arrays.asList(("gabelmoo,tor26,ides,maatuska,dannenberg,urras,"
-        + "moria1,dizum").split(",")));
-    missingConsensuses.removeAll(this.downloadedConsensuses.keySet());
-    if (!missingConsensuses.isEmpty()) {
-      StringBuilder sb = new StringBuilder();
-      for (String nickname : missingConsensuses) {
-        sb.append(", " + nickname);
-      }
-      this.warnings.put("The following directory authorities did not "
-          + "return a consensus within a timeout of 60 seconds: "
-          + sb.toString().substring(2), 150L * 60L * 1000L);
-    }
-  }
-
-  /* Check if all consensuses are fresh. */
-  private void checkAllConsensusesFresh() {
-    long fresh = System.currentTimeMillis() - 60L * 60L * 1000L;
-    SortedSet<String> nonFresh = new TreeSet<String>();
-    for (Map.Entry<String, Status> e : downloadedConsensuses.entrySet()) {
-      String nickname = e.getKey();
-      Status downloadedConsensus = e.getValue();
-      if (downloadedConsensus.getValidAfterMillis() < fresh) {
-        nonFresh.add(nickname);
-      }
-    }
-    if (!nonFresh.isEmpty()) {
-      StringBuilder sb = new StringBuilder();
-      for (String nickname : nonFresh) {
-        sb.append(", " + nickname);
-      }
-      this.warnings.put("The consensuses published by the following "
-          + "directory authorities are more than 1 hour old and "
-          + "therefore not fresh anymore: "
-          + sb.toString().substring(2), 150L * 60L * 1000L);
-    }
-  }
-
-  /* Check if the most recent consensus is older than 1 hour. */
-  private boolean isConsensusFresh(Status consensus) {
-    if (consensus.getValidAfterMillis() <
-        System.currentTimeMillis() - 60L * 60L * 1000L) {
-      return false;
-    } else {
-      return true;
-    }
-  }
-
-  /* Check supported consensus methods of all votes. */
-  private void checkConsensusMethods() {
-    for (Status vote : this.downloadedVotes) {
-      if (!vote.getConsensusMethods().contains(
-          this.downloadedConsensus.getConsensusMethods().last())) {
-        this.warnings.put(vote.getNickname() + " does not "
-            + "support consensus method "
-            + this.downloadedConsensus.getConsensusMethods().last(),
-            24L * 60L * 60L * 1000L);
-      }
-    }
-  }
-
-  /* Check if the recommended versions in a vote are different from the
-   * recommended versions in the consensus. */
-  private void checkRecommendedVersions() {
-    for (Status vote : this.downloadedVotes) {
-      if (vote.getRecommendedClientVersions() != null &&
-          !downloadedConsensus.getRecommendedClientVersions().equals(
-          vote.getRecommendedClientVersions())) {
-        StringBuilder message = new StringBuilder();
-        message.append(vote.getNickname() + " recommends other "
-            + "client versions than the consensus:");
-        for (String version : vote.getRecommendedClientVersions()) {
-          message.append(" " + version);
-        }
-        this.warnings.put(message.toString(), 150L * 60L * 1000L);
-      }
-      if (vote.getRecommendedServerVersions() != null &&
-          !downloadedConsensus.getRecommendedServerVersions().equals(
-          vote.getRecommendedServerVersions())) {
-        StringBuilder message = new StringBuilder();
-        message.append(vote.getNickname() + " recommends other "
-            + "server versions than the consensus:");
-        for (String version : vote.getRecommendedServerVersions()) {
-          message.append(" " + version);
-        }
-        this.warnings.put(message.toString(), 150L * 60L * 1000L);
-      }
-    }
-  }
-
-  /* Check if a vote contains conflicting or invalid consensus
-   * parameters. */
-  private void checkConsensusParameters() {
-    Set<String> validParameters = new HashSet<String>(Arrays.asList(
-        ("circwindow,CircuitPriorityHalflifeMsec,refuseunknownexits,"
-        + "cbtdisabled,cbtnummodes,cbtrecentcount,cbtmaxtimeouts,"
-        + "cbtmincircs,cbtquantile,cbtclosequantile,cbttestfreq,"
-        + "cbtmintimeout,cbtinitialtimeout,bwauthpid").split(",")));
-    for (Status vote : this.downloadedVotes) {
-      Map<String, String> voteConsensusParams =
-          vote.getConsensusParams();
-      boolean conflictOrInvalid = false;
-      if (voteConsensusParams != null) {
-        for (Map.Entry<String, String> e :
-            voteConsensusParams.entrySet()) {
-          if (!downloadedConsensus.getConsensusParams().containsKey(
-              e.getKey()) ||
-              !downloadedConsensus.getConsensusParams().get(e.getKey()).
-              equals(e.getValue()) ||
-              !validParameters.contains(e.getKey())) {
-            StringBuilder message = new StringBuilder();
-            message.append(vote.getNickname() + " sets conflicting or "
-                + "invalid consensus parameters:");
-            for (Map.Entry<String, String> p :
-                voteConsensusParams.entrySet()) {
-              message.append(" " + p.getKey() + "=" + p.getValue());
-            }
-            this.warnings.put(message.toString(), 150L * 60L * 1000L);
-            break;
-          }
-        }
-      }
-    }
-  }
-
-  /* Check whether any of the authority keys expire in the next 14
-   * days. */
-  private void checkAuthorityKeys() {
-    for (Status vote : this.downloadedVotes) {
-      long voteDirKeyExpiresMillis = vote.getDirKeyExpiresMillis();
-      if (voteDirKeyExpiresMillis - 14L * 24L * 60L * 60L * 1000L <
-          System.currentTimeMillis()) {
-        this.warnings.put(vote.getNickname() + "'s certificate "
-            + "expires in the next 14 days: "
-            + dateTimeFormat.format(voteDirKeyExpiresMillis),
-            24L * 60L * 60L * 1000L);
-      }
-    }
-  }
-
-  /* Check if any votes are missing. */
-  private void checkMissingVotes() {
-    SortedSet<String> knownAuthorities = new TreeSet<String>(
-        Arrays.asList(("dannenberg,dizum,gabelmoo,ides,maatuska,moria1,"
-        + "tor26,urras").split(",")));
-    SortedSet<String> missingVotes =
-        new TreeSet<String>(knownAuthorities);
-    for (Status vote : this.downloadedVotes) {
-      missingVotes.remove(vote.getNickname());
-    }
-    if (!missingVotes.isEmpty()) {
-      StringBuilder sb = new StringBuilder();
-      for (String missingDir : missingVotes) {
-        sb.append(", " + missingDir);
-      }
-      this.warnings.put("We're missing votes from the following "
-          + "directory authorities: " + sb.toString().substring(2),
-          150L * 60L * 1000L);
-    }
-  }
-
-  /* Check if any bandwidth scanner results are missing. */
-  private void checkBandwidthScanners() {
-    SortedSet<String> missingBandwidthScanners = new TreeSet<String>(
-        Arrays.asList("ides,urras,moria1,gabelmoo,maatuska".split(",")));
-    for (Status vote : this.downloadedVotes) {
-      if (vote.getBandwidthWeights() > 0) {
-        missingBandwidthScanners.remove(vote.getNickname());
-      }
-    }
-    if (!missingBandwidthScanners.isEmpty()) {
-      StringBuilder sb = new StringBuilder();
-      for (String dir : missingBandwidthScanners) {
-        sb.append(", " + dir);
-      }
-      this.warnings.put("The following directory authorities are not "
-          + "reporting bandwidth scanner results: "
-          + sb.toString().substring(2), 150L * 60L * 1000L);
-    }
-  }
-
   /* Prepare a report to be written to stdout. */
   private String preparedReport = null;
   private void prepareReport() {
+    SortedMap<String, Long> warningStrings = new TreeMap<String, Long>();
+    for (Map.Entry<Warning, String> e : this.warnings.entrySet()) {
+      Warning type = e.getKey();
+      String details = e.getValue();
+      switch (type) {
+        case NoConsensusKnown:
+          break;
+        case ConsensusDownloadTimeout:
+          warningStrings.put("The following directory authorities did "
+              + "not return a consensus within a timeout of 60 seconds: "
+              + details, 150L * 60L * 1000L);
+          break;
+        case ConsensusNotFresh:
+          warningStrings.put("The consensuses published by the following "
+              + "directory authorities are more than 1 hour old and "
+              + "therefore not fresh anymore: " + details,
+              150L * 60L * 1000L);
+          break;
+        case ConsensusMethodNotSupported:
+          warningStrings.put("The following directory authorities do not "
+              + "support the consensus method that the consensus uses: "
+              + details, 24L * 60L * 60L * 1000L);
+          break;
+        case DifferentRecommendedClientVersions:
+          warningStrings.put("The following directory authorities "
+              + "recommend other client versions than the consensus: "
+              + details, 150L * 60L * 1000L);
+          break;
+        case DifferentRecommendedServerVersions:
+          warningStrings.put("The following directory authorities "
+              + "recommend other server versions than the consensus: "
+              + details, 150L * 60L * 1000L);
+          break;
+        case ConflictingOrInvalidConsensusParams:
+          warningStrings.put("The following directory authorities set "
+              + "conflicting or invalid consensus parameters: " + details,
+              150L * 60L * 1000L);
+          break;
+        case CertificateExpiresSoon:
+          warningStrings.put("The certificates of the following "
+              + "directory authorities expire within the next 14 days: "
+              + details, 24L * 60L * 60L * 1000L);
+          break;
+        case VotesMissing:
+          warningStrings.put("We're missing votes from the following "
+              + "directory authorities: " + details, 150L * 60L * 1000L);
+          break;
+        case BandwidthScannerResultsMissing:
+          warningStrings.put("The following directory authorities are "
+              + "not reporting bandwidth scanner results: " + details,
+              150L * 60L * 1000L);
+          break;
+      }
+    }
     long now = System.currentTimeMillis();
     boolean writeReport = false;
-    for (Map.Entry<String, Long> e : this.warnings.entrySet()) {
+    for (Map.Entry<String, Long> e : warningStrings.entrySet()) {
       String message = e.getKey();
       long warnInterval = e.getValue();
       if (!lastWarned.containsKey(message) ||
@@ -305,7 +147,7 @@ public class StdOutReport implements Report {
     }
     if (writeReport) {
       StringBuilder sb = new StringBuilder();
-      for (String message : this.warnings.keySet()) {
+      for (String message : warningStrings.keySet()) {
         this.lastWarned.put(message, now);
         sb.append("\n\n" + message);
       }
diff --git a/src/org/torproject/chc/Warning.java b/src/org/torproject/chc/Warning.java
new file mode 100644
index 0000000..3425c6c
--- /dev/null
+++ b/src/org/torproject/chc/Warning.java
@@ -0,0 +1,46 @@
+/* Copyright 2011 The Tor Project
+ * See LICENSE for licensing information */
+package org.torproject.chc;
+
+/* Warning about irregularities in parsed consensuses and votes. */
+public enum Warning {
+
+  /* No consensus is known that can be checked. */
+  NoConsensusKnown,
+
+  /* One or more directory authorities did not return a consensus within a
+   * timeout of 60 seconds. */
+  ConsensusDownloadTimeout,
+
+  /* One or more directory authorities published a consensus that is more
+   * than 1 hour old and therefore not fresh anymore. */
+  ConsensusNotFresh,
+
+  /* One or more directory authorities does not support the consensus
+   * method that the consensus uses. */
+  ConsensusMethodNotSupported,
+
+  /* One or more directory authorities recommends different client
+   * versions than the ones in the consensus. */
+  DifferentRecommendedClientVersions,
+
+  /* One or more directory authorities recommends different server
+   * versions than the ones in the consensus. */
+  DifferentRecommendedServerVersions,
+
+  /* One or more directory authorities set conflicting or invalid
+   * consensus parameters. */
+  ConflictingOrInvalidConsensusParams,
+
+  /* The certificate(s) of one or more directory authorities expire within
+   * the next 14 days. */
+  CertificateExpiresSoon,
+
+  /* The vote(s) of one or more directory authorities are missing. */
+  VotesMissing,
+
+  /* One or more directory authorities are not reporting bandwidth scanner
+   * results. */
+  BandwidthScannerResultsMissing
+}
+





More information about the tor-commits mailing list