From: Brian Warner Date: Wed, 15 Feb 2012 18:24:42 +0000 (+0000) Subject: make provisioning/reliability work in the new location, fix tests X-Git-Url: https://git.rkrishnan.org/components/com_hotproperty/frontends/FTP-and-SFTP.txt?a=commitdiff_plain;h=fe1df149e1b05308860e3c3fff7ecf2e7a626172;p=tahoe-lafs%2Ftahoe-lafs.git make provisioning/reliability work in the new location, fix tests --- diff --git a/Makefile b/Makefile index 38bb6479..4bf09d39 100644 --- a/Makefile +++ b/Makefile @@ -199,6 +199,10 @@ check-grid: .built bench-dirnode: .built $(TAHOE) @src/allmydata/test/bench_dirnode.py +# the provisioning tool runs as a stand-alone webapp server +run-provisioning-tool: .built + $(TAHOE) @misc/operations_helpers/provisioning/run.py + # 'make repl' is a simple-to-type command to get a Python interpreter loop # from which you can type 'import allmydata' repl: diff --git a/misc/operations_helpers/provisioning/provisioning.py b/misc/operations_helpers/provisioning/provisioning.py index 9d9af0ea..37acd16d 100644 --- a/misc/operations_helpers/provisioning/provisioning.py +++ b/misc/operations_helpers/provisioning/provisioning.py @@ -1,12 +1,17 @@ -from nevow import inevow, rend, tags as T +from nevow import inevow, rend, loaders, tags as T import math -from allmydata.util import mathutil -from allmydata.web.common import getxmlfile +import util # factorial and binomial copied from # http://mail.python.org/pipermail/python-list/2007-April/435718.html +def div_ceil(n, d): + """ + The smallest integer k such that k*d >= n. + """ + return (n/d) + (n%d != 0) + def factorial(n): """factorial(n): return the factorial of the integer n. factorial(0) = 1 @@ -35,7 +40,7 @@ def binomial(n, k): class ProvisioningTool(rend.Page): addSlash = True - docFactory = getxmlfile("provisioning.xhtml") + docFactory = loaders.xmlfile(util.sibling("provisioning.xhtml")) def render_forms(self, ctx, data): req = inevow.IRequest(ctx) @@ -566,12 +571,12 @@ class ProvisioningTool(rend.Page): number(total_file_check_rate, "Hz")]) - total_drives = max(mathutil.div_ceil(int(total_share_space), - int(drive_size)), + total_drives = max(div_ceil(int(total_share_space), + int(drive_size)), num_servers) add_output("Drives", T.div["Total drives: ", number(total_drives), " drives"]) - drives_per_server = mathutil.div_ceil(total_drives, num_servers) + drives_per_server = div_ceil(total_drives, num_servers) add_output("Servers", T.div["Drives per server: ", drives_per_server]) @@ -606,8 +611,7 @@ class ProvisioningTool(rend.Page): # $44/server/mo power+space server_bandwidth = max(server_inbound_byte_rate, server_outbound_byte_rate) - server_bandwidth_mbps = mathutil.div_ceil(int(server_bandwidth*8), - int(1e6)) + server_bandwidth_mbps = div_ceil(int(server_bandwidth*8), int(1e6)) server_monthly_cost = 70*server_bandwidth_mbps + 44 add_output("Servers", T.div["Monthly cost per server: $", server_monthly_cost]) diff --git a/misc/operations_helpers/provisioning/run.py b/misc/operations_helpers/provisioning/run.py new file mode 100644 index 00000000..d81f771a --- /dev/null +++ b/misc/operations_helpers/provisioning/run.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +# this depends upon Twisted and Nevow, but not upon Tahoe itself + +import webbrowser + +from twisted.application import strports +from twisted.internet import reactor +from nevow import appserver, rend, loaders +from twisted.web import static +import web_reliability, provisioning + +class Root(rend.Page): + docFactory = loaders.xmlstr('''\ + + + Tahoe-LAFS Provisioning/Reliability Calculator + + + +

Reliability Tool

+

Provisioning Tool

