~ahasenack/landscape-client/landscape-client-11.02-0ubuntu0.8.04.1

« back to all changes in this revision

Viewing changes to landscape/user/changes.py

  • Committer: Andreas Hasenack
  • Date: 2011-05-05 14:12:15 UTC
  • Revision ID: andreas@canonical.com-20110505141215-5ymuyyh5es9pwa6p
Added hardy files.

Show diffs side-by-side

added added

removed removed

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