From 994d97c64440ddcf817a3c9f554596df06c685c9 Mon Sep 17 00:00:00 2001
From: Brian Warner <warner@allmydata.com>
Date: Tue, 18 Nov 2008 15:30:15 -0700
Subject: [PATCH] webapi: introducer stats: add 'announcement_distinct_hosts'
 to the t=json form, to show how many distinct hosts are providing e.g.
 storage services

---
 docs/frontends/webapi.txt         | 17 ++++++++++++++++-
 src/allmydata/test/test_system.py |  2 ++
 src/allmydata/web/introweb.py     | 20 ++++++++++++++++++++
 3 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/docs/frontends/webapi.txt b/docs/frontends/webapi.txt
index 59ac9ed1..a91a478d 100644
--- a/docs/frontends/webapi.txt
+++ b/docs/frontends/webapi.txt
@@ -1162,7 +1162,22 @@ GET /   (introducer status)
 
  By adding "?t=json" to the URL, the node will return a JSON-formatted
  dictionary of stats values, which can be used to produce graphs of connected
- clients over time.
+ clients over time. This dictionary has the following keys:
+
+  ["subscription_summary"] : a dictionary mapping service name (like
+                             "storage") to an integer with the number of
+                             clients that have subscribed to hear about that
+                             service
+  ["announcement_summary"] : a dictionary mapping service name to an integer
+                             with the number of servers which are announcing
+                             that service
+  ["announcement_distinct_hosts"] : a dictionary mapping service name to an
+                                    integer which represents the number of
+                                    distinct hosts that are providing that
+                                    service. If two servers have announced
+                                    FURLs which use the same hostnames (but
+                                    different ports and tubids), they are
+                                    considered to be on the same host.
 
 
 == Static Files in /public_html ==
diff --git a/src/allmydata/test/test_system.py b/src/allmydata/test/test_system.py
index baa06b18..716544ee 100644
--- a/src/allmydata/test/test_system.py
+++ b/src/allmydata/test/test_system.py
@@ -802,6 +802,8 @@ class SystemTest(SystemTestMixin, unittest.TestCase):
                                      {"storage": 5})
                 self.failUnlessEqual(data["announcement_summary"],
                                      {"storage": 5, "stub_client": 5})
+                self.failUnlessEqual(data["announcement_distinct_hosts"],
+                                     {"storage": 1, "stub_client": 1})
             except unittest.FailTest:
                 print
                 print "GET %s?t=json output was:" % self.introweb_url
diff --git a/src/allmydata/web/introweb.py b/src/allmydata/web/introweb.py
index 13e48384..f1a6ad02 100644
--- a/src/allmydata/web/introweb.py
+++ b/src/allmydata/web/introweb.py
@@ -31,12 +31,32 @@ class IntroducerRoot(rend.Page):
         res["subscription_summary"] = subscription_summary
 
         announcement_summary = {}
+        service_hosts = {}
         for (ann,when) in i.get_announcements().values():
             (furl, service_name, ri_name, nickname, ver, oldest) = ann
             if service_name not in announcement_summary:
                 announcement_summary[service_name] = 0
             announcement_summary[service_name] += 1
+            if service_name not in service_hosts:
+                service_hosts[service_name] = set()
+            # it's nice to know how many distinct hosts are available for
+            # each service. We define a "host" by a set of addresses
+            # (hostnames or ipv4 addresses), which we extract from the
+            # connection hints. In practice, this is usually close
+            # enough: when multiple services are run on a single host,
+            # they're usually either configured with the same addresses,
+            # or setLocationAutomatically picks up the same interfaces.
+            locations = SturdyRef(furl).getTubRef().getLocations()
+            # list of tuples, ("ipv4", host, port)
+            host = frozenset([hint[1]
+                              for hint in locations
+                              if hint[0] == "ipv4"])
+            service_hosts[service_name].add(host)
         res["announcement_summary"] = announcement_summary
+        distinct_hosts = dict([(name, len(hosts))
+                               for (name, hosts)
+                               in service_hosts.iteritems()])
+        res["announcement_distinct_hosts"] = distinct_hosts
 
         return simplejson.dumps(res, indent=1) + "\n"
 
-- 
2.45.2