Skip to content

Commit 458af37

Browse files
project_groups_setup refactoring
1 parent e94a159 commit 458af37

1 file changed

Lines changed: 142 additions & 77 deletions

File tree

project_group_setup.py

Lines changed: 142 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@
44
import re
55
import sys
66
import json
7+
#import ldap3
78
import getopt
89
import urllib.error
910
import urllib.request
1011

1112
SCRIPT = os.path.basename(__file__)
1213
ENDPOINT = "https://registry-test.cilogon.org/registry/"
1314
OSG_CO_ID = 8
14-
CLUSTER_ID = 10
15+
UNIX_CLUSTER_ID = 10
1516
LDAP_TARGET_ID = 9
1617
MINTIMEOUT = 5
1718
MAXTIMEOUT = 625
@@ -32,7 +33,7 @@
3233
OPTIONS:
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+
158168
def 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

170181
def 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

193217
def 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+
233356
def 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

302367
if __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

Comments
 (0)