-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathsync-project-owner-avus
More file actions
executable file
·162 lines (119 loc) · 4.63 KB
/
Copy pathsync-project-owner-avus
File metadata and controls
executable file
·162 lines (119 loc) · 4.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#!/usr/bin/env --split-string=uv run --script
# -*- coding: utf-8 -*-
#
# ///
# dependencies = [
# "python-irodsclient",
# "python-ldap",
# ]
# ///
#
# Requires the following system packages:
# libldap2-dev
# libsasl2-dev
#
# © 2025, The Arizona Board of Regents on behalf of The University of Arizona.
# For license information, see https://cyverse.org/license.
"""Aligns project folder ipc::project-owner AVUs with the users who have own permission.
This script does the following for each collection in /<zone>/home/shared.
1. Extracts the usernames of the users that have own permission on the collection.
3. Queries LDAP to get full names for each owner
4. Updates the (ipc::project-owner, <username>, <full name>) AVUs attached to it.
Usage:
sync-project-owner-avus LDAP-URL
Parameters:
LDAP-URL the URL used to access the LDAP server used for resolving full names.
"""
import os
from os import path
import sys
from typing import Dict, List, Optional
from irods.access import iRODSAccess
from irods.collection import iRODSCollection
from irods.exception import CAT_INVALID_AUTHENTICATION
from irods.models import Collection, CollectionAccess, User
from irods.session import iRODSSession, NonAnonymousLoginWithoutPassword
import ldap
from ldap.ldapobject import LDAPObject
_LDAP_BASE = "dc=iplantcollaborative,dc=org"
_ATTR = 'ipc::project-owner'
def main(args: List[str]) -> int:
"""The entrypoint"""
if len(args) < 1:
print("Requires the LDAP URL as the first argument", file=sys.stderr)
return 1
ldap_inst = _init_ldap(args[0])
irods_env = _resolve_irods_env()
if not irods_env:
print("The iRODS environment file cannot be found", file=sys.stderr)
return 1
try:
with iRODSSession(irods_env_file=irods_env) as irods:
if irods.users.get(irods.username, irods.zone).type != 'rodsadmin':
print("The authenticated iRODS user needs to be a rodsadmin", file=sys.stderr)
return 1
_sync_avus(ldap_inst, irods)
except CAT_INVALID_AUTHENTICATION:
print("The iRODS session has not been initialized. Please use `iinit`", file=sys.stderr)
return 1
except NonAnonymousLoginWithoutPassword:
print("The iRODS session has not been initialized. Please use `iinit`", file=sys.stderr)
return 1
return 0
def _init_ldap(url: str) -> LDAPObject:
ldap_inst = ldap.initialize(url)
ldap_inst.simple_bind_s()
return ldap_inst
def _resolve_irods_env() -> Optional[str]:
env = os.environ.get(
'IRODS_ENVIRONMENT_FILE', path.expanduser('~/.irods/irods_environment.json'))
if os.path.isfile(env):
return env
def _sync_avus(ldap_inst, irods):
projects_coll = irods.collections.get(f"/{irods.zone}/home/shared")
for coll in projects_coll.subcollections:
print(f"Processing {coll.path}")
owners = _get_owners(ldap_inst, irods, coll)
tagged_owners = _get_tagged_owners(coll)
for username, cn in owners.items():
tagged_cn = tagged_owners.get(username)
if tagged_cn is None:
coll.metadata.add(_ATTR, username, cn)
elif tagged_cn != cn:
coll.metadata.remove(_ATTR, username, tagged_cn)
coll.metadata.add(_ATTR, username, cn)
for username, tagged_cn in tagged_owners.items():
cn = owners.get(username)
if cn is None:
coll.metadata.remove(_ATTR, username, cn)
def _get_owners(
ldap_inst: LDAPObject, irods: iRODSSession, coll: iRODSCollection
) -> Dict[str, str]:
owners = {}
owner_id_query = irods.query(CollectionAccess.user_id)
for owner_id_res in owner_id_query.filter(
Collection.name == coll.path, CollectionAccess.type == iRODSAccess['own']
):
owner_query = irods.query(User.name)
for owner_res in owner_query.filter(
User.id == owner_id_res[CollectionAccess.user_id], User.type == 'rodsuser'
):
owners[owner_res[User.name]] = _resolve_common_name(ldap_inst, owner_res[User.name])
return owners
def _resolve_common_name(ldap_inst: LDAPObject, uid: str) -> str:
ldap_res = ldap_inst.search_s(
base=_LDAP_BASE,
scope=ldap.SCOPE_SUBTREE,
filterstr=f"(uid={uid})",
attrlist=['cn'])
if ldap_res:
return ldap_res[0][1]['cn'][0].decode('utf-8')
else:
return ''
def _get_tagged_owners(coll: iRODSCollection) -> Dict[str, str]:
owners = {}
for avu in coll.metadata.get_all(_ATTR):
owners[avu.value] = avu.units
return owners
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))