Changeset f57d1e9 in trunk
- Timestamp:
- 2016-05-05T01:37:23Z (9 years ago)
- Branches:
- master
- Children:
- 1e1e86f
- Parents:
- d1d9884 (diff), 93bb3e9 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent. - Files:
-
- 1 added
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
TabularUnified docs/stats.rst ¶
rd1d9884 rf57d1e9 280 280 The stats-gatherer is created in the same fashion as regular tahoe client 281 281 nodes and introducer nodes. Choose a base directory for the gatherer to live 282 in (but do not create the directory). Then run: 282 in (but do not create the directory). Choose the hostname that should be 283 advertised in the gatherer's FURL. Then run: 283 284 284 285 :: 285 286 286 tahoe create-stats-gatherer $BASEDIR287 tahoe create-stats-gatherer --hostname=HOSTNAME $BASEDIR 287 288 288 289 and start it with "tahoe start $BASEDIR". Once running, the gatherer will … … 296 297 297 298 [client] 298 stats_gatherer.furl = pb://qbo4ktl667zmtiuou6lwbjryli2brv6t@ 192.168.0.8:49997/wxycb4kaexzskubjnauxeoptympyf45y299 stats_gatherer.furl = pb://qbo4ktl667zmtiuou6lwbjryli2brv6t@HOSTNAME:PORTNUM/wxycb4kaexzskubjnauxeoptympyf45y 299 300 300 301 or simply copy the stats_gatherer.furl file into the node's base directory 301 302 (next to the tahoe.cfg file): it will be interpreted in the same way. 302 303 303 The first time it is started, the gatherer will listen on a random unused TCP 304 port, so it should not conflict with anything else that you have running on 305 that host at that time. On subsequent runs, it will re-use the same port (to 306 keep its FURL consistent). To explicitly control which port it uses, write 307 the desired portnumber into a file named "portnum" (i.e. $BASEDIR/portnum), 308 and the next time the gatherer is started, it will start listening on the 309 given port. The portnum file is actually a "strports specification string", 310 as described in :doc:`configuration`. 304 When the gatherer is created, it will allocate a random unused TCP port, so 305 it should not conflict with anything else that you have running on that host 306 at that time. To explicitly control which port it uses, run the creation 307 command with ``--location=`` and ``--port=`` instead of ``--hostname=``. If 308 you use a hostname of ``example.org`` and a port number of ``1234``, then 309 run:: 310 311 tahoe create-stats-gatherer --location=tcp:example.org:1234 --port=tcp:1234 312 313 ``--location=`` is a Foolscap FURL hints string (so it can be a 314 comma-separated list of connection hints), and ``--port=`` is a Twisted 315 "server endpoint specification string", as described in :doc:`configuration`. 311 316 312 317 Once running, the stats gatherer will create a standard JSON file in … … 323 328 "storage_server.disk_avail' values from all servers to compute a 324 329 total-disk-available number for the entire grid (however, the "disk watcher" 325 daemon, in misc/operations_helpers/spacetime/, is better suited for this specific task). 330 daemon, in misc/operations_helpers/spacetime/, is better suited for this 331 specific task). 326 332 327 333 Using Munin To Graph Stats Values 328 334 ================================= 329 335 330 The misc/ munin/ directory contains various plugins to graph stats for Tahoe331 nodes. They are intended for use with the Munin_ system-management tool, which 332 typically polls target systems every 5 minutes and produces a web page with 333 graphs of various things over multiple time scales (last hour, last month, 334 last year).336 The misc/operations_helpers/munin/ directory contains various plugins to 337 graph stats for Tahoe nodes. They are intended for use with the Munin_ 338 system-management tool, which typically polls target systems every 5 minutes 339 and produces a web page with graphs of various things over multiple time 340 scales (last hour, last month, last year). 335 341 336 342 Most of the plugins are designed to pull stats from a single Tahoe node, and -
TabularUnified src/allmydata/scripts/stats_gatherer.py ¶
rd1d9884 rf57d1e9 1 2 1 import os, sys 3 2 from twisted.python import usage 4 3 from allmydata.scripts.common import NoDefaultBasedirOptions 5 4 from allmydata.scripts.create_node import write_tac 6 5 from allmydata.util.assertutil import precondition 7 6 from allmydata.util.encodingutil import listdir_unicode, quote_output 7 from allmydata.util import fileutil, iputil 8 8 9 9 10 10 class CreateStatsGathererOptions(NoDefaultBasedirOptions): 11 11 subcommand_name = "create-stats-gatherer" 12 optParameters = [ 13 ("hostname", None, None, "Hostname of this machine, used to build location"), 14 ("location", None, None, "FURL connection hints, e.g. 'tcp:HOSTNAME:PORT'"), 15 ("port", None, None, "listening endpoint, e.g. 'tcp:PORT'"), 16 ] 17 def postOptions(self): 18 if self["hostname"] and (not self["location"]) and (not self["port"]): 19 pass 20 elif (not self["hostname"]) and self["location"] and self["port"]: 21 pass 22 else: 23 raise usage.UsageError("You must provide --hostname, or --location and --port.") 24 25 description = """ 26 Create a "stats-gatherer" service, which is a standalone process that 27 collects and stores runtime statistics from many server nodes. This is a 28 tool for operations personnel to keep track of free disk space, server 29 load, and protocol activity, across a fleet of Tahoe storage servers. 30 31 The "stats-gatherer" listens on a TCP port and publishes a Foolscap FURL 32 by writing it into a file named "stats_gatherer.furl". You must copy this 33 FURL into the servers' tahoe.cfg, as the [client] stats_gatherer.furl= 34 entry. Those servers will then establish a connection to the 35 stats-gatherer and publish their statistics on a periodic basis. The 36 gatherer writes a summary JSON file out to disk after each update. 37 38 The stats-gatherer listens on a configurable port, and writes a 39 configurable hostname+port pair into the FURL that it publishes. There 40 are two configuration modes you can use. 41 42 * In the first, you provide --hostname=, and the service chooses its own 43 TCP port number. If the host is named "example.org" and you provide 44 --hostname=example.org, the node will pick a port number (e.g. 12345) 45 and use location="tcp:example.org:12345" and port="tcp:12345". 46 47 * In the second, you provide both --location= and --port=, and the 48 service will refrain from doing any allocation of its own. --location= 49 must be a Foolscap "FURL connection hint sequence", which is a 50 comma-separated list of "tcp:HOSTNAME:PORTNUM" strings. --port= must be 51 a Twisted server endpoint specification, which is generally 52 "tcp:PORTNUM". So, if your host is named "example.org" and you want to 53 use port 6789, you should provide --location=tcp:example.org:6789 and 54 --port=tcp:6789. You are responsible for making sure --location= and 55 --port= match each other. 56 """ 12 57 13 58 … … 27 72 os.mkdir(basedir) 28 73 write_tac(basedir, "stats-gatherer") 74 if config["hostname"]: 75 portnum = iputil.allocate_tcp_port() 76 location = "tcp:%s:%d" % (config["hostname"], portnum) 77 port = "tcp:%d" % portnum 78 else: 79 location = config["location"] 80 port = config["port"] 81 fileutil.write(os.path.join(basedir, "location"), location+"\n") 82 fileutil.write(os.path.join(basedir, "port"), port+"\n") 29 83 return 0 30 84 -
TabularUnified src/allmydata/stats.py ¶
rd1d9884 rf57d1e9 12 12 from foolscap.api import eventually, DeadReferenceError, Referenceable, Tub 13 13 14 from allmydata.util import log , fileutil14 from allmydata.util import log 15 15 from allmydata.util.encodingutil import quote_local_unicode_path 16 16 from allmydata.interfaces import RIStatsProvider, RIStatsGatherer, IStatsProducer … … 295 295 self.stats_gatherer.setServiceParent(self) 296 296 297 portnumfile = os.path.join(self.basedir, "portnum")298 297 try: 299 portnum = open(portnumfile, "r").read() 298 with open(os.path.join(self.basedir, "location")) as f: 299 location = f.read().strip() 300 300 except EnvironmentError: 301 portnum = None 302 self.listener = self.tub.listenOn(portnum or "tcp:0") 303 d = self.tub.setLocationAutomatically() 304 if portnum is None: 305 d.addCallback(self.save_portnum) 306 d.addCallback(self.tub_ready) 307 d.addErrback(log.err) 308 309 def save_portnum(self, junk): 310 portnum = self.listener.getPortnum() 311 portnumfile = os.path.join(self.basedir, 'portnum') 312 fileutil.write(portnumfile, '%d\n' % (portnum,)) 313 314 def tub_ready(self, ignored): 301 raise ValueError("Unable to find 'location' in BASEDIR, please rebuild your stats-gatherer") 302 try: 303 with open(os.path.join(self.basedir, "port")) as f: 304 port = f.read().strip() 305 except EnvironmentError: 306 raise ValueError("Unable to find 'port' in BASEDIR, please rebuild your stats-gatherer") 307 308 self.tub.listenOn(port) 309 self.tub.setLocation(location) 315 310 ff = os.path.join(self.basedir, self.furl_file) 316 311 self.gatherer_furl = self.tub.registerReference(self.stats_gatherer, -
TabularUnified src/allmydata/test/common.py ¶
rd1d9884 rf57d1e9 495 495 statsdir = self.getdir("stats_gatherer") 496 496 fileutil.make_dirs(statsdir) 497 portnum = iputil.allocate_tcp_port() 498 location = "tcp:127.0.0.1:%d" % portnum 499 fileutil.write(os.path.join(statsdir, "location"), location) 500 port = "tcp:%d:interface=127.0.0.1" % portnum 501 fileutil.write(os.path.join(statsdir, "port"), port) 497 502 self.stats_gatherer_svc = StatsGathererService(statsdir) 498 503 self.stats_gatherer = self.stats_gatherer_svc.stats_gatherer -
TabularUnified src/allmydata/test/test_runner.py ¶
rd1d9884 rf57d1e9 185 185 return rc, out.getvalue(), err.getvalue() 186 186 187 def do_create(self, kind ):187 def do_create(self, kind, *args): 188 188 basedir = self.workdir("test_" + kind) 189 189 command = "create-" + kind … … 192 192 193 193 n1 = os.path.join(basedir, command + "-n1") 194 argv = ["--quiet", command, "--basedir", n1] 194 argv = ["--quiet", command, "--basedir", n1] + list(args) 195 195 rc, out, err = self.run_tahoe(argv) 196 196 self.failUnlessEqual(err, "") … … 227 227 # test that the non --basedir form works too 228 228 n2 = os.path.join(basedir, command + "-n2") 229 argv = ["--quiet", command ,n2]229 argv = ["--quiet", command] + list(args) + [n2] 230 230 rc, out, err = self.run_tahoe(argv) 231 231 self.failUnlessEqual(err, "") … … 237 237 # test the --node-directory form 238 238 n3 = os.path.join(basedir, command + "-n3") 239 argv = ["--quiet", "--node-directory", n3, command] 239 argv = ["--quiet", "--node-directory", n3, command] + list(args) 240 240 rc, out, err = self.run_tahoe(argv) 241 241 self.failUnlessEqual(err, "") … … 248 248 # test that the output (without --quiet) includes the base directory 249 249 n4 = os.path.join(basedir, command + "-n4") 250 argv = [command ,n4]250 argv = [command] + list(args) + [n4] 251 251 rc, out, err = self.run_tahoe(argv) 252 252 self.failUnlessEqual(err, "") … … 283 283 284 284 def test_stats_gatherer(self): 285 self.do_create("stats-gatherer" )285 self.do_create("stats-gatherer", "--hostname=127.0.0.1") 286 286 287 287 def test_subcommands(self): … … 292 292 run_by_human=False) 293 293 294 def test_stats_gatherer_good_args(self): 295 rc = runner.runner(["create-stats-gatherer", "--hostname=foo", 296 self.mktemp()]) 297 self.assertEqual(rc, 0) 298 rc = runner.runner(["create-stats-gatherer", "--location=tcp:foo:1234", 299 "--port=tcp:1234", self.mktemp()]) 300 self.assertEqual(rc, 0) 301 302 def test_stats_gatherer_bad_args(self): 303 # missing hostname/location/port 304 argv = "create-stats-gatherer D" 305 self.assertRaises(usage.UsageError, runner.runner, argv.split(), 306 run_by_human=False) 307 308 # missing port 309 argv = "create-stats-gatherer --location=foo D" 310 self.assertRaises(usage.UsageError, runner.runner, argv.split(), 311 run_by_human=False) 312 313 # missing location 314 argv = "create-stats-gatherer --port=foo D" 315 self.assertRaises(usage.UsageError, runner.runner, argv.split(), 316 run_by_human=False) 317 318 # can't provide both 319 argv = "create-stats-gatherer --hostname=foo --port=foo D" 320 self.assertRaises(usage.UsageError, runner.runner, argv.split(), 321 run_by_human=False) 322 323 # can't provide both 324 argv = "create-stats-gatherer --hostname=foo --location=foo D" 325 self.assertRaises(usage.UsageError, runner.runner, argv.split(), 326 run_by_human=False) 327 328 # can't provide all three 329 argv = "create-stats-gatherer --hostname=foo --location=foo --port=foo D" 330 self.assertRaises(usage.UsageError, runner.runner, argv.split(), 331 run_by_human=False) 294 332 295 333 class RunNode(common_util.SignalMixin, unittest.TestCase, pollmixin.PollMixin,
Note: See TracChangeset
for help on using the changeset viewer.