classify-users: determine type of Athena accounts
[user/alex/software/my-snippets.git] / compute-list-closure
1 #!/usr/bin/python
2
3 import moira
4 import sys
5 import Queue
6
7 def lenient_query(*query):
8     try:
9         results = moira.query(*query)
10     except moira.MoiraException as e:
11         msg = e[1]
12         if msg == 'No records in database match query':
13             results = []
14         else:
15             raise
16     return results
17     
18
19 def expand_closure(lst, owns=True, members=True, member_of=True, recursive=True, ):
20     closure = set()
21     include_type = 'list'
22     if recursive: include_type = 'rlist'
23     if owns:
24         results = lenient_query('get_ace_use', include_type, lst)
25         for result in results:
26             if result['use_type'] == 'LIST':
27                 closure.add(result['use_name'])
28
29     if members:
30         results = lenient_query('get_members_of_list', lst)
31         for result in results:
32             if result['member_type'] == 'LIST':
33                 closure.add(result['member_name'])
34
35     if member_of:
36         results = lenient_query('get_lists_of_member', include_type, lst)
37         for result in results:
38             closure.add(result['list_name'])
39
40     return closure
41
42 def get_exclusions(lst):
43     exclusions = set()
44     results = lenient_query('get_members_of_list', lst)
45     for result in results:
46         if result['member_type'] == 'LIST':
47             exclusions.add(result['member_name'])
48     return exclusions
49
50 def compute_closure(lists, exclude):
51     closure = set()
52     parent = {}
53
54     the_queue = Queue.Queue()
55     for lst in lists:
56         the_queue.put(lst)
57     for lst in lists:
58         parent[lst] = None
59
60     while not the_queue.empty():
61         lst = the_queue.get()
62         if lst in closure:
63             print "skipping %s" % (lst, )
64             continue
65         closure.add(lst)
66         try:
67             new_lists = expand_closure(lst, member_of=False, recursive=False, )
68         except moira.MoiraException as e:
69             msg = e[1]
70             if msg == 'Insufficient permission to perform requested database access':
71                 new_lists = []
72                 print >>sys.stderr, "List %s (parent %s) appears to be hidden; ignoring. (Queue length: %d; closure length: %d)" % (lst, parent[lst], the_queue.qsize(), len(closure), )
73             else:
74                 raise
75         for new_list in new_lists:
76             if new_list in closure:
77                 pass
78             elif new_list in exclude:
79                 print "Excluding %s (parent %s)" % (new_list, lst)
80             else:
81                 the_queue.put(new_list)
82                 parent[new_list] = lst
83                 print "%s (from %s)" % (new_list, lst)
84     return closure
85
86 if __name__ == '__main__':
87     moira.connect()
88     moira.auth('awdflu') # client name is awdflu --- Alex Dehnert file-lists-updater
89     starter_list = sys.argv[1]
90     exclude_list = sys.argv[2]
91     exclude = get_exclusions(exclude_list)
92     closure = compute_closure([starter_list], exclude)
93     moira.disconnect()
94     print "\n\n\n"
95     for lst in closure:
96         print lst
97     print
98     print "Count:", len(closure)