[CalendarServer-changes] [574]
CalendarServer/branches/caladmin-tool/caladmin
source_changes at macosforge.org
source_changes at macosforge.org
Wed Nov 22 16:03:33 PST 2006
Revision: 574
http://trac.macosforge.org/projects/calendarserver/changeset/574
Author: dreid at apple.com
Date: 2006-11-22 16:03:32 -0800 (Wed, 22 Nov 2006)
Log Message:
-----------
better, more flexible reporting, removal of quotas subcommand quota information is now conveyed in the principal subcommands (users, resources, groups)
Modified Paths:
--------------
CalendarServer/branches/caladmin-tool/caladmin/formatters.py
CalendarServer/branches/caladmin-tool/caladmin/options.py
CalendarServer/branches/caladmin-tool/caladmin/principals.py
CalendarServer/branches/caladmin-tool/caladmin/script.py
CalendarServer/branches/caladmin-tool/caladmin/stats.py
CalendarServer/branches/caladmin-tool/caladmin/util.py
Removed Paths:
-------------
CalendarServer/branches/caladmin-tool/caladmin/quotas.py
Modified: CalendarServer/branches/caladmin-tool/caladmin/formatters.py
===================================================================
--- CalendarServer/branches/caladmin-tool/caladmin/formatters.py 2006-11-22 23:50:23 UTC (rev 573)
+++ CalendarServer/branches/caladmin-tool/caladmin/formatters.py 2006-11-23 00:03:32 UTC (rev 574)
@@ -20,8 +20,8 @@
FORMATTERS = {}
-def registerFormatter(short, formatter):
- FORMATTERS[short] = formatter
+def registerFormatter(formatter):
+ FORMATTERS[formatter.name] = formatter
def listFormatters():
return FORMATTERS.keys()
@@ -31,32 +31,119 @@
class BaseFormatter(object):
- def __init__(self, dst=None):
- self.dst = dst
+ config = None
+
+ def __init__(self, dest=None, options=None):
+ self.dest = dest
- if not self.dst:
- self.dst = sys.stdout
+ if not self.dest:
+ self.dest = sys.stdout
+ self.options = options
+ if not options:
+ self.options = {}
+
+ self.reportTypes = []
+
+ for attr in self.__dict__:
+ if attr.startswith('report_'):
+ self.reportTypes.append(attr.split('_', 1)[1])
+
+ def write(self, data):
+ self.dest.write(data)
+ self.dest.flush()
+
+ def close(self):
+ self.dest.close()
+
+ def printReport(self, report):
+ reportPrinter = getattr(self, 'report_%s' % (report['type'],), None)
+
+ if reportPrinter:
+ reportPrinter(report)
+
+ else:
+ self.report_default(report)
+
+ def report_default(self, report):
+ import pprint
+
+ preport = pprint.pformat(report)
+
+ self.write(''.join([preport, '\n']))
+ self.close()
+
+
class PlainFormatter(BaseFormatter):
- def printRow(self, row, spacelen):
- for el in row:
- self.dst.write(str(el))
- self.dst.write(' '*(spacelen - len(str(el))))
-
- self.dst.write('\n')
+ name = "plain"
-registerFormatter('plain', PlainFormatter)
+registerFormatter(PlainFormatter)
+import csv
+
class CsvFormatter(BaseFormatter):
- def printRow(self, row, spacelen):
- for el in row:
- self.dst.write(str(el))
- self.dst.write(',')
+ name = "csv"
+
+ def writeList(self, fieldnames, l):
+ dw = csv.DictWriter(self.dest,
+ **self.options)
+
+ dw.writerow(dict(zip(fieldnames,
+ fieldnames)))
+
+ dw.writerows(l)
+
+ def report_principals(self, report):
+ if 'fieldnames' not in self.options:
+ self.options['fieldnames'] = [
+ 'principalName',
+ 'calendarHome',
+ 'calendarCount',
+ 'eventCount',
+ 'todoCount',
+ 'disabled',
+ 'diskUsage',
+ 'quotaRoot',
+ 'quotaUsed',
+ 'quotaAvail',
+ 'quotaFree']
+
+ self.writeDict(self.options['fieldnames'],
+ report['records'])
- self.dst.write('\n')
+ report_users = report_groups = report_resources = report_principals
-registerFormatter('csv', CsvFormatter)
+ def report_stats(self, report):
+ if 'fieldnames' not in self.options:
+ self.options['fieldnames'] = report['data'].keys()
+ self.options['fieldnames'].sort()
+ self.writeList(self.options['fieldnames'],
+ [report['data']])
+
+
+registerFormatter(CsvFormatter)
+import plistlib
+
+class PlistFormatter(BaseFormatter):
+ name = "plist"
+
+ def report_principals(self, report):
+ plist = plistlib.Dict()
+
+ plist[report['type']] = list(report['records'])
+
+ plistlib.writePlist(plist, self.dest)
+
+ report_users = report_groups = report_resources = report_principals
+
+ def report_stats(self, report):
+ plist = plistlib.Dict()
+ plist[report['type']] = report['data']
+
+ plistlib.writePlist(plist, self.dest)
+
+registerFormatter(PlistFormatter)
Modified: CalendarServer/branches/caladmin-tool/caladmin/options.py
===================================================================
--- CalendarServer/branches/caladmin-tool/caladmin/options.py 2006-11-22 23:50:23 UTC (rev 573)
+++ CalendarServer/branches/caladmin-tool/caladmin/options.py 2006-11-23 00:03:32 UTC (rev 574)
@@ -52,7 +52,10 @@
self.params += rest
def postOptions(self):
- reflect.namedAny(self.action)(self).run()
+
+ report = reflect.namedAny(self.action)(self).run()
+ self.parent.formatter.config = self
+ self.parent.formatter.printReport(report)
PARAM_HUMAN = ['human', 'h', 'Display byte values in a human readable form.']
@@ -61,48 +64,6 @@
PARAM_GIGA = ['gigabytes', 'g', 'Display byte values in gigabytes']
-class QuotaOptions(SubCommand):
- name = 'quotas'
- help = 'Retrieve quota information for principals'
- action = 'caladmin.quotas.QuotaAction'
-
- optFlags = [
- PARAM_HUMAN,
- PARAM_KILO,
- PARAM_MEGA,
- PARAM_GIGA,
- ]
-
- def __init__(self):
- SubCommand.__init__(self)
-
- self['types'] = []
-
- def opt_users(self):
- """Show Quotas for user calendars.
- """
-
- self['types'].append('users')
- opt_u = opt_users
-
- def opt_groups(self):
- """Show Quotas for group calendars.
- """
-
- self['types'].append('groups')
- opt_g = opt_groups
-
- def opt_resources(self):
- """Show Quotas for resource calendars.
- """
-
- self['types'].append('resources')
- opt_r = opt_resources
-
-
-registerCommand(QuotaOptions)
-
-
class PurgeOptions(SubCommand):
name = 'purge'
help = ('Keep your store from becoming unnecessarily large by purging '
@@ -130,6 +91,7 @@
registerCommand(StatsOptions)
+
from twisted.python import filepath
from twistedcaldav.caldavd import caldavd_defaults
@@ -192,7 +154,8 @@
]
def postOptions(self):
- reflect.namedAny(self.action)(self, self.name).run()
+ report = reflect.namedAny(self.action)(self, self.name).run()
+ self.parent.formatter.printReport(report)
class UserOptions(PrincipalOptions):
Modified: CalendarServer/branches/caladmin-tool/caladmin/principals.py
===================================================================
--- CalendarServer/branches/caladmin-tool/caladmin/principals.py 2006-11-22 23:50:23 UTC (rev 573)
+++ CalendarServer/branches/caladmin-tool/caladmin/principals.py 2006-11-23 00:03:32 UTC (rev 574)
@@ -34,16 +34,18 @@
self.root = self.config.parent.root
self.calendarCollection = self.config.parent.calendarCollection
self.principalCollection = self.config.parent.principalCollection
-
+
def run(self):
+ report = {'type': self.type,
+ 'records': []}
+
if not self.config.params:
- principals = util.getPrincipalList(self.principalCollection,
- self.type,
+ principals = util.getPrincipalList(self.principalCollection,
+ self.type,
disabled=self.config['disabled'])
else:
principals = []
-
for p in self.config.params:
p = self.principalCollection.child(self.type).child(p)
@@ -51,27 +53,37 @@
if self.config['disabled']:
if util.isPrincipalDisabled(p):
principals.append(p)
+
else:
principals.append(p)
- if not self.config['list']:
- self.formatter.printRow(['Name', 'Calendars', 'Events', 'Todos',
- 'Disk Usage'], 16)
+ def _getRecords():
+ for p in principals:
+ precord = {}
+
+ pcal = self.calendarCollection.child(
+ self.type
+ ).child(p.basename())
+
+ precord['principalName'] = p.basename()
+
+ precord['calendarHome'] = pcal.path
- for p in principals:
- pcal = self.calendarCollection.child(self.type).child(p.basename())
- row = []
+ precord.update(
+ util.getQuotaStatsForPrincipal(
+ self.config,
+ pcal,
+ self.config.parent.config['UserQuotaBytes']))
- row.append(p.basename())
+ precord.update(
+ util.getCalendarDataCounts(pcal))
- if not self.config['list']:
+ precord['diskUsage'] = util.getDiskUsage(self.config, pcal)
- row.extend(util.getCalendarDataCounts(pcal))
+ precord['disabled'] = util.isPrincipalDisabled(p)
- row.append(util.prepareByteValue(self.config,
- util.getDiskUsage(pcal)))
-
- self.formatter.printRow(row, 16)
+ yield precord
-
-
+ report['records'] = _getRecords()
+
+ return report
Deleted: CalendarServer/branches/caladmin-tool/caladmin/quotas.py
===================================================================
--- CalendarServer/branches/caladmin-tool/caladmin/quotas.py 2006-11-22 23:50:23 UTC (rev 573)
+++ CalendarServer/branches/caladmin-tool/caladmin/quotas.py 2006-11-23 00:03:32 UTC (rev 574)
@@ -1,114 +0,0 @@
-##
-# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# DRI: David Reid, dreid at apple.com
-##
-
-import xattr
-
-from twisted.web2.dav.resource import TwistedQuotaRootProperty, TwistedQuotaUsedProperty
-from twisted.web import microdom
-
-from caladmin.util import prepareByteValue
-
-quotaRoot = "WebDAV:" + TwistedQuotaRootProperty.sname().replace("/", "%2F")
-quotaUsed = "WebDAV:" + TwistedQuotaUsedProperty.sname().replace("/", "%2F")
-
-def getQuotaRoot(fp):
- x = xattr.xattr(fp.path)
- if not x.has_key(quotaRoot):
- return None
-
- dom = microdom.parseString(x[quotaRoot])
-
- qr = microdom.getElementsByTagName(dom, 'quota-root')[0]
-
- return int(qr.firstChild().value)
-
-
-def getQuotaUsed(fp):
- x = xattr.xattr(fp.path)
- if not x.has_key(quotaUsed):
- return None
-
- dom = microdom.parseString(x[quotaUsed])
-
- qu = microdom.getElementsByTagName(dom, 'quota-used')[0]
-
- return int(qu.firstChild().value)
-
-
-class QuotaAction(object):
- def __init__(self, config):
- self.config = config
- self.userQuotaBytes = config.parent.config['UserQuotaBytes']
- self.calendarCollection = config.parent.calendarCollection
- self.principalCollection = config.parent.principalCollection
- self.formatter = config.parent.formatter
-
- def getQuotaStats(self):
-
- defaultQuota = getQuotaRoot(self.calendarCollection)
- if not defaultQuota:
- defaultQuota = self.userQuotaBytes
-
- for type in self.config['types']:
-
- typeRoot = self.calendarCollection.child(type)
-
- typePrincipals = self.principalCollection.child(type)
-
- if not typeRoot.exists() or not typePrincipals.exists():
- continue
-
- typeQuota = getQuotaRoot(typeRoot)
- if not typeQuota:
- typeQuota = defaultQuota
-
- for child in typePrincipals.listdir():
- if child in ['.db.sqlite']:
- continue
-
- child = typeRoot.child(child)
-
- childQuota = getQuotaRoot(child)
- if not childQuota:
- childQuota = typeQuota
-
- childUsed = getQuotaUsed(child)
- if not childUsed:
- childUsed = 0
-
- childAvailable = childQuota - childUsed
-
- yield (child.basename(),
- type,
- prepareByteValue(self.config, childQuota),
- prepareByteValue(self.config, childUsed),
- prepareByteValue(self.config, childAvailable))
-
- def run(self):
- if not self.config['types']:
- self.config['types'] = ['users', 'groups', 'resources']
-
- self.formatter.printRow(['Name',
- 'Type',
- 'Quota',
- 'Used',
- 'Available'],
- 16)
-
- for x in self.getQuotaStats():
- self.formatter.printRow(x, 16)
Modified: CalendarServer/branches/caladmin-tool/caladmin/script.py
===================================================================
--- CalendarServer/branches/caladmin-tool/caladmin/script.py 2006-11-22 23:50:23 UTC (rev 573)
+++ CalendarServer/branches/caladmin-tool/caladmin/script.py 2006-11-23 00:03:32 UTC (rev 574)
@@ -54,7 +54,18 @@
usage.Options.__init__(self)
self.config = None
+ self.format_options = {}
+ def opt_option(self, option):
+ if '=' in option:
+ k,v = option.split('=', 1)
+
+ self.format_options[k] = v
+ else:
+ self.format_options[option] = True
+
+ opt_o = opt_option
+
def parseArgs(self, *rest):
self.params += rest
@@ -91,7 +102,8 @@
lf.sort()
if self['format'] in lf:
- self.formatter = formatters.getFormatter(self['format'])()
+ self.formatter = formatters.getFormatter(self['format'])
+ self.formatter = self.formatter(options=self.format_options)
else:
raise usage.UsageError("Please specify a valid formatter: %s" % (
', '.join(lf)))
Modified: CalendarServer/branches/caladmin-tool/caladmin/stats.py
===================================================================
--- CalendarServer/branches/caladmin-tool/caladmin/stats.py 2006-11-22 23:50:23 UTC (rev 573)
+++ CalendarServer/branches/caladmin-tool/caladmin/stats.py 2006-11-23 00:03:32 UTC (rev 574)
@@ -51,59 +51,43 @@
self.getAccountCount,
self.getGroupCount,
self.getResourceCount,
- self.getCalendarCount,
- self.getEventCount,
- self.getTodoCount,
self.getDiskUsage]
def getDiskUsage(self):
- return ("Disk Usage",
- util.prepareByteValue(self.config,
- util.getDiskUsage(self.root)))
+ return ("diskUsage",
+ util.getDiskUsage(self.config, self.root))
def getAccountCount(self):
- return ("# Accounts",
+ return ("accountCount",
len(util.getPrincipalList(
self.principalCollection,
'users')))
def getGroupCount(self):
- return ("# Groups",
+ return ("groupCount",
len(util.getPrincipalList(
self.principalCollection,
'groups')))
def getResourceCount(self):
- return ("# Resources",
+ return ("resourceCount",
len(util.getPrincipalList(
self.principalCollection,
'resources')))
- def getEventCount(self):
- return ("# Events", self.eventCount)
-
- def getTodoCount(self):
- return ("# Todos", self.todoCount)
-
- def getCalendarCount(self):
- return ("# Calendars", self.calCount)
-
- def printStatistics(self, head, stats):
- self.formatter.printRow([head], 16)
-
- for stat in stats:
- self.formatter.printRow(stat, 16)
-
def run(self):
assert self.root.exists()
stats = []
- (self.calCount,
- self.eventCount,
- self.todoCount) = util.getCalendarDataCounts(self.calendarCollection)
+ report = {'type': 'stats',
+ 'data': {}}
+ report['data'].update(
+ util.getCalendarDataCounts(
+ self.calendarCollection))
+
for gatherer in self.gatherers:
- stats.append(gatherer())
+ stat, value = gatherer()
+ report['data'][stat] = value
- self.printStatistics("Overall Statistics", stats)
-
+ return report
Modified: CalendarServer/branches/caladmin-tool/caladmin/util.py
===================================================================
--- CalendarServer/branches/caladmin-tool/caladmin/util.py 2006-11-22 23:50:23 UTC (rev 573)
+++ CalendarServer/branches/caladmin-tool/caladmin/util.py 2006-11-23 00:03:32 UTC (rev 574)
@@ -76,15 +76,14 @@
return pl
-def getDiskUsage(fp):
-
+def getDiskUsage(config, fp):
status, output = commands.getstatusoutput(
' '.join(['/usr/bin/du', '-s', fp.path]))
if status != 0:
return 0
- return int(output.split()[0])
+ return prepareByteValue(config, int(output.split()[0]))
def getResourceType(fp):
@@ -132,8 +131,65 @@
elif component.resourceType() == 'VTODO':
todoCount += 1
- return (calCount, eventCount, todoCount)
+ return {'calendarCount': calCount,
+ 'eventCount': eventCount,
+ 'todoCount': todoCount}
def isPrincipalDisabled(principal):
return False
+
+
+from twisted.web2.dav.resource import TwistedQuotaRootProperty, TwistedQuotaUsedProperty
+
+quotaRoot = "WebDAV:" + TwistedQuotaRootProperty.sname().replace("/", "%2F")
+quotaUsed = "WebDAV:" + TwistedQuotaUsedProperty.sname().replace("/", "%2F")
+
+def getQuotaRoot(fp):
+ x = xattr.xattr(fp.path)
+ if not x.has_key(quotaRoot):
+ return None
+
+ dom = microdom.parseString(x[quotaRoot])
+
+ qr = microdom.getElementsByTagName(dom, 'quota-root')[0]
+
+ return int(qr.firstChild().value)
+
+
+def getQuotaUsed(fp):
+ x = xattr.xattr(fp.path)
+ if not x.has_key(quotaUsed):
+ return None
+
+ dom = microdom.parseString(x[quotaUsed])
+
+ qu = microdom.getElementsByTagName(dom, 'quota-used')[0]
+
+ return int(qu.firstChild().value)
+
+
+def getQuotaStatsForPrincipal(config, principal, defaultQuota=None, depth=2):
+ quotaRoot = principal
+
+ principalQuota = getQuotaRoot(quotaRoot)
+
+ while not principalQuota and depth > 0:
+ depth -= 1
+ quotaRoot = quotaRoot.parent()
+ principalQuota = getQuotaRoot(quotaRoot)
+
+ if not principalQuota:
+ principalQuota = defaultQuota
+
+ principalUsed = getQuotaUsed(principal)
+ if not principalUsed:
+ principalUsed = 0
+
+ principalAvail = principalQuota - principalUsed
+ principalFree = (float(principalAvail)/principalQuota)*100
+
+ return {'quotaRoot': prepareByteValue(config, principalQuota),
+ 'quotaUsed': prepareByteValue(config, principalUsed),
+ 'quotaAvail': prepareByteValue(config, principalAvail),
+ 'quotaFree': principalFree}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20061122/ea657dca/attachment.html
More information about the calendarserver-changes
mailing list