def test_csv_field_error_exit_prints_error_details(self, mock_print_err): with self.assertRaises(SystemExit): controlflow.csv_field_error_exit('aField', ['unusedField1', 'unusedField2']) printed_message = mock_print_err.call_args[0][0] self.assertIn('aField', printed_message) self.assertIn('unusedField1', printed_message) self.assertIn('unusedField2', printed_message)
def move(): cbcm = build() body = {'resource_ids': []} i = 3 resource_ids = [] batch_size = 600 while i < len(sys.argv): myarg = sys.argv[i].lower().replace('_', '') if myarg == 'ids': resource_ids.extend(sys.argv[i + 1].split(',')) i += 2 elif myarg == 'query': query = sys.argv[i + 1] page_message = gapi.got_total_items_msg('Browsers', '...\n') browsers = gapi.get_all_pages(cbcm.chromebrowsers(), 'list', 'browsers', page_message=page_message, customer=GC_Values[GC_CUSTOMER_ID], query=query, projection='BASIC', fields='browsers(deviceId),nextPageToken') ids = [browser['deviceId'] for browser in browsers] resource_ids.extend(ids) i += 2 elif myarg == 'file': with fileutils.open_file(sys.argv[i+1], strip_utf_bom=True) as filed: for row in filed: rid = row.strip() if rid: resource_ids.append(rid) i += 2 elif myarg == 'csvfile': drive, fname_column = os.path.splitdrive(sys.argv[i+1]) if fname_column.find(':') == -1: controlflow.system_error_exit( 2, 'Expected csvfile FileName:FieldName') (filename, column) = fname_column.split(':') with fileutils.open_file(drive + filename) as filed: input_file = csv.DictReader(filed, restval='') if column not in input_file.fieldnames: controlflow.csv_field_error_exit(column, input_file.fieldnames) for row in input_file: rid = row[column].strip() if rid: resource_ids.append(rid) i += 2 elif myarg in ['ou', 'orgunit', 'org']: org_unit = gapi_directory_orgunits.getOrgUnitItem(sys.argv[i + 1]) body['org_unit_path'] = org_unit i += 2 elif myarg == 'batchsize': batch_size = int(sys.argv[i+1]) i += 2 else: controlflow.invalid_argument_exit(sys.argv[i], 'gam move browsers') if 'org_unit_path' not in body: controlflow.missing_argument_exit('ou', 'gam move browsers') elif not resource_ids: controlflow.missing_argument_exit('query or ids', 'gam move browsers') # split moves into max 600 devices per batch for chunk in range(0, len(resource_ids), batch_size): body['resource_ids'] = resource_ids[chunk:chunk + batch_size] print(f' moving {len(body["resource_ids"])} browsers to ' \ f'{body["org_unit_path"]}') gapi.call(cbcm.chromebrowsers(), 'moveChromeBrowsersToOu', customer=GC_Values[GC_CUSTOMER_ID], body=body)
def test_csv_field_error_exit_raises_systemexit_error(self): with self.assertRaises(SystemExit): controlflow.csv_field_error_exit('aField', ['unusedField1', 'unusedField2'])
def test_csv_field_error_exit_exits_code_2(self): with self.assertRaises(SystemExit) as context_manager: controlflow.csv_field_error_exit('aField', ['unusedField1', 'unusedField2']) self.assertEqual(context_manager.exception.code, 2)
def sync(): ci = gapi_cloudidentity.build_dwd() device_types = gapi.get_enum_values_minus_unspecified( ci._rootDesc['schemas']['GoogleAppsCloudidentityDevicesV1Device'] ['properties']['deviceType']['enum']) customer = _get_device_customerid() device_filter = None csv_file = None serialnumber_column = 'serialNumber' devicetype_column = 'deviceType' static_devicetype = None assettag_column = None unassigned_missing_action = 'delete' assigned_missing_action = 'donothing' missing_actions = ['delete', 'wipe', 'donothing'] i = 3 while i < len(sys.argv): myarg = sys.argv[i].lower().replace('_', '') if myarg in ['filter', 'query']: device_filter = sys.argv[i + 1] i += 2 elif myarg == 'csvfile': csv_file = sys.argv[i + 1] i += 2 elif myarg == 'serialnumbercolumn': serialnumber_column = sys.argv[i + 1] i += 2 elif myarg == 'devicetypecolumn': devicetype_column = sys.argv[i + 1] i += 2 elif myarg == 'staticdevicetype': static_devicetype = sys.argv[i + 1].upper() if static_devicetype not in device_types: controlflow.expected_argument_exit('device_type', ', '.join(device_types), sys.argv[i + 1]) i += 2 elif myarg in {'assettagcolumn', 'assetidcolumn'}: assettag_column = sys.argv[i + 1] i += 2 elif myarg == 'unassignedmissingaction': unassigned_missing_action = sys.argv[i + 1].lower().replace( '_', '') if unassigned_missing_action not in missing_actions: controlflow.expected_argument_exit('unassigned_missing_action', ', '.join(missing_actions), sys.argv[i + 1]) i += 2 elif myarg == 'assignedmissingaction': assigned_missing_action = sys.argv[i + 1].lower().replace('_', '') if assigned_missing_action not in missing_actions: controlflow.expected_argument_exit('assigned_missing_action', ', '.join(missing_actions), sys.argv[i + 1]) i += 2 else: controlflow.invalid_argument_exit(sys.argv[i], 'gam sync devices') if not csv_file: controlflow.system_error_exit( 3, 'csvfile is a required argument for "gam sync devices".') f = fileutils.open_file(csv_file) input_file = csv.DictReader(f, restval='') if serialnumber_column not in input_file.fieldnames: controlflow.csv_field_error_exit(serialnumber_column, input_file.fieldnames) if not static_devicetype and devicetype_column not in input_file.fieldnames: controlflow.csv_field_error_exit(devicetype_column, input_file.fieldnames) if assettag_column and assettag_column not in input_file.fieldnames: controlflow.csv_field_error_exit(assettag_column, input_file.fieldnames) local_devices = {} for row in input_file: # upper() is very important to comparison since Google # always return uppercase serials local_device = { 'serialNumber': row[serialnumber_column].strip().upper() } if static_devicetype: local_device['deviceType'] = static_devicetype else: local_device['deviceType'] = row[devicetype_column].strip() sndt = f"{local_device['serialNumber']}-{local_device['deviceType']}" if assettag_column: local_device['assetTag'] = row[assettag_column].strip() sndt += f"-{local_device['assetTag']}" local_devices[sndt] = local_device fileutils.close_file(f) page_message = gapi.got_total_items_msg('Company Devices', '...\n') device_fields = ['serialNumber', 'deviceType', 'lastSyncTime', 'name'] if assettag_column: device_fields.append('assetTag') fields = f'nextPageToken,devices({",".join(device_fields)})' remote_devices = {} remote_device_map = {} result = gapi.get_all_pages(ci.devices(), 'list', 'devices', customer=customer, page_message=page_message, pageSize=100, filter=device_filter, view='COMPANY_INVENTORY', fields=fields) for remote_device in result: sn = remote_device['serialNumber'] last_sync = remote_device.pop('lastSyncTime', NEVER_TIME_NOMS) name = remote_device.pop('name') sndt = f"{remote_device['serialNumber']}-{remote_device['deviceType']}" if assettag_column: if 'assetTag' not in remote_device: remote_device['assetTag'] = '' sndt += f"-{remote_device['assetTag']}" remote_devices[sndt] = remote_device remote_device_map[sndt] = {'name': name} if last_sync == NEVER_TIME_NOMS: remote_device_map[sndt]['unassigned'] = True devices_to_add = [] for sndt, device in iter(local_devices.items()): if sndt not in remote_devices: devices_to_add.append(device) missing_devices = [] for sndt, device in iter(remote_devices.items()): if sndt not in local_devices: missing_devices.append(device) print( f'Need to add {len(devices_to_add)} and remove {len(missing_devices)} devices...' ) for add_device in devices_to_add: print(f'Creating {add_device["serialNumber"]}') try: result = gapi.call( ci.devices(), 'create', customer=customer, throw_reasons=[gapi_errors.ErrorReason.FOUR_O_NINE], body=add_device) print( f' created {result["response"]["deviceType"]} device {result["response"]["name"]} with serial {result["response"]["serialNumber"]}' ) except googleapiclient.errors.HttpError: print(f' {add_device["serialNumber"]} already exists') for missing_device in missing_devices: sn = missing_device['serialNumber'] sndt = f"{sn}-{missing_device['deviceType']}" if assettag_column: sndt += f"-{missing_device['assetTag']}" name = remote_device_map[sndt]['name'] unassigned = remote_device_map[sndt].get('unassigned') action = unassigned_missing_action if unassigned else assigned_missing_action if action == 'donothing': pass else: if action == 'delete': kwargs = {'customer': customer} else: kwargs = {'body': {'customer': customer}} gapi.call(ci.devices(), action, name=name, **kwargs) print(f'{action}d {sn}')