/usr/share/pyshared/landscape/user/changes.py is in landscape-common 12.04.3-0ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | from landscape.diff import diff
class UserChanges(object):
"""Detect changes made since the last snapshot was taken.
If no snapshot is available all users and groups are reported.
When a snapshot is available, only the changes between the current
state and the snapshotted state are transmitted to the server.
"""
def __init__(self, persist, provider):
super(UserChanges, self).__init__()
self._persist = persist
self._provider = provider
# FIXME This shouldn't really be necessary. Not having it
# here with the current factoring is also problematic. Figure
# out a clean way to factor this. Gustavo suggested splitting
# it into _build_old_data and _build_new_data and just calling
# that from the necessary places.
self._refresh()
def _refresh(self):
"""Load the previous snapshot and update current data."""
self._old_users = self._persist.get("users", {})
self._old_groups = self._persist.get("groups", {})
self._new_users = self._create_index(
"username", self._provider.get_users())
self._new_groups = self._create_index(
"name", self._provider.get_groups())
def snapshot(self):
"""Save the current state and use it as a comparison snapshot."""
self._persist.set("users", self._new_users)
self._persist.set("groups", self._new_groups)
def clear(self):
"""
Reset the snapshot state and forget all knowledge of users and
groups.
"""
self._persist.remove("users")
self._persist.remove("groups")
def _create_index(self, key, sequence):
"""
Given a key and a sequence of dicts, return a dict of the form
C{{dict[key]: dict, ...}}.
"""
index = {}
for data in sequence:
index[data[key]] = data
return index
def create_diff(self):
"""Returns the changes since the last snapshot.
See landscape.message_schemas.USERS schema for a description of the
dictionary returned by this method.
"""
self._refresh()
changes = {}
changes.update(self._detect_user_changes())
changes.update(self._detect_group_changes())
return changes
def _detect_user_changes(self):
"""
Compare the current user snapshot to the old one and return a
C{dict} with C{create-users}, C{update-users} and
C{delete-users} fields. Fields without data aren't included
in the result.
"""
changes = {}
creates, updates, deletes = diff(self._old_users, self._new_users)
if creates:
changes["create-users"] = list(creates.itervalues())
if updates:
changes["update-users"] = list(updates.itervalues())
if deletes:
changes["delete-users"] = list(deletes.iterkeys())
return changes
def _detect_group_changes(self):
"""
Compare the current group snapshot to the old one and create a
C{dict} with C{create-groups}, C{delete-groups},
C{create-group-members} and {delete-group-members} fields.
Fields without data aren't included in the result.
"""
changes = {}
creates, updates, deletes = diff(self._old_groups, self._new_groups)
if creates:
groups = []
create_members = {}
for value in creates.itervalues():
# Use a copy to avoid removing the 'members' element
# from stored data.
value = value.copy()
members = value.pop("members")
if members:
create_members[value["name"]] = members
groups.append(value)
changes["create-groups"] = groups
if create_members:
changes["create-group-members"] = create_members
if updates:
remove_members = {}
create_members = {}
update_groups = []
for groupname, new_data in updates.iteritems():
old_data = self._old_groups[groupname]
old_members = set(old_data["members"])
new_members = set(new_data["members"])
created = new_members - old_members
if created:
create_members[groupname] = sorted(created)
removed = old_members - new_members
if removed:
remove_members[groupname] = sorted(removed)
if old_data["gid"] != new_data["gid"]:
update_groups.append({"name": groupname,
"gid": new_data["gid"]})
if create_members:
members = changes.setdefault("create-group-members", {})
members.update(create_members)
if remove_members:
members = changes.setdefault("delete-group-members", {})
members.update(remove_members)
if update_groups:
members = changes.setdefault("update-groups", [])
members.extend(update_groups)
if deletes:
changes["delete-groups"] = deletes.keys()
return changes
|