44import re
55import sys
66import json
7+ #import ldap3
78import getopt
89import urllib .error
910import urllib .request
1011
1112SCRIPT = os .path .basename (__file__ )
1213ENDPOINT = "https://registry-test.cilogon.org/registry/"
1314OSG_CO_ID = 8
14- CLUSTER_ID = 10
15+ UNIX_CLUSTER_ID = 10
1516LDAP_TARGET_ID = 9
1617MINTIMEOUT = 5
1718MAXTIMEOUT = 625
3233OPTIONS:
3334 -u USER[:PASS] specify USER and optionally PASS on command line
3435 -c OSG_CO_ID specify OSG CO ID (default = { OSG_CO_ID } )
35- -g CLUSTER_ID specify UNIX Cluster ID (default = { CLUSTER_ID } )
36+ -g CLUSTER_ID specify UNIX Cluster ID (default = { UNIX_CLUSTER_ID } )
3637 -l LDAP_TARGET specify LDAP Provsion ID (defult = { LDAP_TARGET_ID } )
3738 -d passfd specify open fd to read PASS
3839 -f passfile specify path to file to open and read PASS
@@ -63,7 +64,7 @@ class Options:
6364 endpoint = ENDPOINT
6465 user = "co_8.william_test"
6566 osg_co_id = OSG_CO_ID
66- unix_id = CLUSTER_ID
67+ ucid = UNIX_CLUSTER_ID
6768 provision_target = LDAP_TARGET_ID
6869 outfile = None
6970 authstr = None
@@ -129,7 +130,7 @@ def call_api3(method, target, data, **kw):
129130 currentTimeout *= TIMEOUTMULTIPLE
130131 else :
131132 sys .exit (
132- f"Exception raised after maximum timeout { options .max_timeout } seconds reached. "
133+ f"Exception raised after maximum retrys and timeout { options .max_timeout } seconds reached. "
133134 + f"Exception reason: { exception .reason } .\n Request: { req .full_url } "
134135 )
135136
@@ -155,29 +156,39 @@ def get_co_person_identifiers(pid):
155156 return call_api ("identifiers.json" , copersonid = pid )
156157
157158
159+ def get_unix_cluster_groups (ucid ):
160+ return call_api ("unix_cluster/unix_cluster_groups.json" , unix_cluster_id = ucid )
161+
162+
163+ def get_unix_cluster_groups_ids (ucid ):
164+ unix_cluster_groups = get_unix_cluster_groups (ucid )
165+ return set (group ["CoGroupId" ] for group in unix_cluster_groups ["UnixClusterGroups" ])
166+
167+
158168def get_datalist (data , listname ):
159169 return data [listname ] if data else []
160170
161171
162- def identifier_index (id_list , id_type ):
172+ def identifier_from_list (id_list , id_type ):
163173 id_type_list = [id ["Type" ] for id in id_list ]
164174 try :
165- return id_type_list .index (id_type )
175+ id_index = id_type_list .index (id_type )
176+ return id_list [id_index ]["Identifier" ]
166177 except ValueError :
167- return - 1
178+ return None
168179
169180
170181def identifier_matches (id_list , id_type , regex_string ):
171182 pattern = re .compile (regex_string )
172- index = identifier_index (id_list , id_type )
173- return (index != - 1 ) & (pattern .match (id_list [ index ][ "Identifier" ] ) is not None )
183+ value = identifier_from_list (id_list , id_type )
184+ return (value is not None ) & (pattern .match (value ) is not None )
174185
175186
176- def add_identifier_to_group (gid , type , identifier_name ):
187+ def add_identifier_to_group (gid , type , identifier_value ):
177188 new_identifier_info = {
178189 "Version" : "1.0" ,
179190 "Type" : type ,
180- "Identifier" : identifier_name ,
191+ "Identifier" : identifier_value ,
181192 "Login" : False ,
182193 "Person" : {"Type" : "Group" , "Id" : str (gid )},
183194 "Status" : "Active" ,
@@ -187,7 +198,20 @@ def add_identifier_to_group(gid, type, identifier_name):
187198 "Version" : "1.0" ,
188199 "Identifiers" : [new_identifier_info ],
189200 }
190- return call_api3 (POST , "identifiers.json" , data )
201+ call_api3 (POST , "identifiers.json" , data )
202+
203+
204+ def add_unix_cluster_group (gid ):
205+ request = {
206+ "RequestType" : "UnixClusterGroups" ,
207+ "Version" : "1.0" ,
208+ "UnixClusterGroups" : [{"Version" : "1.0" , "UnixClusterId" : options .ucid , "CoGroupId" : gid }],
209+ }
210+ call_api3 (POST , "unix_cluster/unix_cluster_groups.json" , request )
211+
212+
213+ def ldap_provision_group (gid ):
214+ call_api2 (POST , f"co_provisioning_targets/provision/{ options .provision_target } /cogroupid:{ gid } .json" )
191215
192216
193217def parse_options (args ):
@@ -210,7 +234,7 @@ def parse_options(args):
210234 if op == "-c" :
211235 options .osg_co_id = int (arg )
212236 if op == "-g" :
213- options .unix_id = int (arg )
237+ options .ucid = int (arg )
214238 if op == "-l" :
215239 options .provision_target = int (arg )
216240 if op == "-d" :
@@ -230,78 +254,119 @@ def parse_options(args):
230254 options .authstr = mkauthstr (user , passwd )
231255
232256
257+ def append_if_project (project_groups , group ):
258+ # If this group has a ospoolproject id, and it starts with "Yes-", it's a project
259+ if identifier_matches (group ["ID_List" ], "ospoolproject" , (OSPOOL_PROJECT_PREFIX_STR + "*" )):
260+ # Add a dict of the relavent data for this project to the project_groups list
261+ project_groups .append (group )
262+
263+
264+ def update_highest_osggid (highest_osggid , group ):
265+ # Get the value of the osggid identifier, if this group has one
266+ osggid = identifier_from_list (group ["ID_List" ], "osggid" )
267+ # If this group has a osggid, keep a hold of the highest one we've seen so far
268+ if osggid is not None :
269+ return max (highest_osggid , int (osggid ))
270+
271+
272+ def get_comanage_data ():
273+ comanage_data = {"Projects" : [], "highest_osggid" : 0 }
274+
275+ co_groups = get_osg_co_groups ()["CoGroups" ]
276+ for group_data in co_groups :
277+ try :
278+ identifier_list = get_co_group_identifiers (group_data ["Id" ])["Identifiers" ]
279+ # Store this groups data in a dictionary to avoid repeated API calls
280+ group = {"Gid" : group_data ["Id" ], "Name" : group_data ["Name" ], "ID_List" : identifier_list }
281+
282+ append_if_project (comanage_data ["Projects" ], group )
283+
284+ comanage_data ["highest_osggid" ] = update_highest_osggid (comanage_data ["highest_osggid" ], group )
285+ except TypeError :
286+ pass
287+ return comanage_data
288+
289+
290+ def get_projects_to_setup (project_groups ):
291+ projects_to_setup = {
292+ "Need Identifiers" : [],
293+ "Need Cluster Groups" : [],
294+ "Need Provisioning" : [],
295+ }
296+
297+ # CO Groups associated with a UNIX Cluster Group
298+ clustered_group_ids = get_unix_cluster_groups_ids (options .ucid )
299+
300+ for project in project_groups :
301+ # If this project doesn't have an osggid already assigned to it...
302+ if identifier_from_list (project ["ID_List" ], "osggid" ) is None :
303+ # Prep the project to have the proper identifiers added to it
304+ projects_to_setup ["Need Identifiers" ].append (project )
305+
306+ # If this project doesn't have a UNIX Cluster Group associated with it...
307+ if not project ["Gid" ] in clustered_group_ids :
308+ # Prep it to have one made for it and to be provisioned in LDAP
309+ projects_to_setup ["Need Cluster Groups" ].append (project )
310+ projects_to_setup ["Need Provisioning" ].append (project )
311+
312+ return projects_to_setup
313+
314+
315+ def add_missing_group_identifier (project , id_type , value ):
316+ # If the group doesn't already have an id of this type...
317+ if identifier_from_list (project ["ID_List" ], id_type ) is None :
318+ add_identifier_to_group (project ["Gid" ], id_type , value )
319+ print (f'project { project ["Gid" ]} : aded id { value } of type { id_type } ' )
320+
321+
322+ def assign_identifiers_to_project (project , id_dict ):
323+ for k , v in id_dict .items ():
324+ # Add an identifier of type k and value v to this group, if it dones't have them already
325+ add_missing_group_identifier (project , k , v )
326+
327+
328+ def assign_identifiers (project_list , highest_osggid ):
329+ highest = highest_osggid
330+ for project in project_list :
331+ # Project name identifier is the CO Group name in lower case
332+ project_name = project ["Name" ].lower ()
333+
334+ # Determine what osggid to assign this project,
335+ # based on the starting range and the highest osggid seen in existing groups
336+ osggid_to_assign = max (highest + 1 , options .project_gid_startval )
337+ highest = osggid_to_assign
338+
339+ identifiers_to_add = {"osggid" : osggid_to_assign , "osggroup" : project_name }
340+
341+ assign_identifiers_to_project (project , identifiers_to_add )
342+
343+
344+ def create_unix_cluster_groups (project_list ):
345+ for project in project_list :
346+ add_unix_cluster_group (project ["Gid" ])
347+ print (f'project group { project ["Gid" ]} : added UNIX Cluster Group' )
348+
349+
350+ def provision_groups (project_list ):
351+ for project in project_list :
352+ ldap_provision_group (project ["Gid" ])
353+ print (f'project group { project ["Gid" ]} : Provisioned Group' )
354+
355+
233356def main (args ):
234357 parse_options (args )
235358
236- # get groups with 'OSPool project name' matching "Yes-*" that don't have a 'OSG GID'
359+ comanage_data = get_comanage_data ()
360+ projects_to_setup = get_projects_to_setup (comanage_data ["Projects" ])
237361
238- co_groups = get_osg_co_groups ()["CoGroups" ]
239- highest_osggid = 0
240- project_groups = set ()
241- projects_to_assign_identifiers = []
242-
243- unix_cluster_groups = call_api ("unix_cluster/unix_cluster_groups.json" , unix_cluster_id = options .unix_id )
244- clustered_group_ids = set (group ["CoGroupId" ] for group in unix_cluster_groups ["UnixClusterGroups" ])
245- projects_needing_cluster_groups = set ()
246-
247- for group in co_groups :
248- gid = group ["Id" ]
249- identifier_data = get_co_group_identifiers (gid )
250-
251- if identifier_data :
252- identifier_list = identifier_data ["Identifiers" ]
253-
254- project_id_index = identifier_index (identifier_list , "ospoolproject" )
255- if project_id_index != - 1 :
256- project_id = str (identifier_list [project_id_index ]["Identifier" ])
257- if re .compile (OSPOOL_PROJECT_PREFIX_STR + "*" ).match (project_id ) is not None :
258- project_groups .add (gid )
259-
260- osggid_index = identifier_index (identifier_list , "osggid" )
261- if osggid_index != - 1 :
262- highest_osggid = max (highest_osggid , int (identifier_list [osggid_index ]["Identifier" ]))
263-
264- if gid in project_groups :
265- if osggid_index == - 1 :
266- project_name = project_id .replace (OSPOOL_PROJECT_PREFIX_STR , "" , 1 ).lower ()
267- project_data = (
268- gid ,
269- project_name ,
270- )
271- projects_to_assign_identifiers .append (project_data )
272-
273- if not gid in clustered_group_ids :
274- projects_needing_cluster_groups .add (gid )
275-
276- for gid , project_name in projects_to_assign_identifiers :
277- # for each, set a 'OSG GID' starting from 200000 and a 'OSG Group Name' that is the group name
278- osggid_to_assign = max (highest_osggid + 1 , options .project_gid_startval )
279- highest_osggid = osggid_to_assign
280- add_identifier_to_group (gid , type = "osggid" , identifier_name = osggid_to_assign )
281- add_identifier_to_group (gid , type = "osggroup" , identifier_name = project_name )
282- print (f"project { project_name } : added osggid { osggid_to_assign } and osg project name { project_name } " )
283-
284- for gid in projects_needing_cluster_groups :
285- request = {
286- "RequestType" : "UnixClusterGroups" ,
287- "Version" : "1.0" ,
288- "UnixClusterGroups" : [{"Version" : "1.0" , "UnixClusterId" : options .unix_id , "CoGroupId" : gid }],
289- }
290- call_api3 (
291- POST ,
292- "unix_cluster/unix_cluster_groups.json" ,
293- request ,
294- )
295- print (f"project group { gid } : added UNIX Cluster Group" )
296-
297- for project_gid in project_groups :
298- #Provision all project groups
299- call_api2 (POST , f"co_provisioning_targets/provision/{ options .provision_target } /cogroupid:{ project_gid } .json" )
362+ assign_identifiers (projects_to_setup ["Need Identifiers" ], comanage_data ["highest_osggid" ])
363+ create_unix_cluster_groups (projects_to_setup ["Need Cluster Groups" ])
364+ provision_groups (projects_to_setup ["Need Provisioning" ])
300365
301366
302367if __name__ == "__main__" :
303368 try :
304369 main (sys .argv [1 :])
305- except urllib . error . HTTPError as e :
370+ except OSError as e :
306371 print (e , file = sys .stderr )
307372 sys .exit (1 )
0 commit comments