Skip to content

Commit a9559aa

Browse files
committed
copy osg-comanage-project-usermap.py -> group_fixup.py (SOFTWARE-5057)
separate copy commit to show changes later
1 parent b575ea5 commit a9559aa

File tree

1 file changed

+227
-0
lines changed

1 file changed

+227
-0
lines changed

group_fixup.py

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
#!/usr/bin/env python3
2+
3+
import os
4+
import sys
5+
import json
6+
import getopt
7+
import collections
8+
import urllib.error
9+
import urllib.request
10+
11+
12+
SCRIPT = os.path.basename(__file__)
13+
ENDPOINT = "https://registry-test.cilogon.org/registry/"
14+
OSG_CO_ID = 8
15+
16+
17+
_usage = f"""\
18+
usage: [PASS=...] {SCRIPT} [OPTIONS]
19+
20+
OPTIONS:
21+
-u USER[:PASS] specify USER and optionally PASS on command line
22+
-c OSG_CO_ID specify OSG CO ID (default = {OSG_CO_ID})
23+
-d passfd specify open fd to read PASS
24+
-f passfile specify path to file to open and read PASS
25+
-e ENDPOINT specify REST endpoint
26+
(default = {ENDPOINT})
27+
-o outfile specify output file (default: write to stdout)
28+
-h display this help text
29+
30+
PASS for USER is taken from the first of:
31+
1. -u USER:PASS
32+
2. -d passfd (read from fd)
33+
3. -f passfile (read from file)
34+
4. read from $PASS env var
35+
"""
36+
37+
def usage(msg=None):
38+
if msg:
39+
print(msg + "\n", file=sys.stderr)
40+
41+
print(_usage, file=sys.stderr)
42+
sys.exit()
43+
44+
45+
class Options:
46+
endpoint = ENDPOINT
47+
user = "co_8.project_script"
48+
osg_co_id = OSG_CO_ID
49+
outfile = None
50+
authstr = None
51+
52+
53+
options = Options()
54+
55+
56+
def getpw(user, passfd, passfile):
57+
if ':' in user:
58+
user, pw = user.split(':', 1)
59+
elif passfd is not None:
60+
pw = os.fdopen(passfd).readline().rstrip('\n')
61+
elif passfile is not None:
62+
pw = open(passfile).readline().rstrip('\n')
63+
elif 'PASS' in os.environ:
64+
pw = os.environ['PASS']
65+
else:
66+
usage("PASS required")
67+
return user, pw
68+
69+
70+
def mkauthstr(user, passwd):
71+
from base64 import encodebytes
72+
raw_authstr = '%s:%s' % (user, passwd)
73+
return encodebytes(raw_authstr.encode()).decode().replace('\n', '')
74+
75+
76+
def mkrequest(target, **kw):
77+
url = os.path.join(options.endpoint, target)
78+
if kw:
79+
url += "?" + "&".join( "{}={}".format(k,v) for k,v in kw.items() )
80+
req = urllib.request.Request(url)
81+
req.add_header("Authorization", "Basic %s" % options.authstr)
82+
req.get_method = lambda: 'GET'
83+
return req
84+
85+
86+
def call_api(target, **kw):
87+
req = mkrequest(target, **kw)
88+
resp = urllib.request.urlopen(req)
89+
payload = resp.read()
90+
return json.loads(payload) if payload else None
91+
92+
93+
def get_osg_co_groups():
94+
return call_api("co_groups.json", coid=options.osg_co_id)
95+
96+
97+
# primary api calls
98+
99+
def get_co_group_identifiers(gid):
100+
return call_api("identifiers.json", cogroupid=gid)
101+
102+
103+
def get_co_group_members(gid):
104+
return call_api("co_group_members.json", cogroupid=gid)
105+
106+
107+
def get_co_person_identifiers(pid):
108+
return call_api("identifiers.json", copersonid=pid)
109+
110+
111+
# @rorable
112+
# def foo(x): ...
113+
# x | foo -> foo(x)
114+
class rorable:
115+
def __init__(self, f): self.f = f
116+
def __call__(self, *a, **kw): return self.f(*a, **kw)
117+
def __ror__ (self, x): return self.f(x)
118+
119+
120+
def get_datalist(listname):
121+
def get(data):
122+
return data[listname] if data else []
123+
return rorable(get)
124+
125+
126+
# api call results massagers
127+
128+
def get_osg_co_groups__map():
129+
#print("get_osg_co_groups__map()")
130+
data = get_osg_co_groups() | get_datalist("CoGroups")
131+
return { g["Id"]: g["Name"] for g in data }
132+
133+
134+
def co_group_is_ospool(gid):
135+
#print(f"co_group_is_ospool({gid})")
136+
data = get_co_group_identifiers(gid) | get_datalist("Identifiers")
137+
return any( i["Type"] == "ospoolproject" for i in data )
138+
139+
140+
def get_co_group_members__pids(gid):
141+
#print(f"get_co_group_members__pids({gid})")
142+
data = get_co_group_members(gid) | get_datalist("CoGroupMembers")
143+
return [ m["Person"]["Id"] for m in data ]
144+
145+
146+
def get_co_person_osguser(pid):
147+
#print(f"get_co_person_osguser({pid})")
148+
data = get_co_person_identifiers(pid) | get_datalist("Identifiers")
149+
typemap = { i["Type"]: i["Identifier"] for i in data }
150+
return typemap.get("osguser")
151+
152+
153+
def parse_options(args):
154+
try:
155+
ops, args = getopt.getopt(args, 'u:c:d:f:e:o:h')
156+
except getopt.GetoptError:
157+
usage()
158+
159+
if args:
160+
usage("Extra arguments: %s" % repr(args))
161+
162+
passfd = None
163+
passfile = None
164+
165+
for op, arg in ops:
166+
if op == '-h': usage()
167+
if op == '-u': options.user = arg
168+
if op == '-c': options.osg_co_id = int(arg)
169+
if op == '-d': passfd = int(arg)
170+
if op == '-f': passfile = arg
171+
if op == '-e': options.endpoint = arg
172+
if op == '-o': options.outfile = arg
173+
174+
user, passwd = getpw(options.user, passfd, passfile)
175+
options.authstr = mkauthstr(user, passwd)
176+
177+
178+
def gid_pids_to_osguser_pid_gids(gid_pids, pid_osguser):
179+
pid_gids = collections.defaultdict(set)
180+
181+
for gid in gid_pids:
182+
for pid in gid_pids[gid]:
183+
if pid_osguser[pid] is not None:
184+
pid_gids[pid].add(gid)
185+
186+
return pid_gids
187+
188+
189+
def get_osguser_groups():
190+
groups = get_osg_co_groups__map()
191+
ospool_gids = filter(co_group_is_ospool, groups)
192+
gid_pids = { gid: get_co_group_members__pids(gid) for gid in ospool_gids }
193+
all_pids = set( pid for gid in gid_pids for pid in gid_pids[gid] )
194+
pid_osguser = { pid: get_co_person_osguser(pid) for pid in all_pids }
195+
pid_gids = gid_pids_to_osguser_pid_gids(gid_pids, pid_osguser)
196+
197+
return { pid_osguser[pid]: sorted(map(groups.get, gids))
198+
for pid, gids in pid_gids.items() }
199+
200+
201+
def print_usermap_to_file(osguser_groups, file):
202+
for osguser, groups in sorted(osguser_groups.items()):
203+
print("* {} {}".format(osguser, ",".join(groups)), file=file)
204+
205+
206+
def print_usermap(osguser_groups):
207+
if options.outfile:
208+
with open(options.outfile, "w") as w:
209+
print_usermap_to_file(osguser_groups, w)
210+
else:
211+
print_usermap_to_file(osguser_groups, sys.stdout)
212+
213+
214+
def main(args):
215+
parse_options(args)
216+
217+
osguser_groups = get_osguser_groups()
218+
print_usermap(osguser_groups)
219+
220+
221+
if __name__ == "__main__":
222+
try:
223+
main(sys.argv[1:])
224+
except urllib.error.HTTPError as e:
225+
print(e, file=sys.stderr)
226+
sys.exit(1)
227+

0 commit comments

Comments
 (0)