[tor-commits] [collector/master] Archive bridge pool assignments again.
karsten at torproject.org
karsten at torproject.org
Thu Sep 19 08:39:52 UTC 2019
commit b2b3363232fd1a425a6e83bde89b2687b56abc0a
Author: Karsten Loesing <karsten.loesing at gmx.net>
Date: Fri Aug 30 11:09:23 2019 +0200
Archive bridge pool assignments again.
Implements #31558.
---
CHANGELOG.md | 1 +
.../org/torproject/metrics/collector/Main.java | 3 +
.../BridgePoolAssignmentsProcessor.java | 363 +++++++++++++++++++++
.../metrics/collector/conf/Annotation.java | 1 +
.../metrics/collector/conf/Configuration.java | 1 +
.../org/torproject/metrics/collector/conf/Key.java | 6 +
.../persist/BridgePoolAssignmentPersistence.java | 34 ++
.../collector/persist/DescriptorPersistence.java | 2 +
.../metrics/collector/sync/SyncPersistence.java | 6 +
src/main/resources/collector.properties | 18 +
.../metrics/collector/conf/ConfigurationTest.java | 2 +-
.../metrics/collector/cron/CollecTorMainTest.java | 1 +
12 files changed, 437 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b38b124..4ecfb35 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,7 @@
- Remove Cobertura from the build process.
- Archive snowflake statistics.
- Update to metrics-lib 2.7.0.
+ - Archive bridge pool assignments again.
# Changes in version 1.9.1 - 2019-05-29
diff --git a/src/main/java/org/torproject/metrics/collector/Main.java b/src/main/java/org/torproject/metrics/collector/Main.java
index 6907e93..3150ffc 100644
--- a/src/main/java/org/torproject/metrics/collector/Main.java
+++ b/src/main/java/org/torproject/metrics/collector/Main.java
@@ -4,6 +4,7 @@
package org.torproject.metrics.collector;
import org.torproject.metrics.collector.bridgedescs.SanitizedBridgesWriter;
+import org.torproject.metrics.collector.bridgepools.BridgePoolAssignmentsProcessor;
import org.torproject.metrics.collector.conf.Configuration;
import org.torproject.metrics.collector.conf.ConfigurationException;
import org.torproject.metrics.collector.conf.Key;
@@ -49,6 +50,8 @@ public class Main {
static { // add a new main class here
collecTorMains.put(Key.BridgedescsActivated, SanitizedBridgesWriter.class);
+ collecTorMains.put(Key.BridgePoolAssignmentsActivated,
+ BridgePoolAssignmentsProcessor.class);
collecTorMains.put(Key.ExitlistsActivated, ExitListDownloader.class);
collecTorMains.put(Key.UpdateindexActivated, CreateIndexJson.class);
collecTorMains.put(Key.RelaydescsActivated, ArchiveWriter.class);
diff --git a/src/main/java/org/torproject/metrics/collector/bridgepools/BridgePoolAssignmentsProcessor.java b/src/main/java/org/torproject/metrics/collector/bridgepools/BridgePoolAssignmentsProcessor.java
new file mode 100644
index 0000000..cad91ef
--- /dev/null
+++ b/src/main/java/org/torproject/metrics/collector/bridgepools/BridgePoolAssignmentsProcessor.java
@@ -0,0 +1,363 @@
+/* Copyright 2011--2019 The Tor Project
+ * See LICENSE for licensing information */
+
+package org.torproject.metrics.collector.bridgepools;
+
+import org.torproject.metrics.collector.conf.Configuration;
+import org.torproject.metrics.collector.conf.ConfigurationException;
+import org.torproject.metrics.collector.conf.Key;
+import org.torproject.metrics.collector.cron.CollecTorMain;
+
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Hex;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.Stack;
+import java.util.TreeMap;
+
+public class BridgePoolAssignmentsProcessor extends CollecTorMain {
+
+ /**
+ * Class logger.
+ */
+ private static final Logger logger = LoggerFactory.getLogger(
+ BridgePoolAssignmentsProcessor.class);
+
+ /**
+ * Directory containing original, not-yet-sanitized bridge pool assignment
+ * files.
+ */
+ private File assignmentsDirectory;
+
+ /**
+ * Directory containing sanitized bridge pool assignments for tarballs.
+ */
+ private String outputPathName;
+
+ /**
+ * Directory containing recently stored sanitized bridge pool assignments.
+ */
+ private String recentPathName;
+
+ /**
+ * Timestamp format in bridge-pool-assignments line.
+ */
+ private DateTimeFormatter assignmentFormat = DateTimeFormatter.ofPattern(
+ "uuuu-MM-dd HH:mm:ss");
+
+ /**
+ * File name format.
+ */
+ private DateTimeFormatter filenameFormat = DateTimeFormatter.ofPattern(
+ "uuuu/MM/dd/uuuu-MM-dd-HH-mm-ss");
+
+ /**
+ * Initialize this class with the given configuration.
+ */
+ public BridgePoolAssignmentsProcessor(Configuration config) {
+ super(config);
+ }
+
+ /**
+ * Return the module identifier.
+ *
+ * @return Module identifier.
+ */
+ @Override
+ public String module() {
+ return "BridgePoolAssignments";
+ }
+
+ /**
+ * Return the synchronization marker.
+ *
+ * @return Synchronization marker.
+ */
+ @Override
+ protected String syncMarker() {
+ return "BridgePoolAssignments";
+ }
+
+ /**
+ * Start processing files, which includes reading original, not-yet-sanitized
+ * bridge pool assignment files from disk, splitting them into bridge pool
+ * assignment descriptors, sanitizing contained fingerprints, and writing
+ * sanitized bridge pool assignments to disk.
+ *
+ * @throws ConfigurationException Thrown if configuration values cannot be
+ * obtained.
+ */
+ @Override
+ protected void startProcessing() throws ConfigurationException {
+ logger.info("Starting bridge-pool-assignments module of CollecTor.");
+ this.initializeConfiguration();
+ List<File> assignmentFiles = this.listAssignmentFiles();
+ for (File assignmentFile : assignmentFiles) {
+ logger.info("Processing bridge pool assignment file '{}'...",
+ assignmentFile.getAbsolutePath());
+ for (Map.Entry<LocalDateTime, SortedMap<String, String>> e
+ : this.readBridgePoolAssignments(assignmentFile).entrySet()) {
+ LocalDateTime published = e.getKey();
+ SortedMap<String, String> originalAssignments = e.getValue();
+ SortedMap<String, String> sanitizedAssignments
+ = this.sanitizeAssignments(originalAssignments);
+ if (null == sanitizedAssignments) {
+ logger.warn("Unable to sanitize assignments published at {}. "
+ + "Skipping.", published);
+ continue;
+ }
+ String formattedSanitizedAssignments = this.formatSanitizedAssignments(
+ published, sanitizedAssignments);
+ File tarballFile = Paths.get(this.outputPathName,
+ published.format(this.filenameFormat)).toFile();
+ File rsyncFile = new File(this.recentPathName,
+ tarballFile.getName());
+ File[] outputFiles = new File[] { tarballFile, rsyncFile };
+ for (File outputFile : outputFiles) {
+ if (!outputFile.exists()) {
+ this.writeSanitizedAssignmentsToFile(outputFile,
+ formattedSanitizedAssignments);
+ }
+ }
+ }
+ }
+ this.cleanUpRsyncDirectory();
+ logger.info("Finished processing bridge pool assignment file(s).");
+ }
+
+ /**
+ * Initialize configuration by obtaining current configuration values and
+ * storing them in instance attributes.
+ */
+ private void initializeConfiguration() throws ConfigurationException {
+ this.outputPathName = Paths.get(config.getPath(Key.OutputPath).toString(),
+ "bridge-pool-assignments").toString();
+ this.recentPathName = Paths.get(config.getPath(Key.RecentPath).toString(),
+ "bridge-pool-assignments").toString();
+ this.assignmentsDirectory =
+ config.getPath(Key.BridgePoolAssignmentsLocalOrigins).toFile();
+ }
+
+ /**
+ * Compile a list of all assignment files in the input directory.
+ *
+ * @return List of assignment files.
+ */
+ private List<File> listAssignmentFiles() {
+ List<File> assignmentFiles = new ArrayList<>();
+ Stack<File> files = new Stack<>();
+ files.add(this.assignmentsDirectory);
+ while (!files.isEmpty()) {
+ File file = files.pop();
+ if (file.isDirectory()) {
+ File[] filesInDirectory = file.listFiles();
+ if (null != filesInDirectory) {
+ files.addAll(Arrays.asList(filesInDirectory));
+ }
+ } else if (file.getName().startsWith("assignments.log")) {
+ assignmentFiles.add(file);
+ }
+ }
+ return assignmentFiles;
+ }
+
+ /**
+ * Read one or more bridge pool assignments from the given file and store them
+ * in a map with keys being published timestamps and values being maps of
+ * (original, not-yet-sanitized) fingerprints and assignment details.
+ *
+ * @param assignmentFile File containing one or more bridge pool assignments.
+ * @return Map containing all read bridge pool assignments.
+ */
+ private SortedMap<LocalDateTime, SortedMap<String, String>>
+ readBridgePoolAssignments(File assignmentFile) {
+ SortedMap<LocalDateTime, SortedMap<String, String>>
+ readBridgePoolAssignments = new TreeMap<>();
+ try {
+ BufferedReader br;
+ if (assignmentFile.getName().endsWith(".gz")) {
+ br = new BufferedReader(new InputStreamReader(
+ new GzipCompressorInputStream(new FileInputStream(
+ assignmentFile))));
+ } else {
+ br = new BufferedReader(new FileReader(assignmentFile));
+ }
+ String line;
+ SortedMap<String, String> currentAssignments = null;
+ while ((line = br.readLine()) != null) {
+ if (line.startsWith("bridge-pool-assignment ")) {
+ try {
+ LocalDateTime bridgePoolAssignmentTime = LocalDateTime.parse(
+ line.substring("bridge-pool-assignment ".length()),
+ this.assignmentFormat);
+ if (readBridgePoolAssignments.containsKey(
+ bridgePoolAssignmentTime)) {
+ logger.warn("Input file {} contains duplicate line: {}. "
+ + "Discarding previously read line and subsequent assignment "
+ + "lines.", assignmentFile, line);
+ }
+ currentAssignments = new TreeMap<>();
+ readBridgePoolAssignments.put(bridgePoolAssignmentTime,
+ currentAssignments);
+ } catch (DateTimeException e) {
+ logger.warn("Could not parse timestamp from line {}. Skipping "
+ + "bridge pool assignment file '{}'.", line,
+ assignmentFile.getAbsolutePath(), e);
+ break;
+ }
+ } else if (null == currentAssignments) {
+ logger.warn("Input file {} does not start with a "
+ + "bridge-pool-assignments line. Skipping.",
+ assignmentFile);
+ break;
+ } else {
+ String[] parts = line.split(" ", 2);
+ if (parts.length < 2 || parts[0].length() < 40) {
+ logger.warn("Unrecognized line '{}'. Aborting.", line);
+ break;
+ }
+ if (currentAssignments.containsKey(parts[0])) {
+ logger.warn("Input file {} contains duplicate line: {}. "
+ + "Discarding previously read line.", assignmentFile, line);
+ }
+ currentAssignments.put(parts[0], parts[1]);
+ }
+ }
+ br.close();
+ } catch (IOException e) {
+ logger.warn("Could not read bridge pool assignment file '{}'. "
+ + "Skipping.", assignmentFile.getAbsolutePath(), e);
+ }
+ if (!readBridgePoolAssignments.isEmpty()
+ && readBridgePoolAssignments.lastKey().minusMinutes(330L)
+ .isBefore(LocalDateTime.now())) {
+ logger.warn("The last known bridge pool assignment list was "
+ + "published at {}, which is more than 5:30 hours in the past.",
+ readBridgePoolAssignments.lastKey());
+ }
+ return readBridgePoolAssignments;
+ }
+
+ /**
+ * Sanitize the given bridge pool assignments by returning a new map with keys
+ * being SHA-1 digests of keys found in the given map.
+ *
+ * @param originalAssignments Map of (original, not-yet-sanitized)
+ * fingerprints to assignment details.
+ * @return Map of sanitized fingerprints to assignment details.
+ */
+ private SortedMap<String, String> sanitizeAssignments(
+ SortedMap<String, String> originalAssignments) {
+ SortedMap<String, String> sanitizedAssignments = new TreeMap<>();
+ for (Map.Entry<String, String> e : originalAssignments.entrySet()) {
+ String originalFingerprint = e.getKey();
+ String assignmentDetails = e.getValue();
+ try {
+ String hashedFingerprint = Hex.encodeHexString(DigestUtils.sha1(
+ Hex.decodeHex(originalFingerprint.toCharArray()))).toLowerCase();
+ sanitizedAssignments.put(hashedFingerprint, assignmentDetails);
+ } catch (DecoderException ex) {
+ logger.warn("Unable to decode hex fingerprint. Aborting.", ex);
+ return null;
+ }
+ }
+ return sanitizedAssignments;
+ }
+
+ /**
+ * Format sanitized bridge pool assignments consisting of a published
+ * timestamp and a map of sanitized fingerprints to assignment details as a
+ * single string.
+ *
+ * @param published Published timestamp as found in the bridge-pool-assignment
+ * line.
+ * @param sanitizedAssignments Map of sanitized fingerprints to assignment
+ * details.
+ * @return Formatted sanitized bridge pool assignments.
+ */
+ private String formatSanitizedAssignments(LocalDateTime published,
+ SortedMap<String, String> sanitizedAssignments) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("@type bridge-pool-assignment 1.0\n");
+ sb.append(String.format("bridge-pool-assignment %s\n",
+ published.format(this.assignmentFormat)));
+ for (Map.Entry<String, String> e : sanitizedAssignments.entrySet()) {
+ sb.append(String.format("%s %s%n", e.getKey(), e.getValue()));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Write the given formatted sanitized bridge pool assignments to the given
+ * file, or if that fails for any reason, log a warning and exit.
+ *
+ * @param outputFile File to write to.
+ * @param formattedSanitizedAssignments Formatted sanitized bridge pool
+ * assignments to write.
+ */
+ private void writeSanitizedAssignmentsToFile(File outputFile,
+ String formattedSanitizedAssignments) {
+ if (!outputFile.getParentFile().exists()
+ && !outputFile.getParentFile().mkdirs()) {
+ logger.warn("Could not create parent directories of {}.", outputFile);
+ return;
+ }
+ try (BufferedWriter bw = new BufferedWriter(new FileWriter(outputFile))) {
+ bw.write(formattedSanitizedAssignments);
+ } catch (IOException e) {
+ logger.warn("Unable to write sanitized bridge pool assignments to {}.",
+ outputFile, e);
+ }
+ }
+
+ /**
+ * Delete all files from the rsync directory that have not been modified in
+ * the last three days.
+ */
+ public void cleanUpRsyncDirectory() {
+ Instant cutOff = Instant.now().minus(3L, ChronoUnit.DAYS);
+ Stack<File> allFiles = new Stack<>();
+ allFiles.add(new File(this.recentPathName));
+ while (!allFiles.isEmpty()) {
+ File file = allFiles.pop();
+ if (file.isDirectory()) {
+ File[] filesInDirectory = file.listFiles();
+ if (null != filesInDirectory) {
+ allFiles.addAll(Arrays.asList(filesInDirectory));
+ }
+ } else if (Instant.ofEpochMilli(file.lastModified()).isBefore(cutOff)) {
+ try {
+ Files.deleteIfExists(file.toPath());
+ } catch (IOException e) {
+ logger.warn("Unable to delete file {} that is apparently older than "
+ + "three days.", file, e);
+ }
+ }
+ }
+ }
+}
+
+
diff --git a/src/main/java/org/torproject/metrics/collector/conf/Annotation.java b/src/main/java/org/torproject/metrics/collector/conf/Annotation.java
index 8cd3324..7d2bbe9 100644
--- a/src/main/java/org/torproject/metrics/collector/conf/Annotation.java
+++ b/src/main/java/org/torproject/metrics/collector/conf/Annotation.java
@@ -8,6 +8,7 @@ public enum Annotation {
BandwidthFile("@type bandwidth-file 1.0\n"),
BridgeExtraInfo("@type bridge-extra-info 1.3\n"),
+ BridgePoolAssignment("@type bridge-pool-assignment 1.0\n"),
BridgeServer("@type bridge-server-descriptor 1.2\n"),
Cert("@type dir-key-certificate-3 1.0\n"),
Consensus("@type network-status-consensus-3 1.0\n"),
diff --git a/src/main/java/org/torproject/metrics/collector/conf/Configuration.java b/src/main/java/org/torproject/metrics/collector/conf/Configuration.java
index 27f5125..59229e3 100644
--- a/src/main/java/org/torproject/metrics/collector/conf/Configuration.java
+++ b/src/main/java/org/torproject/metrics/collector/conf/Configuration.java
@@ -88,6 +88,7 @@ public class Configuration extends Observable implements Cloneable {
private void anythingActivated() throws ConfigurationException {
if (!(this.getBool(Key.RelaydescsActivated)
|| this.getBool(Key.BridgedescsActivated)
+ || this.getBool(Key.BridgePoolAssignmentsActivated)
|| this.getBool(Key.ExitlistsActivated)
|| this.getBool(Key.UpdateindexActivated)
|| this.getBool(Key.OnionPerfActivated)
diff --git a/src/main/java/org/torproject/metrics/collector/conf/Key.java b/src/main/java/org/torproject/metrics/collector/conf/Key.java
index e683fe2..dfef673 100644
--- a/src/main/java/org/torproject/metrics/collector/conf/Key.java
+++ b/src/main/java/org/torproject/metrics/collector/conf/Key.java
@@ -27,6 +27,7 @@ public enum Key {
SyncPath(Path.class),
RelaySources(SourceType[].class),
BridgeSources(SourceType[].class),
+ BridgePoolAssignmentsSources(SourceType[].class),
ExitlistSources(SourceType[].class),
OnionPerfSources(SourceType[].class),
WebstatsSources(SourceType[].class),
@@ -35,6 +36,8 @@ public enum Key {
RelaySyncOrigins(URL[].class),
BridgeSyncOrigins(URL[].class),
BridgeLocalOrigins(Path.class),
+ BridgePoolAssignmentsLocalOrigins(Path.class),
+ BridgePoolAssignmentsSyncOrigins(URL[].class),
ExitlistSyncOrigins(URL[].class),
OnionPerfSyncOrigins(URL[].class),
WebstatsSyncOrigins(URL[].class),
@@ -42,6 +45,9 @@ public enum Key {
BridgedescsActivated(Boolean.class),
BridgedescsOffsetMinutes(Integer.class),
BridgedescsPeriodMinutes(Integer.class),
+ BridgePoolAssignmentsActivated(Boolean.class),
+ BridgePoolAssignmentsOffsetMinutes(Integer.class),
+ BridgePoolAssignmentsPeriodMinutes(Integer.class),
ExitlistsActivated(Boolean.class),
ExitlistsOffsetMinutes(Integer.class),
ExitlistsPeriodMinutes(Integer.class),
diff --git a/src/main/java/org/torproject/metrics/collector/persist/BridgePoolAssignmentPersistence.java b/src/main/java/org/torproject/metrics/collector/persist/BridgePoolAssignmentPersistence.java
new file mode 100644
index 0000000..5613060
--- /dev/null
+++ b/src/main/java/org/torproject/metrics/collector/persist/BridgePoolAssignmentPersistence.java
@@ -0,0 +1,34 @@
+/* Copyright 2016--2018 The Tor Project
+ * See LICENSE for licensing information */
+
+package org.torproject.metrics.collector.persist;
+
+import org.torproject.descriptor.BridgePoolAssignment;
+import org.torproject.metrics.collector.conf.Annotation;
+
+import java.nio.file.Paths;
+
+public class BridgePoolAssignmentPersistence
+ extends DescriptorPersistence<BridgePoolAssignment> {
+
+ public BridgePoolAssignmentPersistence(BridgePoolAssignment desc) {
+ super(desc, Annotation.BridgePoolAssignment.bytes());
+ calculatePaths();
+ }
+
+ private void calculatePaths() {
+ String file = PersistenceUtils.dateTime(desc.getPublishedMillis());
+ String[] parts = file.split(DASH);
+ this.recentPath = Paths.get(
+ BRIDGEPOOLASSIGNMENTS,
+ file).toString();
+ this.storagePath = Paths.get(
+ BRIDGEPOOLASSIGNMENTS,
+ parts[0], // year
+ parts[1], // month
+ parts[2], // day
+ file).toString();
+ }
+
+}
+
diff --git a/src/main/java/org/torproject/metrics/collector/persist/DescriptorPersistence.java b/src/main/java/org/torproject/metrics/collector/persist/DescriptorPersistence.java
index fed4839..3e7a06b 100644
--- a/src/main/java/org/torproject/metrics/collector/persist/DescriptorPersistence.java
+++ b/src/main/java/org/torproject/metrics/collector/persist/DescriptorPersistence.java
@@ -18,6 +18,8 @@ public abstract class DescriptorPersistence<T extends Descriptor> {
DescriptorPersistence.class);
protected static final String BRIDGEDESCS = "bridge-descriptors";
+ protected static final String BRIDGEPOOLASSIGNMENTS
+ = "bridge-pool-assignments";
protected static final String DASH = "-";
protected static final String DOT = ".";
protected static final String MICRODESC = "microdesc";
diff --git a/src/main/java/org/torproject/metrics/collector/sync/SyncPersistence.java b/src/main/java/org/torproject/metrics/collector/sync/SyncPersistence.java
index 4b3b7bc..cfc3dbe 100644
--- a/src/main/java/org/torproject/metrics/collector/sync/SyncPersistence.java
+++ b/src/main/java/org/torproject/metrics/collector/sync/SyncPersistence.java
@@ -6,6 +6,7 @@ package org.torproject.metrics.collector.sync;
import org.torproject.descriptor.BandwidthFile;
import org.torproject.descriptor.BridgeExtraInfoDescriptor;
import org.torproject.descriptor.BridgeNetworkStatus;
+import org.torproject.descriptor.BridgePoolAssignment;
import org.torproject.descriptor.BridgeServerDescriptor;
import org.torproject.descriptor.Descriptor;
import org.torproject.descriptor.ExitList;
@@ -21,6 +22,7 @@ import org.torproject.metrics.collector.conf.ConfigurationException;
import org.torproject.metrics.collector.conf.Key;
import org.torproject.metrics.collector.persist.BandwidthFilePersistence;
import org.torproject.metrics.collector.persist.BridgeExtraInfoPersistence;
+import org.torproject.metrics.collector.persist.BridgePoolAssignmentPersistence;
import org.torproject.metrics.collector.persist.BridgeServerDescriptorPersistence;
import org.torproject.metrics.collector.persist.ConsensusPersistence;
import org.torproject.metrics.collector.persist.DescriptorPersistence;
@@ -132,6 +134,10 @@ public class SyncPersistence {
descPersist = new BridgeServerDescriptorPersistence(
(BridgeServerDescriptor) desc, received);
break;
+ case "BridgePoolAssignment":
+ descPersist = new BridgePoolAssignmentPersistence(
+ (BridgePoolAssignment) desc);
+ break;
case "ExitList": // downloaded is part of desc, which to use?
descPersist = new ExitlistPersistence((ExitList) desc, received);
break;
diff --git a/src/main/resources/collector.properties b/src/main/resources/collector.properties
index a4eed7a..b180a3e 100644
--- a/src/main/resources/collector.properties
+++ b/src/main/resources/collector.properties
@@ -18,6 +18,12 @@ BridgedescsPeriodMinutes = 60
# offset in minutes since the epoch and
BridgedescsOffsetMinutes = 9
## the following defines, if this module is activated
+BridgePoolAssignmentsActivated = false
+# period in minutes
+BridgePoolAssignmentsPeriodMinutes = 60
+# offset in minutes since the epoch and
+BridgePoolAssignmentsOffsetMinutes = 9
+## the following defines, if this module is activated
ExitlistsActivated = false
# period in minutes
ExitlistsPeriodMinutes = 60
@@ -146,6 +152,18 @@ ReplaceIpAddressesWithHashes = false
BridgeDescriptorMappingsLimit = inf
#
#
+######## Bridge pool assignments ########
+#
+## Define descriptor sources
+# possible values: Sync, Local
+BridgePoolAssignmentsSources = Local
+## Retrieve files from the following instances.
+## List of URLs separated by comma.
+BridgePoolAssignmentsSyncOrigins = https://collector.torproject.org
+## Relative path to directory to read bridge pool assignment files from
+BridgePoolAssignmentsLocalOrigins = in/bridge-pool-assignments/
+#
+#
######## Exit lists ########
#
## Define descriptor sources
diff --git a/src/test/java/org/torproject/metrics/collector/conf/ConfigurationTest.java b/src/test/java/org/torproject/metrics/collector/conf/ConfigurationTest.java
index 3a69c0c..201d541 100644
--- a/src/test/java/org/torproject/metrics/collector/conf/ConfigurationTest.java
+++ b/src/test/java/org/torproject/metrics/collector/conf/ConfigurationTest.java
@@ -38,7 +38,7 @@ public class ConfigurationTest {
public void testKeyCount() {
assertEquals("The number of properties keys in enum Key changed."
+ "\n This test class should be adapted.",
- 59, Key.values().length);
+ 65, Key.values().length);
}
@Test()
diff --git a/src/test/java/org/torproject/metrics/collector/cron/CollecTorMainTest.java b/src/test/java/org/torproject/metrics/collector/cron/CollecTorMainTest.java
index d0fe173..99f1f48 100644
--- a/src/test/java/org/torproject/metrics/collector/cron/CollecTorMainTest.java
+++ b/src/test/java/org/torproject/metrics/collector/cron/CollecTorMainTest.java
@@ -69,6 +69,7 @@ public class CollecTorMainTest {
switch (marker) {
case "Relay":
case "Bridge":
+ case "BridgePoolAssignments":
case "Exitlist":
case "OnionPerf":
case "Webstats":
More information about the tor-commits
mailing list