import re import sys import gam from gam.var import * from gam import controlflow from gam import display from gam import gapi from gam.gapi import errors as gapi_errors from gam.gapi.directory import customer as gapi_directory_customer def _get_customerid(): ''' returns customerId with format C{customer_id}''' gapi_directory_customer.setTrueCustomerId() customer_id = GC_Values[GC_CUSTOMER_ID] if customer_id[0] != 'C': customer_id = 'C' + customer_id return customer_id def build(): return gam.buildGAPIObject('licensing') def getProductAndSKU(sku): l_sku = sku.lower().replace('-', '').replace(' ', '') for a_sku, sku_values in list(SKUS.items()): if l_sku == a_sku.lower().replace( '-', '') or l_sku in sku_values['aliases'] or l_sku == sku_values[ 'displayName'].lower().replace(' ', ''): return (sku_values['product'], a_sku) try: product = re.search('^([A-Z,a-z]*-[A-Z,a-z]*)', sku).group(1) except AttributeError: product = sku return (product, sku) def user_lic_result(request_id, response, exception): if exception: http_status, reason, message = gapi_errors.get_gapi_error_detail( exception, soft_errors=True) print(f'ERROR: {request_id}: {http_status} - {reason} {message}') def create(users, sku=None): lic = build() if not sku: sku = sys.argv[5] productId, skuId = getProductAndSKU(sku) sku_name = _formatSKUIdDisplayName(skuId) i = 6 if len(sys.argv) > 6 and sys.argv[i].lower() in ['product', 'productid']: productId = sys.argv[i+1] i += 2 for user in users: print(f'Adding license {sku_name} from to {user}') gapi.call(lic.licenseAssignments(), 'insert', soft_errors=True, productId=productId, skuId=skuId, body={'userId': user}) def delete(users, sku=None): lic = build() if not sku: sku = sys.argv[5] productId, skuId = getProductAndSKU(sku) sku_name = _formatSKUIdDisplayName(skuId) i = 6 if len(sys.argv) > 6 and sys.argv[i].lower() in ['product', 'productid']: productId = sys.argv[i+1] i += 2 for user in users: print(f'Removing license {sku_name} from user {user}') gapi.call(lic.licenseAssignments(), 'delete', soft_errors=True, productId=productId, skuId=skuId, userId=user) def sync(users): sku = sys.argv[5] current_licenses = gam.getUsersToModify(entity_type='license', entity=sku) users_to_license = [user for user in users if user not in current_licenses] users_to_unlicense = [user for user in current_licenses if user not in users] print(f'Need to remove license from {len(users_to_unlicense)} and add to ' \ f'{len(users_to_license)} users...') # do the remove first to free up seats delete(users_to_unlicense, sku) create(users_to_license, sku) def update(users, sku=None, old_sku=None): lic = build() if not sku: sku = sys.argv[5] productId, skuId = getProductAndSKU(sku) sku_name = _formatSKUIdDisplayName(skuId) i = 6 if len(sys.argv) > 6 and sys.argv[i].lower() in ['product', 'productid']: productId = sys.argv[i+1] i += 2 if not old_sku: try: old_sku = sys.argv[i] if old_sku.lower() == 'from': old_sku = sys.argv[i + 1] except KeyError: controlflow.system_error_exit( 2, 'You need to specify the user\'s old SKU as the last argument' ) _, old_sku = getProductAndSKU(old_sku) old_sku_name = _formatSKUIdDisplayName(old_sku) for user in users: print(f'Changing user {user} from license {old_sku_name} to {sku_name}') gapi.call(lic.licenseAssignments(), 'patch', soft_errors=True, productId=productId, skuId=old_sku, userId=user, body={'skuId': skuId}) def print_(returnFields=None, skus=None, countsOnly=False, returnCounts=False): lic = build() customer_id = _get_customerid() products = [] licenses = [] licenseCounts = [] if not returnFields: csvRows = [] todrive = False i = 3 while i < len(sys.argv): myarg = sys.argv[i].lower() if not returnCounts and myarg == 'todrive': todrive = True i += 1 elif myarg in ['products', 'product']: products = sys.argv[i + 1].split(',') i += 2 elif myarg in ['sku', 'skus']: skus = sys.argv[i + 1].split(',') i += 2 elif myarg == 'allskus': skus = sorted(SKUS) products = [] i += 1 elif myarg == 'gsuite': skus = [ skuId for skuId in SKUS if SKUS[skuId]['product'] in ['Google-Apps', '101031'] ] products = [] i += 1 elif myarg == 'countsonly': countsOnly = True i += 1 else: controlflow.invalid_argument_exit(sys.argv[i], 'gam print licenses') if not countsOnly: fields = 'nextPageToken,items(productId,skuId,userId)' titles = ['userId', 'productId', 'skuId'] else: fields = 'nextPageToken,items(userId)' if not returnCounts: if skus: titles = ['productId', 'skuId', 'licenses'] else: titles = ['productId', 'licenses'] else: fields = f'nextPageToken,items({returnFields})' if skus: for sku in skus: if not products: product, sku = getProductAndSKU(sku) else: product = products[0] page_message = gapi.got_total_items_msg( f'Licenses for {SKUS.get(sku, {"displayName": sku})["displayName"]}', '...\n') try: licenses += gapi.get_all_pages( lic.licenseAssignments(), 'listForProductAndSku', 'items', throw_reasons=[ gapi_errors.ErrorReason.INVALID, gapi_errors.ErrorReason.FORBIDDEN ], page_message=page_message, customerId=customer_id, productId=product, skuId=sku, fields=fields) if countsOnly: licenseCounts.append([ 'Product', product, 'SKU', sku, 'Licenses', len(licenses) ]) licenses = [] except (gapi_errors.GapiInvalidError, gapi_errors.GapiForbiddenError): pass else: if not products: products = sorted(PRODUCTID_NAME_MAPPINGS) for productId in products: page_message = gapi.got_total_items_msg( f'Licenses for {PRODUCTID_NAME_MAPPINGS.get(productId, productId)}', '...\n') try: licenses += gapi.get_all_pages( lic.licenseAssignments(), 'listForProduct', 'items', throw_reasons=[ gapi_errors.ErrorReason.INVALID, gapi_errors.ErrorReason.FORBIDDEN ], page_message=page_message, customerId=customer_id, productId=productId, fields=fields) if countsOnly: licenseCounts.append( ['Product', productId, 'Licenses', len(licenses)]) licenses = [] except (gapi_errors.GapiInvalidError, gapi_errors.GapiForbiddenError): pass if countsOnly: if returnCounts: return licenseCounts if skus: for u_license in licenseCounts: csvRows.append({ 'productId': u_license[1], 'skuId': u_license[3], 'licenses': u_license[5] }) else: for u_license in licenseCounts: csvRows.append({ 'productId': u_license[1], 'licenses': u_license[3] }) display.write_csv_file(csvRows, titles, 'Licenses', todrive) return if returnFields: if returnFields == 'userId': userIds = [] for u_license in licenses: userId = u_license.get('userId', '').lower() if userId: userIds.append(userId) return userIds userSkuIds = {} for u_license in licenses: userId = u_license.get('userId', '').lower() skuId = u_license.get('skuId') if userId and skuId: userSkuIds.setdefault(userId, []) userSkuIds[userId].append(skuId) return userSkuIds for u_license in licenses: userId = u_license.get('userId', '').lower() skuId = u_license.get('skuId', '') csvRows.append({ 'userId': userId, 'productId': u_license.get('productId', ''), 'skuId': _skuIdToDisplayName(skuId) }) display.write_csv_file(csvRows, titles, 'Licenses', todrive) def show(): licenseCounts = print_(countsOnly=True, returnCounts=True) for u_license in licenseCounts: line = '' for i in range(0, len(u_license), 2): line += f'{u_license[i]}: {u_license[i+1]}, ' print(line[:-2]) def _skuIdToDisplayName(skuId): return SKUS[skuId]['displayName'] if skuId in SKUS else skuId def _formatSKUIdDisplayName(skuId): skuIdDisplay = _skuIdToDisplayName(skuId) if skuId == skuIdDisplay: return skuId return f'{skuId} ({skuIdDisplay})'