mirror of
https://github.com/GAM-team/GAM.git
synced 2026-06-28 09:51:36 +00:00
465 lines
16 KiB
Python
465 lines
16 KiB
Python
import sys
|
|
|
|
import gam
|
|
from gam.var import *
|
|
from gam import controlflow
|
|
from gam import display
|
|
from gam import gapi
|
|
from gam.gapi import directory as gapi_directory
|
|
from gam.gapi import errors as gapi_errors
|
|
|
|
|
|
def _getAllParentOrgUnitsForUser(user, cd=None):
|
|
if not cd:
|
|
cd = gapi_directory.build()
|
|
parent_path = gapi.call(cd.users(),
|
|
'get',
|
|
userKey=user,
|
|
fields='orgUnitPath',
|
|
projection='basic')['orgUnitPath']
|
|
if parent_path == '/':
|
|
orgUnitPath, orgUnitId = getOrgUnitId('/', cd)
|
|
return {orgUnitId: orgUnitPath}
|
|
parent_path = encodeOrgUnitPath(makeOrgUnitPathRelative(parent_path))
|
|
orgUnits = {}
|
|
while True:
|
|
result = gapi.call(cd.orgunits(),
|
|
'get',
|
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
|
orgUnitPath=parent_path,
|
|
fields='orgUnitId,orgUnitPath,parentOrgUnitId')
|
|
orgUnits[result['orgUnitId']] = result['orgUnitPath']
|
|
if 'parentOrgUnitId' not in result:
|
|
break
|
|
parent_path = result['parentOrgUnitId']
|
|
return orgUnits
|
|
|
|
|
|
def create():
|
|
cd = gapi_directory.build()
|
|
name = getOrgUnitItem(sys.argv[3], pathOnly=True, absolutePath=False)
|
|
parent = ''
|
|
body = {}
|
|
i = 4
|
|
while i < len(sys.argv):
|
|
myarg = sys.argv[i].lower()
|
|
if myarg == 'description':
|
|
body['description'] = sys.argv[i + 1].replace('\\n', '\n')
|
|
i += 2
|
|
elif myarg == 'parent':
|
|
parent = getOrgUnitItem(sys.argv[i + 1])
|
|
i += 2
|
|
elif myarg == 'noinherit':
|
|
body['blockInheritance'] = True
|
|
i += 1
|
|
elif myarg == 'inherit':
|
|
body['blockInheritance'] = False
|
|
i += 1
|
|
else:
|
|
controlflow.invalid_argument_exit(sys.argv[i], 'gam create org')
|
|
if parent.startswith('id:'):
|
|
parent = gapi.call(cd.orgunits(),
|
|
'get',
|
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
|
orgUnitPath=parent,
|
|
fields='orgUnitPath')['orgUnitPath']
|
|
if parent == '/':
|
|
orgUnitPath = parent + name
|
|
else:
|
|
orgUnitPath = parent + '/' + name
|
|
if orgUnitPath.count('/') > 1:
|
|
body['parentOrgUnitPath'], body['name'] = orgUnitPath.rsplit('/', 1)
|
|
else:
|
|
body['parentOrgUnitPath'] = '/'
|
|
body['name'] = orgUnitPath[1:]
|
|
parent = body['parentOrgUnitPath']
|
|
gapi.call(cd.orgunits(),
|
|
'insert',
|
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
|
body=body,
|
|
retry_reasons=[gapi_errors.ErrorReason.DAILY_LIMIT_EXCEEDED])
|
|
print(f'Created OrgUnit {body["name"]}')
|
|
|
|
|
|
def delete():
|
|
cd = gapi_directory.build()
|
|
name = getOrgUnitItem(sys.argv[3])
|
|
print(f'Deleting organization {name}')
|
|
gapi.call(cd.orgunits(),
|
|
'delete',
|
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
|
orgUnitPath=encodeOrgUnitPath(makeOrgUnitPathRelative(name)))
|
|
|
|
|
|
def info(name=None, return_attrib=None):
|
|
cd = gapi_directory.build()
|
|
checkSuspended = None
|
|
if not name:
|
|
name = getOrgUnitItem(sys.argv[3])
|
|
get_users = True
|
|
show_children = False
|
|
i = 4
|
|
while i < len(sys.argv):
|
|
myarg = sys.argv[i].lower()
|
|
if myarg == 'nousers':
|
|
get_users = False
|
|
i += 1
|
|
elif myarg in ['children', 'child']:
|
|
show_children = True
|
|
i += 1
|
|
elif myarg in ['suspended', 'notsuspended']:
|
|
checkSuspended = myarg == 'suspended'
|
|
i += 1
|
|
else:
|
|
controlflow.invalid_argument_exit(sys.argv[i], 'gam info org')
|
|
if name == '/':
|
|
orgs = gapi.call(cd.orgunits(),
|
|
'list',
|
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
|
type='children',
|
|
fields='organizationUnits/parentOrgUnitId')
|
|
if 'organizationUnits' in orgs and orgs['organizationUnits']:
|
|
name = orgs['organizationUnits'][0]['parentOrgUnitId']
|
|
else:
|
|
topLevelOrgId = getTopLevelOrgId(cd, '/')
|
|
if topLevelOrgId:
|
|
name = topLevelOrgId
|
|
else:
|
|
name = makeOrgUnitPathRelative(name)
|
|
result = gapi.call(cd.orgunits(),
|
|
'get',
|
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
|
orgUnitPath=encodeOrgUnitPath(name))
|
|
if return_attrib:
|
|
return result[return_attrib]
|
|
display.print_json(result)
|
|
if get_users:
|
|
name = result['orgUnitPath']
|
|
page_message = gapi.got_total_items_first_last_msg('Users')
|
|
users = gapi.get_all_pages(
|
|
cd.users(),
|
|
'list',
|
|
'users',
|
|
page_message=page_message,
|
|
message_attribute='primaryEmail',
|
|
customer=GC_Values[GC_CUSTOMER_ID],
|
|
query=orgUnitPathQuery(name, checkSuspended),
|
|
fields='users(primaryEmail,orgUnitPath),nextPageToken')
|
|
if checkSuspended is None:
|
|
print('Users:')
|
|
elif not checkSuspended:
|
|
print('Users (Not suspended):')
|
|
else:
|
|
print('Users (Suspended):')
|
|
for user in users:
|
|
if show_children or (name.lower() == user['orgUnitPath'].lower()):
|
|
sys.stdout.write(f' {user["primaryEmail"]}')
|
|
if name.lower() != user['orgUnitPath'].lower():
|
|
print(' (child)')
|
|
else:
|
|
print('')
|
|
|
|
|
|
def list_orgunits(listType='all', orgUnitPath=None, fields=None):
|
|
retrievedOrgIds = []
|
|
parentOrgIds = []
|
|
cd = gapi_directory.build()
|
|
if fields:
|
|
# Always get parentOrgUnitId so we can
|
|
# find missing parents
|
|
if 'parentOrgUnitId' not in fields:
|
|
fields.append('parentOrgUnitId')
|
|
get_fields = ','.join(fields)
|
|
list_fields = f'organizationUnits({get_fields})'
|
|
else:
|
|
list_fields = None
|
|
get_fields = None
|
|
orgs = gapi.call(cd.orgunits(),
|
|
'list',
|
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
|
type=listType,
|
|
orgUnitPath=orgUnitPath,
|
|
fields=list_fields)
|
|
if not 'organizationUnits' in orgs:
|
|
topLevelOrgId = getTopLevelOrgId(cd, orgUnitPath)
|
|
if topLevelOrgId:
|
|
parentOrgIds.append(topLevelOrgId)
|
|
orgunits = []
|
|
else:
|
|
orgunits = orgs['organizationUnits']
|
|
for row in orgunits:
|
|
retrievedOrgIds.append(row['orgUnitId'])
|
|
if row['parentOrgUnitId'] not in parentOrgIds:
|
|
parentOrgIds.append(row['parentOrgUnitId'])
|
|
missing_parents = set(parentOrgIds) - set(retrievedOrgIds)
|
|
for missing_parent in missing_parents:
|
|
try:
|
|
result = gapi.call(cd.orgunits(),
|
|
'get',
|
|
throw_reasons=['required'],
|
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
|
orgUnitPath=missing_parent,
|
|
fields=get_fields)
|
|
orgunits.append(result)
|
|
except:
|
|
pass
|
|
return orgunits
|
|
|
|
|
|
def print_():
|
|
print_order = [
|
|
'orgUnitPath', 'orgUnitId', 'name', 'description', 'parentOrgUnitPath',
|
|
'parentOrgUnitId', 'blockInheritance'
|
|
]
|
|
listType = 'all'
|
|
orgUnitPath = '/'
|
|
todrive = False
|
|
fields = ['orgUnitPath', 'name', 'orgUnitId', 'parentOrgUnitId']
|
|
titles = []
|
|
csvRows = []
|
|
i = 3
|
|
while i < len(sys.argv):
|
|
myarg = sys.argv[i].lower().replace('_', '')
|
|
if myarg == 'todrive':
|
|
todrive = True
|
|
i += 1
|
|
elif myarg == 'toplevelonly':
|
|
listType = 'children'
|
|
i += 1
|
|
elif myarg == 'fromparent':
|
|
orgUnitPath = getOrgUnitItem(sys.argv[i + 1])
|
|
i += 2
|
|
elif myarg == 'allfields':
|
|
fields = None
|
|
i += 1
|
|
elif myarg == 'fields':
|
|
fields += sys.argv[i + 1].split(',')
|
|
i += 2
|
|
else:
|
|
controlflow.invalid_argument_exit(sys.argv[i], 'gam print orgs')
|
|
gam.printGettingAllItems('Organizational Units', None)
|
|
orgunits = list_orgunits(listType=listType,
|
|
orgUnitPath=orgUnitPath,
|
|
fields=fields)
|
|
for row in orgunits:
|
|
orgEntity = {}
|
|
for key, value in list(row.items()):
|
|
if key in ['kind', 'etag', 'etags']:
|
|
continue
|
|
if key not in titles:
|
|
titles.append(key)
|
|
orgEntity[key] = value
|
|
csvRows.append(orgEntity)
|
|
for title in titles:
|
|
if title not in print_order:
|
|
print_order.append(title)
|
|
titles = sorted(titles, key=print_order.index)
|
|
# sort results similar to how they list in admin console
|
|
csvRows.sort(key=lambda x: x['orgUnitPath'].lower(), reverse=False)
|
|
display.write_csv_file(csvRows, titles, 'Orgs', todrive)
|
|
|
|
|
|
def orgid_to_org_map():
|
|
orgunits = list_orgunits(fields=['orgUnitPath', 'orgUnitId'])
|
|
result = {ou['orgUnitId']:ou['orgUnitPath'] for ou in orgunits}
|
|
return result
|
|
|
|
def update():
|
|
cd = gapi_directory.build()
|
|
orgUnitPath = getOrgUnitItem(sys.argv[3])
|
|
if sys.argv[4].lower() in ['move', 'add']:
|
|
entity_type = sys.argv[5].lower()
|
|
if entity_type in usergroup_types:
|
|
users = gam.getUsersToModify(entity_type=entity_type,
|
|
entity=sys.argv[6])
|
|
else:
|
|
entity_type = 'users'
|
|
users = gam.getUsersToModify(entity_type=entity_type,
|
|
entity=sys.argv[5])
|
|
if (entity_type.startswith('cros')) or (
|
|
(entity_type == 'all') and (sys.argv[6].lower() == 'cros')):
|
|
for l in range(0, len(users), 50):
|
|
move_body = {'deviceIds': users[l:l + 50]}
|
|
print(
|
|
f' moving {len(move_body["deviceIds"])} devices to {orgUnitPath}'
|
|
)
|
|
gapi.call(cd.chromeosdevices(),
|
|
'moveDevicesToOu',
|
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
|
orgUnitPath=orgUnitPath,
|
|
body=move_body)
|
|
else:
|
|
i = 0
|
|
count = len(users)
|
|
for user in users:
|
|
i += 1
|
|
sys.stderr.write(
|
|
f' moving {user} to {orgUnitPath}{gam.currentCountNL(i, count)}'
|
|
)
|
|
try:
|
|
gapi.call(cd.users(),
|
|
'update',
|
|
throw_reasons=[
|
|
gapi_errors.ErrorReason.CONDITION_NOT_MET
|
|
],
|
|
userKey=user,
|
|
body={'orgUnitPath': orgUnitPath})
|
|
except gapi_errors.GapiConditionNotMetError:
|
|
pass
|
|
else:
|
|
body = {}
|
|
i = 4
|
|
while i < len(sys.argv):
|
|
myarg = sys.argv[i].lower()
|
|
if myarg == 'name':
|
|
body['name'] = sys.argv[i + 1]
|
|
i += 2
|
|
elif myarg == 'description':
|
|
body['description'] = sys.argv[i + 1].replace('\\n', '\n')
|
|
i += 2
|
|
elif myarg == 'parent':
|
|
parent = getOrgUnitItem(sys.argv[i + 1])
|
|
if parent.startswith('id:'):
|
|
body['parentOrgUnitId'] = parent
|
|
else:
|
|
body['parentOrgUnitPath'] = parent
|
|
i += 2
|
|
elif myarg == 'noinherit':
|
|
body['blockInheritance'] = True
|
|
i += 1
|
|
elif myarg == 'inherit':
|
|
body['blockInheritance'] = False
|
|
i += 1
|
|
else:
|
|
controlflow.invalid_argument_exit(sys.argv[i], 'gam update org')
|
|
gapi.call(cd.orgunits(),
|
|
'update',
|
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
|
orgUnitPath=encodeOrgUnitPath(
|
|
makeOrgUnitPathRelative(orgUnitPath)),
|
|
body=body)
|
|
|
|
|
|
def orgUnitPathQuery(path, checkSuspended):
|
|
query = "orgUnitPath='{}'".format(path.replace(
|
|
"'", "\\'")) if path != '/' else ''
|
|
if checkSuspended is not None:
|
|
query += f' isSuspended={checkSuspended}'
|
|
return query
|
|
|
|
|
|
def makeOrgUnitPathAbsolute(path):
|
|
if path == '/':
|
|
return path
|
|
if path.startswith('/'):
|
|
return path.rstrip('/')
|
|
if path.startswith('id:'):
|
|
return path
|
|
if path.startswith('uid:'):
|
|
return path[1:]
|
|
return '/' + path.rstrip('/')
|
|
|
|
|
|
def makeOrgUnitPathRelative(path):
|
|
if path == '/':
|
|
return path
|
|
if path.startswith('/'):
|
|
return path[1:].rstrip('/')
|
|
if path.startswith('id:'):
|
|
return path
|
|
if path.startswith('uid:'):
|
|
return path[1:]
|
|
return path.rstrip('/')
|
|
|
|
|
|
def encodeOrgUnitPath(path):
|
|
# 6.22 - This method no longer works.
|
|
# % no longer needs encoding and + is handled incorrectly in API with or without encoding
|
|
return path
|
|
# if path.find('+') == -1 and path.find('%') == -1:
|
|
# return path
|
|
# encpath = ''
|
|
# for c in path:
|
|
# if c == '+':
|
|
# encpath += '%2B'
|
|
# elif c == '%':
|
|
# encpath += '%25'
|
|
# else:
|
|
# encpath += c
|
|
# return encpath
|
|
|
|
|
|
def getOrgUnitItem(orgUnit, pathOnly=False, absolutePath=True):
|
|
if pathOnly and (orgUnit.startswith('id:') or orgUnit.startswith('uid:')):
|
|
controlflow.system_error_exit(
|
|
2, f'{orgUnit} is not valid in this context')
|
|
if absolutePath:
|
|
return makeOrgUnitPathAbsolute(orgUnit)
|
|
return makeOrgUnitPathRelative(orgUnit)
|
|
|
|
|
|
def getTopLevelOrgId(cd, orgUnitPath):
|
|
try:
|
|
# create a temp org so we can learn what the top level org ID is (sigh)
|
|
temp_org = gapi.call(cd.orgunits(),
|
|
'insert',
|
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
|
body={
|
|
'name': 'temp-delete-me',
|
|
'parentOrgUnitPath': orgUnitPath
|
|
},
|
|
fields='parentOrgUnitId,orgUnitId')
|
|
gapi.call(cd.orgunits(),
|
|
'delete',
|
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
|
orgUnitPath=temp_org['orgUnitId'])
|
|
return temp_org['parentOrgUnitId']
|
|
except:
|
|
pass
|
|
return None
|
|
|
|
|
|
def getOrgUnitId(orgUnit, cd=None):
|
|
if cd is None:
|
|
cd = gapi_directory.build()
|
|
orgUnit = getOrgUnitItem(orgUnit)
|
|
if orgUnit[:3] == 'id:':
|
|
return (orgUnit, orgUnit)
|
|
if orgUnit == '/':
|
|
result = gapi.call(cd.orgunits(),
|
|
'list',
|
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
|
orgUnitPath='/',
|
|
type='children',
|
|
fields='organizationUnits(parentOrgUnitId)')
|
|
if result.get('organizationUnits', []):
|
|
return (orgUnit, result['organizationUnits'][0]['parentOrgUnitId'])
|
|
topLevelOrgId = getTopLevelOrgId(cd, '/')
|
|
if topLevelOrgId:
|
|
return (orgUnit, topLevelOrgId)
|
|
return (orgUnit, '/') #Bogus but should never happen
|
|
result = gapi.call(cd.orgunits(),
|
|
'get',
|
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
|
orgUnitPath=encodeOrgUnitPath(
|
|
makeOrgUnitPathRelative(orgUnit)),
|
|
fields='orgUnitId')
|
|
return (orgUnit, result['orgUnitId'])
|
|
|
|
|
|
def orgunit_from_orgunitid(orgunitid, cd=None):
|
|
if cd is None:
|
|
cd = gapi_directory.build()
|
|
orgunitpath = GM_Globals[GM_MAP_ORGUNIT_ID_TO_NAME].get(orgunitid)
|
|
if not orgunitpath:
|
|
try:
|
|
orgunitpath = gapi.call(cd.orgunits(),
|
|
'get',
|
|
customerId=GC_Values[GC_CUSTOMER_ID],
|
|
orgUnitPath=f'id:{orgunitid}' if not orgunitid.startswith('id:') else orgunitid,
|
|
fields='orgUnitPath')['orgUnitPath']
|
|
except:
|
|
orgunitpath = orgunitid
|
|
GM_Globals[GM_MAP_ORGUNIT_ID_TO_NAME][orgunitid] = orgunitpath
|
|
return orgunitpath
|