mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2025-02-12 22:15:30 +00:00
Use twisted.web.template in web/storage.py
Related to ticket:3247. Nevow usage has been removed, and generated page looks the same as its former self, but tests are failing because test_storage.py assumes that we're using nevow.
This commit is contained in:
parent
7a37eeee67
commit
aad3557d2b
@ -1,10 +1,10 @@
|
|||||||
|
|
||||||
import time, json
|
import time, json
|
||||||
from nevow import rend, tags as T
|
from twisted.python.filepath import FilePath
|
||||||
|
from twisted.web.template import tags as T, renderer, Element, renderElement, XMLFile
|
||||||
from allmydata.web.common import (
|
from allmydata.web.common import (
|
||||||
getxmlfile,
|
|
||||||
abbreviate_time,
|
abbreviate_time,
|
||||||
MultiFormatPage,
|
MultiFormatResource
|
||||||
)
|
)
|
||||||
from allmydata.util.abbreviate import abbreviate_space
|
from allmydata.util.abbreviate import abbreviate_space
|
||||||
from allmydata.util import time_format, idlib
|
from allmydata.util import time_format, idlib
|
||||||
@ -16,91 +16,100 @@ def remove_prefix(s, prefix):
|
|||||||
return s[len(prefix):]
|
return s[len(prefix):]
|
||||||
|
|
||||||
|
|
||||||
class StorageStatus(MultiFormatPage):
|
class StorageStatusElement(Element):
|
||||||
docFactory = getxmlfile("storage_status.xhtml")
|
loader = XMLFile(FilePath(__file__).sibling("storage_status.xhtml"))
|
||||||
# the default 'data' argument is the StorageServer instance
|
|
||||||
|
|
||||||
def __init__(self, storage, nickname=""):
|
def __init__(self, storage, nickname):
|
||||||
rend.Page.__init__(self, storage)
|
super(StorageStatusElement, self).__init__()
|
||||||
self.storage = storage
|
self.storage = storage
|
||||||
self.nickname = nickname
|
self.nick = nickname
|
||||||
|
|
||||||
def render_JSON(self, req):
|
@renderer
|
||||||
req.setHeader("content-type", "text/plain")
|
def nickname(self, req, tag):
|
||||||
d = {"stats": self.storage.get_stats(),
|
return self.nick
|
||||||
"bucket-counter": self.storage.bucket_counter.get_state(),
|
|
||||||
"lease-checker": self.storage.lease_checker.get_state(),
|
|
||||||
"lease-checker-progress": self.storage.lease_checker.get_progress(),
|
|
||||||
}
|
|
||||||
return json.dumps(d, indent=1) + "\n"
|
|
||||||
|
|
||||||
def data_nickname(self, ctx, storage):
|
@renderer
|
||||||
return self.nickname
|
def nodeid(self, req, tag):
|
||||||
def data_nodeid(self, ctx, storage):
|
|
||||||
return idlib.nodeid_b2a(self.storage.my_nodeid)
|
return idlib.nodeid_b2a(self.storage.my_nodeid)
|
||||||
|
|
||||||
def render_storage_running(self, ctx, storage):
|
def get_stat(self, key):
|
||||||
if storage:
|
return self.storage.get_stats().get(key)
|
||||||
return ctx.tag
|
|
||||||
else:
|
|
||||||
return T.h1["No Storage Server Running"]
|
|
||||||
|
|
||||||
def render_bool(self, ctx, data):
|
def str(self, tag, val):
|
||||||
return {True: "Yes", False: "No"}[bool(data)]
|
if val is None:
|
||||||
|
return tag("?")
|
||||||
|
return tag(str(val))
|
||||||
|
|
||||||
def render_abbrev_space(self, ctx, size):
|
def abbr(self, tag, val):
|
||||||
if size is None:
|
if val is None:
|
||||||
return "?"
|
return tag("?")
|
||||||
return abbreviate_space(size)
|
return tag(abbreviate_space(val))
|
||||||
|
|
||||||
def render_space(self, ctx, size):
|
@renderer
|
||||||
if size is None:
|
def disk_total(self, req, tag):
|
||||||
return "?"
|
return self.str(tag, self.get_stat("storage_server.disk_total"))
|
||||||
return "%d" % size
|
|
||||||
|
|
||||||
def data_stats(self, ctx, data):
|
@renderer
|
||||||
# FYI: 'data' appears to be self, rather than the StorageServer
|
def disk_total_abbrev(self, req, tag):
|
||||||
# object in self.original that gets passed to render_* methods. I
|
return self.abbr(tag, self.get_stat("storage_server.disk_total"))
|
||||||
# still don't understand Nevow.
|
|
||||||
|
|
||||||
# Nevow has nevow.accessors.DictionaryContainer: Any data= directive
|
@renderer
|
||||||
# that appears in a context in which the current data is a dictionary
|
def disk_used(self, req, tag):
|
||||||
# will be looked up as keys in that dictionary. So if data_stats()
|
return self.str(tag, self.get_stat("storage_server.disk_used"))
|
||||||
# returns a dictionary, then we can use something like this:
|
|
||||||
#
|
|
||||||
# <ul n:data="stats">
|
|
||||||
# <li>disk_total: <span n:render="abbrev" n:data="disk_total" /></li>
|
|
||||||
# </ul>
|
|
||||||
|
|
||||||
# to use get_stats()["storage_server.disk_total"] . However,
|
@renderer
|
||||||
# DictionaryContainer does a raw d[] instead of d.get(), so any
|
def disk_used_abbrev(self, req, tag):
|
||||||
# missing keys will cause an error, even if the renderer can tolerate
|
return self.abbr(tag, self.get_stat("storage_server.disk_used"))
|
||||||
# None values. To overcome this, we either need a dict-like object
|
|
||||||
# that always returns None for unknown keys, or we must pre-populate
|
|
||||||
# our dict with those missing keys, or we should get rid of data_
|
|
||||||
# methods that return dicts (or find some way to override Nevow's
|
|
||||||
# handling of dictionaries).
|
|
||||||
|
|
||||||
d = dict([ (remove_prefix(k, "storage_server."), v)
|
@renderer
|
||||||
for k,v in self.storage.get_stats().items() ])
|
def disk_free_for_root(self, req, tag):
|
||||||
d.setdefault("disk_total", None)
|
return self.str(tag, self.get_stat("storage_server.disk_free_for_root"))
|
||||||
d.setdefault("disk_used", None)
|
|
||||||
d.setdefault("disk_free_for_root", None)
|
|
||||||
d.setdefault("disk_free_for_nonroot", None)
|
|
||||||
d.setdefault("reserved_space", None)
|
|
||||||
d.setdefault("disk_avail", None)
|
|
||||||
return d
|
|
||||||
|
|
||||||
def data_last_complete_bucket_count(self, ctx, data):
|
@renderer
|
||||||
|
def disk_free_for_root_abbrev(self, req, tag):
|
||||||
|
return self.abbr(tag, self.get_stat("storage_server.disk_free_for_root"))
|
||||||
|
|
||||||
|
@renderer
|
||||||
|
def disk_free_for_nonroot(self, req, tag):
|
||||||
|
return self.str(tag, self.get_stat("storage_server.disk_free_for_nonroot"))
|
||||||
|
|
||||||
|
@renderer
|
||||||
|
def disk_free_for_nonroot_abbrev(self, req, tag):
|
||||||
|
return self.abbr(tag, self.get_stat("storage_server.disk_free_for_nonroot"))
|
||||||
|
|
||||||
|
@renderer
|
||||||
|
def reserved_space(self, req, tag):
|
||||||
|
return self.str(tag, self.get_stat("storage_server.reserved_space"))
|
||||||
|
|
||||||
|
@renderer
|
||||||
|
def reserved_space_abbrev(self, req, tag):
|
||||||
|
return self.abbr(tag, self.get_stat("storage_server.reserved_space"))
|
||||||
|
|
||||||
|
@renderer
|
||||||
|
def disk_avail(self, req, tag):
|
||||||
|
return self.str(tag, self.get_stat("storage_server.disk_avail"))
|
||||||
|
|
||||||
|
@renderer
|
||||||
|
def disk_avail_abbrev(self, req, tag):
|
||||||
|
return self.abbr(tag, self.get_stat("storage_server.disk_avail"))
|
||||||
|
|
||||||
|
@renderer
|
||||||
|
def accepting_immutable_shares(self, req, tag):
|
||||||
|
accepting = self.get_stat("storage_server.accepting_immutable_shares")
|
||||||
|
return {True: "Yes", False: "No"}[bool(accepting)]
|
||||||
|
|
||||||
|
@renderer
|
||||||
|
def last_complete_bucket_count(self, req, tag):
|
||||||
s = self.storage.bucket_counter.get_state()
|
s = self.storage.bucket_counter.get_state()
|
||||||
count = s.get("last-complete-bucket-count")
|
count = s.get("last-complete-bucket-count")
|
||||||
if count is None:
|
if count is None:
|
||||||
return "Not computed yet"
|
return "Not computed yet"
|
||||||
return count
|
return str(count)
|
||||||
|
|
||||||
def render_count_crawler_status(self, ctx, storage):
|
@renderer
|
||||||
|
def count_crawler_status(self, req, tag):
|
||||||
p = self.storage.bucket_counter.get_progress()
|
p = self.storage.bucket_counter.get_progress()
|
||||||
return ctx.tag[self.format_crawler_progress(p)]
|
return self.format_crawler_progress(p)
|
||||||
|
|
||||||
def format_crawler_progress(self, p):
|
def format_crawler_progress(self, p):
|
||||||
cycletime = p["estimated-time-per-cycle"]
|
cycletime = p["estimated-time-per-cycle"]
|
||||||
@ -127,55 +136,51 @@ class StorageStatus(MultiFormatPage):
|
|||||||
return ["Next crawl in %s" % abbreviate_time(soon),
|
return ["Next crawl in %s" % abbreviate_time(soon),
|
||||||
cycletime_s]
|
cycletime_s]
|
||||||
|
|
||||||
def render_lease_expiration_enabled(self, ctx, data):
|
@renderer
|
||||||
|
def storage_running(self, req, tag):
|
||||||
|
if self.storage:
|
||||||
|
return tag
|
||||||
|
return tag("No Storage Server Running")
|
||||||
|
|
||||||
|
@renderer
|
||||||
|
def lease_expiration_enabled(self, req, tag):
|
||||||
lc = self.storage.lease_checker
|
lc = self.storage.lease_checker
|
||||||
if lc.expiration_enabled:
|
if lc.expiration_enabled:
|
||||||
return ctx.tag["Enabled: expired leases will be removed"]
|
return tag("Enabled: expired leases will be removed")
|
||||||
else:
|
else:
|
||||||
return ctx.tag["Disabled: scan-only mode, no leases will be removed"]
|
return tag("Disabled: scan-only mode, no leases will be removed")
|
||||||
|
|
||||||
def render_lease_expiration_mode(self, ctx, data):
|
@renderer
|
||||||
|
def lease_expiration_mode(self, req, tag):
|
||||||
lc = self.storage.lease_checker
|
lc = self.storage.lease_checker
|
||||||
if lc.mode == "age":
|
if lc.mode == "age":
|
||||||
if lc.override_lease_duration is None:
|
if lc.override_lease_duration is None:
|
||||||
ctx.tag["Leases will expire naturally, probably 31 days after "
|
tag("Leases will expire naturally, probably 31 days after "
|
||||||
"creation or renewal."]
|
"creation or renewal.")
|
||||||
else:
|
else:
|
||||||
ctx.tag["Leases created or last renewed more than %s ago "
|
tag("Leases created or last renewed more than %s ago "
|
||||||
"will be considered expired."
|
"will be considered expired."
|
||||||
% abbreviate_time(lc.override_lease_duration)]
|
% abbreviate_time(lc.override_lease_duration))
|
||||||
else:
|
else:
|
||||||
assert lc.mode == "cutoff-date"
|
assert lc.mode == "cutoff-date"
|
||||||
localizedutcdate = time.strftime("%d-%b-%Y", time.gmtime(lc.cutoff_date))
|
localizedutcdate = time.strftime("%d-%b-%Y", time.gmtime(lc.cutoff_date))
|
||||||
isoutcdate = time_format.iso_utc_date(lc.cutoff_date)
|
isoutcdate = time_format.iso_utc_date(lc.cutoff_date)
|
||||||
ctx.tag["Leases created or last renewed before %s (%s) UTC "
|
tag("Leases created or last renewed before %s (%s) UTC "
|
||||||
"will be considered expired." % (isoutcdate, localizedutcdate, )]
|
"will be considered expired."
|
||||||
|
% (isoutcdate, localizedutcdate, ))
|
||||||
if len(lc.mode) > 2:
|
if len(lc.mode) > 2:
|
||||||
ctx.tag[" The following sharetypes will be expired: ",
|
tag(" The following sharetypes will be expired: ",
|
||||||
" ".join(sorted(lc.sharetypes_to_expire)), "."]
|
" ".join(sorted(lc.sharetypes_to_expire)), ".")
|
||||||
return ctx.tag
|
return tag
|
||||||
|
|
||||||
def format_recovered(self, sr, a):
|
@renderer
|
||||||
def maybe(d):
|
def lease_current_cycle_progress(self, req, tag):
|
||||||
if d is None:
|
|
||||||
return "?"
|
|
||||||
return "%d" % d
|
|
||||||
return "%s shares, %s buckets (%s mutable / %s immutable), %s (%s / %s)" % \
|
|
||||||
(maybe(sr["%s-shares" % a]),
|
|
||||||
maybe(sr["%s-buckets" % a]),
|
|
||||||
maybe(sr["%s-buckets-mutable" % a]),
|
|
||||||
maybe(sr["%s-buckets-immutable" % a]),
|
|
||||||
abbreviate_space(sr["%s-diskbytes" % a]),
|
|
||||||
abbreviate_space(sr["%s-diskbytes-mutable" % a]),
|
|
||||||
abbreviate_space(sr["%s-diskbytes-immutable" % a]),
|
|
||||||
)
|
|
||||||
|
|
||||||
def render_lease_current_cycle_progress(self, ctx, data):
|
|
||||||
lc = self.storage.lease_checker
|
lc = self.storage.lease_checker
|
||||||
p = lc.get_progress()
|
p = lc.get_progress()
|
||||||
return ctx.tag[self.format_crawler_progress(p)]
|
return tag(self.format_crawler_progress(p))
|
||||||
|
|
||||||
def render_lease_current_cycle_results(self, ctx, data):
|
@renderer
|
||||||
|
def lease_current_cycle_results(self, req, tag):
|
||||||
lc = self.storage.lease_checker
|
lc = self.storage.lease_checker
|
||||||
p = lc.get_progress()
|
p = lc.get_progress()
|
||||||
if not p["cycle-in-progress"]:
|
if not p["cycle-in-progress"]:
|
||||||
@ -229,10 +234,10 @@ class StorageStatus(MultiFormatPage):
|
|||||||
T.ul[ [T.li[ ["SI %s shnum %d" % corrupt_share
|
T.ul[ [T.li[ ["SI %s shnum %d" % corrupt_share
|
||||||
for corrupt_share in so_far["corrupt-shares"] ]
|
for corrupt_share in so_far["corrupt-shares"] ]
|
||||||
]]])
|
]]])
|
||||||
|
return tag("Current cycle:", p)
|
||||||
|
|
||||||
return ctx.tag["Current cycle:", p]
|
@renderer
|
||||||
|
def lease_last_cycle_results(self, req, tag):
|
||||||
def render_lease_last_cycle_results(self, ctx, data):
|
|
||||||
lc = self.storage.lease_checker
|
lc = self.storage.lease_checker
|
||||||
h = lc.get_state()["history"]
|
h = lc.get_state()["history"]
|
||||||
if not h:
|
if not h:
|
||||||
@ -240,15 +245,15 @@ class StorageStatus(MultiFormatPage):
|
|||||||
last = h[max(h.keys())]
|
last = h[max(h.keys())]
|
||||||
|
|
||||||
start, end = last["cycle-start-finish-times"]
|
start, end = last["cycle-start-finish-times"]
|
||||||
ctx.tag["Last complete cycle (which took %s and finished %s ago)"
|
tag("Last complete cycle (which took %s and finished %s ago)"
|
||||||
" recovered: " % (abbreviate_time(end-start),
|
" recovered: " % (abbreviate_time(end-start),
|
||||||
abbreviate_time(time.time() - end)),
|
abbreviate_time(time.time() - end)),
|
||||||
self.format_recovered(last["space-recovered"], "actual")
|
self.format_recovered(last["space-recovered"], "actual"))
|
||||||
]
|
|
||||||
|
|
||||||
p = T.ul()
|
p = T.ul()
|
||||||
|
|
||||||
def add(*pieces):
|
def add(*pieces):
|
||||||
p[T.li[pieces]]
|
p(T.li(pieces))
|
||||||
|
|
||||||
saw = self.format_recovered(last["space-recovered"], "examined")
|
saw = self.format_recovered(last["space-recovered"], "examined")
|
||||||
add("and saw a total of ", saw)
|
add("and saw a total of ", saw)
|
||||||
@ -264,4 +269,37 @@ class StorageStatus(MultiFormatPage):
|
|||||||
for corrupt_share in last["corrupt-shares"] ]
|
for corrupt_share in last["corrupt-shares"] ]
|
||||||
]]])
|
]]])
|
||||||
|
|
||||||
return ctx.tag[p]
|
return tag(p)
|
||||||
|
|
||||||
|
def format_recovered(self, sr, a):
|
||||||
|
def maybe(d):
|
||||||
|
if d is None:
|
||||||
|
return "?"
|
||||||
|
return "%d" % d
|
||||||
|
return "%s shares, %s buckets (%s mutable / %s immutable), %s (%s / %s)" % \
|
||||||
|
(maybe(sr["%s-shares" % a]),
|
||||||
|
maybe(sr["%s-buckets" % a]),
|
||||||
|
maybe(sr["%s-buckets-mutable" % a]),
|
||||||
|
maybe(sr["%s-buckets-immutable" % a]),
|
||||||
|
abbreviate_space(sr["%s-diskbytes" % a]),
|
||||||
|
abbreviate_space(sr["%s-diskbytes-mutable" % a]),
|
||||||
|
abbreviate_space(sr["%s-diskbytes-immutable" % a]),
|
||||||
|
)
|
||||||
|
|
||||||
|
class StorageStatus(MultiFormatResource):
|
||||||
|
def __init__(self, storage, nickname=""):
|
||||||
|
super(StorageStatus, self).__init__()
|
||||||
|
self.storage = storage
|
||||||
|
self.nickname = nickname
|
||||||
|
|
||||||
|
def render_HTML(self, req):
|
||||||
|
return renderElement(req, StorageStatusElement(self.storage, self.nickname))
|
||||||
|
|
||||||
|
def render_JSON(self, req):
|
||||||
|
req.setHeader("content-type", "text/plain")
|
||||||
|
d = {"stats": self.storage.get_stats(),
|
||||||
|
"bucket-counter": self.storage.bucket_counter.get_state(),
|
||||||
|
"lease-checker": self.storage.lease_checker.get_state(),
|
||||||
|
"lease-checker-progress": self.storage.lease_checker.get_progress(),
|
||||||
|
}
|
||||||
|
return json.dumps(d, indent=1) + "\n"
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<html xmlns:n="http://nevow.com/ns/nevow/0.1">
|
<html xmlns:t="http://twistedmatrix.com/ns/twisted.web.template/0.1">
|
||||||
<head>
|
<head>
|
||||||
<title>Tahoe-LAFS - Storage Server Status</title>
|
<title>Tahoe-LAFS - Storage Server Status</title>
|
||||||
<link href="/tahoe.css" rel="stylesheet" type="text/css"/>
|
<link href="/tahoe.css" rel="stylesheet" type="text/css"/>
|
||||||
@ -7,19 +7,19 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div n:render="storage_running">
|
<div t:render="storage_running">
|
||||||
|
|
||||||
<h1>Storage Server Status</h1>
|
<h1>Storage Server Status</h1>
|
||||||
|
|
||||||
<table n:data="stats">
|
<table class="storage_status">
|
||||||
<tr><td>Total disk space:</td>
|
<tr><td>Total disk space:</td>
|
||||||
<td><span n:render="abbrev_space" n:data="disk_total" /></td>
|
<td><span t:render="disk_total_abbrev" /></td>
|
||||||
<td>(<span n:render="space" n:data="disk_total" />)</td>
|
<td>(<span t:render="disk_total" />)</td>
|
||||||
<td />
|
<td />
|
||||||
</tr>
|
</tr>
|
||||||
<tr><td>Disk space used:</td>
|
<tr><td>Disk space used:</td>
|
||||||
<td>- <span n:render="abbrev_space" n:data="disk_used" /></td>
|
<td>- <span t:render="disk_used_abbrev" /></td>
|
||||||
<td>(<span n:render="space" n:data="disk_used" />)</td>
|
<td>(<span t:render="disk_used" />)</td>
|
||||||
<td />
|
<td />
|
||||||
</tr>
|
</tr>
|
||||||
<tr><td />
|
<tr><td />
|
||||||
@ -28,18 +28,18 @@
|
|||||||
<td />
|
<td />
|
||||||
</tr>
|
</tr>
|
||||||
<tr><td>Disk space free (root):</td>
|
<tr><td>Disk space free (root):</td>
|
||||||
<td><span n:render="abbrev_space" n:data="disk_free_for_root"/></td>
|
<td><span t:render="disk_free_for_root_abbrev"/></td>
|
||||||
<td>(<span n:render="space" n:data="disk_free_for_root"/>)</td>
|
<td>(<span t:render="disk_free_for_root"/>)</td>
|
||||||
<td>[see 1]</td>
|
<td>[see 1]</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr><td>Disk space free (non-root):</td>
|
<tr><td>Disk space free (non-root):</td>
|
||||||
<td><span n:render="abbrev_space" n:data="disk_free_for_nonroot" /></td>
|
<td><span t:render="disk_free_for_nonroot_abbrev" /></td>
|
||||||
<td>(<span n:render="space" n:data="disk_free_for_nonroot" />)</td>
|
<td>(<span t:render="disk_free_for_nonroot" />)</td>
|
||||||
<td>[see 2]</td>
|
<td>[see 2]</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr><td>Reserved space:</td>
|
<tr><td>Reserved space:</td>
|
||||||
<td>- <span n:render="abbrev_space" n:data="reserved_space" /></td>
|
<td>- <span t:render="reserved_space_abbrev" /></td>
|
||||||
<td>(<span n:render="space" n:data="reserved_space" />)</td>
|
<td>(<span t:render="reserved_space" />)</td>
|
||||||
<td />
|
<td />
|
||||||
</tr>
|
</tr>
|
||||||
<tr><td />
|
<tr><td />
|
||||||
@ -48,23 +48,31 @@
|
|||||||
<td />
|
<td />
|
||||||
</tr>
|
</tr>
|
||||||
<tr><td>Space Available to Tahoe:</td>
|
<tr><td>Space Available to Tahoe:</td>
|
||||||
<td><span n:render="abbrev_space" n:data="disk_avail" /></td>
|
<td><span t:render="disk_avail_abbrev" /></td>
|
||||||
<td>(<span n:render="space" n:data="disk_avail" />)</td>
|
<td>(<span t:render="disk_avail" />)</td>
|
||||||
<td />
|
<td />
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>Server Nickname: <span class="nickname mine" n:render="data" n:data="nickname" /></li>
|
<li>Server Nickname:
|
||||||
<li>Server Nodeid: <span class="nodeid mine data-chars" n:render="string" n:data="nodeid" /></li>
|
<span class="nickname mine">
|
||||||
<li n:data="stats">Accepting new shares:
|
<span t:render="nickname" />
|
||||||
<span n:render="bool" n:data="accepting_immutable_shares" /></li>
|
</span>
|
||||||
|
</li>
|
||||||
|
<li>Server Nodeid:
|
||||||
|
<span class="nodeid mine data-chars">
|
||||||
|
<span t:render="nodeid" />
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li t:data="stats">Accepting new shares:
|
||||||
|
<span t:render="accepting_immutable_shares" /></li>
|
||||||
<li>Total buckets:
|
<li>Total buckets:
|
||||||
<span n:render="string" n:data="last_complete_bucket_count" />
|
<span t:render="last_complete_bucket_count" />
|
||||||
(the number of files and directories for which this server is holding
|
(the number of files and directories for which this server is holding
|
||||||
a share)
|
a share)
|
||||||
<ul>
|
<ul>
|
||||||
<li n:render="count_crawler_status" />
|
<li><span t:render="count_crawler_status" /></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -72,11 +80,11 @@
|
|||||||
<h2>Lease Expiration Crawler</h2>
|
<h2>Lease Expiration Crawler</h2>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>Expiration <span n:render="lease_expiration_enabled" /></li>
|
<li>Expiration <span t:render="lease_expiration_enabled" /></li>
|
||||||
<li n:render="lease_expiration_mode" />
|
<li t:render="lease_expiration_mode" />
|
||||||
<li n:render="lease_current_cycle_progress" />
|
<li t:render="lease_current_cycle_progress" />
|
||||||
<li n:render="lease_current_cycle_results" />
|
<li t:render="lease_current_cycle_results" />
|
||||||
<li n:render="lease_last_cycle_results" />
|
<li t:render="lease_last_cycle_results" />
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
Loading…
x
Reference in New Issue
Block a user