+ + +''') + + child_reliability = web_reliability.ReliabilityTool() + child_provisioning = provisioning.ProvisioningTool() + + +def run(portnum): + root = Root() + root.putChild("tahoe.css", static.File("tahoe.css")) + site = appserver.NevowSite(root) + s = strports.service("tcp:%d" % portnum, site) + s.startService() + reactor.callLater(1.0, webbrowser.open, "http://localhost:%d/" % portnum) + reactor.run() + +if __name__ == '__main__': + import sys + portnum = 8070 + if len(sys.argv) > 1: + portnum = int(sys.argv[1]) + run(portnum) diff --git a/misc/operations_helpers/provisioning/tahoe.css b/misc/operations_helpers/provisioning/tahoe.css new file mode 100644 index 00000000..e834ecc7 --- /dev/null +++ b/misc/operations_helpers/provisioning/tahoe.css @@ -0,0 +1,163 @@ + +pre.overflow { + background: #f7f7f7; + border: 1px solid #d7d7d7; + margin: 1em 1.75em; + padding: .25em; + overflow: auto; + } + +/* ----------------------------------------------------------------------- */ + +/* colors borrowed from the Allmydata logo */ + +/* general style */ +h1 { + text-align: center; +} +table { + margin: 1em auto; + border: .2em solid #3289b4; + border-spacing: 1px; +} +th { + color: white; + background-color: #58a1c3; +} +td { + padding: .3em .3em; +} + +th { + padding: .3em .3em; +} + +.table-headings-top th { + text-align: center; + +} +.table-headings-left th { + text-align: right; + vertical-align: top; +} +legend { + font-weight: bold; +} + +.connected-yes, .connected-True { + border: 1px solid #75d24a; + background-color: #EFE; +} +.connected-no, .connected-False { + border: 1px solid #F00; + background-color: #FBB; +} + +.encoded, .nodeid { + font-family: monospace; + font-size: 80%; +} + +.empty-marker { + background-color: white; + color: gray; +} +table td.empty-marker { + padding: 6em 10em; + text-align: center; + vertical-align: center; +} + +/* styles for server listings in tables (nickname above nodeid) */ +th.nickname-and-peerid { + text-align: left; +} +.nickname { + font: inherit; + font-family: sans-serif; + font-weight: bold; +} + + +/* just in case, make sure floats don't stomp on big tables etc. */ +#section { clear: both; } + +/* section-specific styles - turn this client info into a sidebar */ +#this-client { + font-size: 60%; + border: .2em solid #3289b4; + float: right; + width: 40%; + margin: 0 0 .5em .5em; + padding: 3px; +} +#this-client .nodeid { font-size: inherit; } +#this-client h2 { + text-align: center; + background: #3289b4; + color: white; + margin: -2px -2px 0 -2px; /* matches padding */ + padding: .3em; +} +#this-client table { + font-size: inherit; + margin: 0 -3px -3px -3px; /* matches padding */ +} +#this-client td > ul { + list-style-type: outside; + margin: 0 0 0 2.3em; + padding-left: 0; +} + + +/* services table */ +.services { +} + +/* --- Directory page styles --- */ + +body.tahoe-directory-page { + color: black; + background: #c0d9e6; + margin: 1em 0; /* zero margin so the table can be flush */ +} +table.tahoe-directory { + color: black; + background: white; + width: 100%; + /*border-left-color: #D7E0E5; + border-right-color: #D7E0E5;*/ + border-left: 0; + border-right: 0; +} +.tahoe-directory-footer { + color: black; + background: #c0d9e6; + margin: 0 1em; /* compensate for page 0 margin */ +} + +/* directory-screen toolbar */ +.toolbar { + display: table; + margin: .2em auto; + text-align: center; + /*width: 100%;*/ +} +.toolbar .toolbar-item { + display: inline; + text-align: center; + padding: 0 1em; +} + +/* recent upload/download status pages */ + +table.status-download-events { + #border: 1px solid #aaa; + margin: 1em auto; + border: .2em solid #3289b4; + border-spacing: 1px; +} +table.status-download-events td { + border: 1px solid #a00; + padding: 2px +} diff --git a/misc/operations_helpers/provisioning/test_provisioning.py b/misc/operations_helpers/provisioning/test_provisioning.py index 71bc6570..d2b9dbd1 100644 --- a/misc/operations_helpers/provisioning/test_provisioning.py +++ b/misc/operations_helpers/provisioning/test_provisioning.py @@ -1,5 +1,5 @@ -from twisted.trial import unittest +import unittest from allmydata import provisioning ReliabilityModel = None try: @@ -111,3 +111,5 @@ class Reliability(unittest.TestCase): self.failUnlessAlmostEqual(P_dead_unmaintained, 0.033591004555395272) self.failUnlessAlmostEqual(P_dead_maintained, 3.2983995819177542e-08) +if __name__=='__main__': + unittest.main() diff --git a/misc/operations_helpers/provisioning/util.py b/misc/operations_helpers/provisioning/util.py new file mode 100644 index 00000000..db28915c --- /dev/null +++ b/misc/operations_helpers/provisioning/util.py @@ -0,0 +1,5 @@ + +import os.path + +def sibling(filename): + return os.path.join(os.path.dirname(os.path.abspath(__file__)), filename) diff --git a/misc/operations_helpers/provisioning/web_reliability.py b/misc/operations_helpers/provisioning/web_reliability.py index d5d34061..149079e9 100644 --- a/misc/operations_helpers/provisioning/web_reliability.py +++ b/misc/operations_helpers/provisioning/web_reliability.py @@ -1,11 +1,27 @@ -from nevow import rend, tags as T -reliability = None # might not be usable -try: - from allmydata import reliability # requires NumPy -except ImportError: - pass -from allmydata.web.common import getxmlfile, get_arg +from nevow import rend, loaders, tags as T +from nevow.inevow import IRequest +import reliability # requires NumPy +import util + +def get_arg(ctx_or_req, argname, default=None, multiple=False): + """Extract an argument from either the query args (req.args) or the form + body fields (req.fields). If multiple=False, this returns a single value + (or the default, which defaults to None), and the query args take + precedence. If multiple=True, this returns a tuple of arguments (possibly + empty), starting with all those in the query args. + """ + req = IRequest(ctx_or_req) + results = [] + if argname in req.args: + results.extend(req.args[argname]) + if req.fields and argname in req.fields: + results.append(req.fields[argname].value) + if multiple: + return tuple(results) + if results: + return results[0] + return default DAY=24*60*60 @@ -22,7 +38,7 @@ def yandm(seconds): class ReliabilityTool(rend.Page): addSlash = True - docFactory = getxmlfile("reliability.xhtml") + docFactory = loaders.xmlfile(util.sibling("reliability.xhtml")) DEFAULT_PARAMETERS = [ ("drive_lifetime", "8Y", "time",