# HG changeset patch # User Paul Boddie # Date 1455026500 -3600 # Node ID 861e86e687afb591ed2dbe1ea4d37572be155cef # Parent bb1b8e13ef4dfe075199bf69181da1e0f2e4a5fc Changed the recording of reservations for quotas to use free/busy records. diff -r bb1b8e13ef4d -r 861e86e687af docs/wiki/FilesystemUsage --- a/docs/wiki/FilesystemUsage Tue Feb 09 14:17:52 2016 +0100 +++ b/docs/wiki/FilesystemUsage Tue Feb 09 15:01:40 2016 +0100 @@ -53,9 +53,10 @@ .. of a quota across a number of users == `journal` -|| A directory containing transaction files, one per user or user group, -.. describing confirmed reservations and retracted (cancelled) reservations for -.. that user or group +|| A directory containing consolidated schedules, one per user or user group, +.. describing reservations for resources sharing a quota made by the indicated +.. user or group, structured similarly to the `freebusy` file found in each +.. resource's own store {{{ journal/GROUP journal/USER diff -r bb1b8e13ef4d -r 861e86e687af imip_store.py --- a/imip_store.py Tue Feb 09 14:17:52 2016 +0100 +++ b/imip_store.py Tue Feb 09 15:01:40 2016 +0100 @@ -1013,9 +1013,9 @@ filename = self.get_object_in_store(quota, "freebusy", user) if not filename or not isfile(filename): return [] - else: - return map(lambda t: FreeBusyPeriod(*t), - (get_table or self._get_table_atomic)(quota, filename, [(4, None)])) + + return map(lambda t: FreeBusyPeriod(*t), + (get_table or self._get_table_atomic)(quota, filename, [(4, None)])) def set_freebusy(self, quota, user, freebusy, set_table=None): @@ -1042,7 +1042,8 @@ if not filename or not isfile(filename): return [] - return self._get_table_atomic(quota, filename, [(1, None), (3, None)]) + return map(lambda t: FreeBusyPeriod(*t), + self._get_table_atomic(quota, filename, [(4, None)])) def set_entries(self, quota, group, entries): @@ -1055,7 +1056,8 @@ if not filename: return False - self._set_table_atomic(quota, filename, entries, [(1, ""), (3, "")]) + self._set_table_atomic(quota, filename, + map(lambda fb: fb.as_tuple(strings_only=True), entries)) return True # vim: tabstop=4 expandtab shiftwidth=4 diff -r bb1b8e13ef4d -r 861e86e687af imiptools/handlers/scheduling/quota.py --- a/imiptools/handlers/scheduling/quota.py Tue Feb 09 14:17:52 2016 +0100 +++ b/imiptools/handlers/scheduling/quota.py Tue Feb 09 15:01:40 2016 +0100 @@ -19,8 +19,7 @@ this program. If not, see . """ -from imiptools.dates import format_datetime, format_duration, get_datetime, \ - get_duration, to_utc_datetime +from imiptools.dates import get_duration, to_utc_datetime from imiptools.data import get_uri from imiptools.period import Endless from datetime import timedelta @@ -80,13 +79,12 @@ if total == Endless() or not expiry: return - # Obtain the journal entries and limits. + # Update the journal entries. journal = handler.get_journal() entries = journal.get_entries(quota, group) - - if _add_to_entries(entries, handler.uid, handler.recurrenceid, format_duration(total), format_datetime(expiry)): - journal.set_entries(quota, group, entries) + handler.update_freebusy(entries, group, False) + journal.set_entries(quota, group, entries) def remove_from_quota(handler, args): @@ -104,13 +102,12 @@ if total == Endless(): total = None - # Obtain the journal entries and limits. + # Update the journal entries. journal = handler.get_journal() entries = journal.get_entries(quota, group) - - if _remove_from_entries(entries, handler.uid, handler.recurrenceid, format_duration(total)): - journal.set_entries(quota, group, entries) + handler.remove_from_freebusy(entries) + journal.set_entries(quota, group, entries) def _get_quota_and_group(handler, args): @@ -178,73 +175,10 @@ "Return the usage total according to the given 'entries'." total = timedelta(0) - - for found_uid, found_recurrenceid, found_duration, found_expiry in entries: - retraction = found_duration.startswith("-") - multiplier = retraction and -1 or 1 - total += multiplier * get_duration(found_duration[retraction and 1 or 0:]) - + for period in entries: + total += period.get_duration() return total -def _add_to_entries(entries, uid, recurrenceid, duration, expiry): - - """ - Add to 'entries' an entry for the event having the given 'uid' and - 'recurrenceid' with the given 'duration' and 'expiry' time. - """ - - confirmed = _find_applicable_entry(entries, uid, recurrenceid) - - # Where a previous entry still applies, retract it if different. - - if confirmed: - found_uid, found_recurrenceid, found_duration, found_expiry = confirmed - if found_duration != duration: - entries.append((found_uid, found_recurrenceid, "-%s" % found_duration, found_expiry)) - else: - return False - - # Without an applicable previous entry, add a new entry. - - entries.append((uid, recurrenceid, duration, expiry)) - return True - -def _remove_from_entries(entries, uid, recurrenceid, duration): - - """ - Remove from the given 'entries' any entry for the event having the given - 'uid' and 'recurrenceid' with the given 'duration'. - """ - - confirmed = _find_applicable_entry(entries, uid, recurrenceid) - - # Where a previous entry still applies, retract it. - - if confirmed: - found_uid, found_recurrenceid, found_duration, found_expiry = confirmed - entries.append((found_uid, found_recurrenceid, "-%s" % found_duration, found_expiry)) - return True - - return False - -def _find_applicable_entry(entries, uid, recurrenceid): - - """ - Within 'entries', find any applicable previous entry for this event, - using the 'uid' and 'recurrenceid'. - """ - - confirmed = None - - for found_uid, found_recurrenceid, found_duration, found_expiry in entries: - if uid == found_uid and recurrenceid == found_recurrenceid: - if found_duration.startswith("-"): - confirmed = None - else: - confirmed = found_uid, found_recurrenceid, found_duration, found_expiry - - return confirmed - # Collective free/busy maintenance. def schedule_across_quota(handler, args): diff -r bb1b8e13ef4d -r 861e86e687af tests/test_resource_invitation_constraints_quota.sh --- a/tests/test_resource_invitation_constraints_quota.sh Tue Feb 09 14:17:52 2016 +0100 +++ b/tests/test_resource_invitation_constraints_quota.sh Tue Feb 09 15:01:40 2016 +0100 @@ -167,7 +167,7 @@ # Check the quota (event is retracted). [ -e "$JOURNALFILE" ] \ -&& [ `grep "event21@example.com" "$JOURNALFILE" | wc -l` = '2' ] \ +&& ! grep -q "event21@example.com" "$JOURNALFILE" \ && grep -q "event22@example.com" "$JOURNALFILE" \ && echo "Success" \ || echo "Failed" @@ -206,8 +206,8 @@ # Check the quota (event is still confirmed). [ -e "$JOURNALFILE" ] \ -&& [ `grep "event21@example.com" "$JOURNALFILE" | wc -l` = '2' ] \ -&& [ `grep "event22@example.com" "$JOURNALFILE" | wc -l` = '1' ] \ +&& ! grep -q "event21@example.com" "$JOURNALFILE" \ +&& grep -q "event22@example.com" "$JOURNALFILE" \ && echo "Success" \ || echo "Failed" @@ -238,8 +238,8 @@ # Check the quota (event is still retracted and not newly confirmed). [ -e "$JOURNALFILE" ] \ -&& [ `grep "event21@example.com" "$JOURNALFILE" | wc -l` = '2' ] \ -&& [ `grep "event22@example.com" "$JOURNALFILE" | wc -l` = '1' ] \ +&& ! grep -q "event21@example.com" "$JOURNALFILE" \ +&& grep -q "event22@example.com" "$JOURNALFILE" \ && echo "Success" \ || echo "Failed" @@ -271,8 +271,8 @@ # Check the quota (event is newly confirmed). [ -e "$JOURNALFILE" ] \ -&& [ `grep "event21@example.com" "$JOURNALFILE" | wc -l` = '3' ] \ -&& [ `grep "event22@example.com" "$JOURNALFILE" | wc -l` = '1' ] \ +&& grep -q "event21@example.com" "$JOURNALFILE" \ +&& grep -q "event22@example.com" "$JOURNALFILE" \ && echo "Success" \ || echo "Failed" diff -r bb1b8e13ef4d -r 861e86e687af tests/test_resource_invitation_constraints_quota_recurring_limits.sh --- a/tests/test_resource_invitation_constraints_quota_recurring_limits.sh Tue Feb 09 14:17:52 2016 +0100 +++ b/tests/test_resource_invitation_constraints_quota_recurring_limits.sh Tue Feb 09 15:01:40 2016 +0100 @@ -172,7 +172,7 @@ # Check the quota (event is retracted). ! [ -e "$JOURNALFILE1" ] \ -|| [ `grep "event25@example.com" "$JOURNALFILE1" | wc -l` = '2' ] \ +|| ! grep -q "event25@example.com" "$JOURNALFILE1" \ && echo "Success" \ || echo "Failed" @@ -223,6 +223,6 @@ # Check the quota (event is confirmed for both resources). [ -e "$JOURNALFILE2" ] \ -&& [ `grep "event25@example.com" "$JOURNALFILE2" | wc -l` = '1' ] \ +&& grep -q "event25@example.com" "$JOURNALFILE2" \ && echo "Success" \ || echo "Failed" diff -r bb1b8e13ef4d -r 861e86e687af tools/update_quotas.py --- a/tools/update_quotas.py Tue Feb 09 14:17:52 2016 +0100 +++ b/tools/update_quotas.py Tue Feb 09 15:01:40 2016 +0100 @@ -41,14 +41,13 @@ "Remove from 'entries' events that end at or before 'expiry'." removed = [] + i = 0 - i = 0 while i < len(entries): - uid, recurrenceid, duration, found_expiry = entry = entries[i] - found_expiry = get_datetime(found_expiry) + period = entries[i] - if found_expiry <= expiry: - removed.append(entry) + if period.get_end_point() <= expiry: + removed.append(period) del entries[i] else: i += 1 @@ -87,8 +86,8 @@ removed = remove_expired_entries(entries, expiry) if verbose: - for entry in removed: - print >>stderr, "Removed", entry + for period in removed: + print >>stderr, "\t".join(("Removed",) + period.as_tuple(strings_only=True)) # Store the processed entries. @@ -98,8 +97,8 @@ # Alternatively, just write the entries to standard output. else: - for entry in entries: - print >>stdout, "\t".join([(s or "") for s in entry]) + for period in entries: + print >>stdout, "\t".join(period.as_tuple(strings_only=True)) finally: journal.release_lock(quota)