mirror of
https://github.com/GAM-team/GAM.git
synced 2025-07-10 14:43:34 +00:00
Device updates (#1247)
* Device updates Make info device consistent with action device: id keyword is optional Add nodeviceusers to print devices pylint cleanup * Fix documentation * Sdd orderby to print devices * Device assetTag cleanup * Fix typo, appease pylint * Strip C from customer ID
This commit is contained in:
@ -158,6 +158,9 @@ If an item contains spaces, it should be surrounded by ".
|
|||||||
<CourseState> ::= active|archived|provisioned|declined
|
<CourseState> ::= active|archived|provisioned|declined
|
||||||
<CrOSID> ::= <String>
|
<CrOSID> ::= <String>
|
||||||
<CustomerID> ::= <String>
|
<CustomerID> ::= <String>
|
||||||
|
<DeviceID> ::= devices/<String>
|
||||||
|
<DeviceType> ::= android|chrome_os|google_sync|ios|linux|mac_os|windows
|
||||||
|
<DeviceUserID> ::= devices/<String>/deviceUsers/<String>
|
||||||
<DomainAlias> ::= <String>
|
<DomainAlias> ::= <String>
|
||||||
<DriveFileACLRole> ::= commenter|contentmanager|editor|fileorganizer|organizer|owner|reader|writer
|
<DriveFileACLRole> ::= commenter|contentmanager|editor|fileorganizer|organizer|owner|reader|writer
|
||||||
<DriveFileID> ::= <String>
|
<DriveFileID> ::= <String>
|
||||||
@ -1127,6 +1130,35 @@ The listlimit <Number> argument limits the number of recent users, time ranges a
|
|||||||
The start <Date> and end <Date> arguments filter the time ranges.
|
The start <Date> and end <Date> arguments filter the time ranges.
|
||||||
Delimiter defaults to comma.
|
Delimiter defaults to comma.
|
||||||
|
|
||||||
|
<DeviceID> ::= devices/<String>
|
||||||
|
<DeviceType> ::= android|chrome_os|google_sync|ios|linux|mac_os|windows
|
||||||
|
<DeviceUserID> ::= devices/<String>/deviceUsers/<String>
|
||||||
|
<DeviceOrderbyFieldName> ::=
|
||||||
|
createtime|devicetype|lastsynctime|model|osversion|serialnumber
|
||||||
|
|
||||||
|
gam create device serialnumber <String> devicetype <DeviceType> [assetid <String>]
|
||||||
|
gam info device [id] <DeviceID>
|
||||||
|
gam delete device [id] <DeviceID>
|
||||||
|
gam cancelwipe device [id] <DeviceID>
|
||||||
|
gam wipe device [id] <DeviceID>
|
||||||
|
gam approve deviceuser [id] <DeviceUserID>
|
||||||
|
gam block deviceuser [id] <DeviceUserID>
|
||||||
|
gam delete deviceuser [id] <DeviceUserID>
|
||||||
|
gam cancelwipe deviceuser [id] <DeviceUserID>
|
||||||
|
gam wipe deviceuser [id] <DeviceUserID>
|
||||||
|
gam print devices [todrive] [query <QueryDevice>]
|
||||||
|
[orderby <DeviceOrderByFieldName> [ascending|descending]]
|
||||||
|
[nocompanydevices] [nouserdevices] [nousers]
|
||||||
|
[formatjson [quotechar <Character>]]
|
||||||
|
gam sync devices
|
||||||
|
csvfile <FileName>
|
||||||
|
[serialnumber_column <String>]
|
||||||
|
[devicetype_column <String>]
|
||||||
|
[assetid_column <String>]
|
||||||
|
[static_devicetype <DeviceType>]
|
||||||
|
[unassigned_missing_action delete|wipe|nonothing]
|
||||||
|
[assigned_missing_action delete|wipe|nonothing]
|
||||||
|
|
||||||
gam update mobile <MobileID>|query:<QueryMobile> action <MobileAction> [doit] [if_users|match_users <UserTypeEntity>]
|
gam update mobile <MobileID>|query:<QueryMobile> action <MobileAction> [doit] [if_users|match_users <UserTypeEntity>]
|
||||||
gam delete mobile <MobileID>
|
gam delete mobile <MobileID>
|
||||||
gam info mobile <MobileID>
|
gam info mobile <MobileID>
|
||||||
|
@ -3,7 +3,6 @@ import sys
|
|||||||
|
|
||||||
import googleapiclient
|
import googleapiclient
|
||||||
|
|
||||||
import gam
|
|
||||||
from gam.var import *
|
from gam.var import *
|
||||||
from gam import controlflow
|
from gam import controlflow
|
||||||
from gam import display
|
from gam import display
|
||||||
@ -12,16 +11,20 @@ from gam import gapi
|
|||||||
from gam import utils
|
from gam import utils
|
||||||
from gam.gapi import errors as gapi_errors
|
from gam.gapi import errors as gapi_errors
|
||||||
from gam.gapi import cloudidentity as gapi_cloudidentity
|
from gam.gapi import cloudidentity as gapi_cloudidentity
|
||||||
from gam.gapi.directory import customer as gapi_directory_customer
|
|
||||||
from gam.gapi.directory import groups as gapi_directory_groups
|
|
||||||
|
|
||||||
|
|
||||||
|
def _get_device_customerid():
|
||||||
|
customer = GC_Values[GC_CUSTOMER_ID]
|
||||||
|
if customer.startswith('C'):
|
||||||
|
customer = customer[1:]
|
||||||
|
return f'customers/{customer}'
|
||||||
|
|
||||||
def create():
|
def create():
|
||||||
ci = gapi_cloudidentity.build_dwd()
|
ci = gapi_cloudidentity.build_dwd()
|
||||||
customer = f'customers/{GC_Values[GC_CUSTOMER_ID]}'
|
customer = _get_device_customerid()
|
||||||
device_types = gapi.get_enum_values_minus_unspecified(
|
device_types = gapi.get_enum_values_minus_unspecified(
|
||||||
ci._rootDesc['schemas']['GoogleAppsCloudidentityDevicesV1Device']['properties']['deviceType']['enum'])
|
ci._rootDesc['schemas']['GoogleAppsCloudidentityDevicesV1Device']['properties']['deviceType']['enum'])
|
||||||
body = {}
|
body = {'deviceType': '', 'serialNumber': ''}
|
||||||
i = 3
|
i = 3
|
||||||
while i < len(sys.argv):
|
while i < len(sys.argv):
|
||||||
myarg = sys.argv[i].lower().replace('_', '')
|
myarg = sys.argv[i].lower().replace('_', '')
|
||||||
@ -35,20 +38,30 @@ def create():
|
|||||||
', '.join(device_types),
|
', '.join(device_types),
|
||||||
sys.argv[i+1])
|
sys.argv[i+1])
|
||||||
i += 2
|
i += 2
|
||||||
|
elif myarg in {'assettag', 'assetid'}:
|
||||||
|
body['assetTag'] = sys.argv[i+1]
|
||||||
|
i += 2
|
||||||
else:
|
else:
|
||||||
controlflow.invalid_argument_exit(sys.argv[i], 'gam create device')
|
controlflow.invalid_argument_exit(sys.argv[i], 'gam create device')
|
||||||
if not body.get('serialNumber') or not body.get('deviceType'):
|
if not body['serialNumber'] or not body['deviceType']:
|
||||||
controlflow.system_error_exit(
|
controlflow.system_error_exit(
|
||||||
3, 'serial_number and device_type are required arguments for "gam create device".')
|
3, 'serial_number and device_type are required arguments for "gam create device".')
|
||||||
result = gapi.call(ci.devices(), 'create', customer=customer, body=body)
|
result = gapi.call(ci.devices(), 'create', customer=customer, body=body)
|
||||||
print(f'Created device {result["response"]["name"]}')
|
print(f'Created device {result["response"]["name"]}')
|
||||||
|
|
||||||
def info():
|
def _get_device_name():
|
||||||
ci = gapi_cloudidentity.build_dwd()
|
|
||||||
customer = f'customers/{GC_Values[GC_CUSTOMER_ID]}'
|
|
||||||
name = sys.argv[3]
|
name = sys.argv[3]
|
||||||
|
if name == 'id':
|
||||||
|
name = sys.argv[4]
|
||||||
if not name.startswith('devices/'):
|
if not name.startswith('devices/'):
|
||||||
name = f'devices/{name}'
|
name = f'devices/{name}'
|
||||||
|
return name
|
||||||
|
|
||||||
|
|
||||||
|
def info():
|
||||||
|
ci = gapi_cloudidentity.build_dwd()
|
||||||
|
customer = _get_device_customerid()
|
||||||
|
name = _get_device_name()
|
||||||
device = gapi.call(ci.devices(), 'get', name=name, customer=customer)
|
device = gapi.call(ci.devices(), 'get', name=name, customer=customer)
|
||||||
device_users = gapi.get_all_pages(ci.devices().deviceUsers(), 'list',
|
device_users = gapi.get_all_pages(ci.devices().deviceUsers(), 'list',
|
||||||
'deviceUsers', parent=name, customer=customer)
|
'deviceUsers', parent=name, customer=customer)
|
||||||
@ -58,7 +71,8 @@ def info():
|
|||||||
|
|
||||||
def _generic_action(action, device_user=False):
|
def _generic_action(action, device_user=False):
|
||||||
ci = gapi_cloudidentity.build_dwd()
|
ci = gapi_cloudidentity.build_dwd()
|
||||||
customer = f'customers/{GC_Values[GC_CUSTOMER_ID]}'
|
customer = _get_device_customerid()
|
||||||
|
name = _get_device_name()
|
||||||
|
|
||||||
# bah, inconsistencies in API
|
# bah, inconsistencies in API
|
||||||
if action == 'delete':
|
if action == 'delete':
|
||||||
@ -70,20 +84,6 @@ def _generic_action(action, device_user=False):
|
|||||||
endpoint = ci.devices().deviceUsers()
|
endpoint = ci.devices().deviceUsers()
|
||||||
else:
|
else:
|
||||||
endpoint = ci.devices()
|
endpoint = ci.devices()
|
||||||
name = None
|
|
||||||
i = 3
|
|
||||||
while i < len(sys.argv):
|
|
||||||
myarg = sys.argv[i].lower().replace('_', '')
|
|
||||||
# The API calls it "name" but GAM will expose as "id" to avoid admin confusion.
|
|
||||||
if myarg == 'id':
|
|
||||||
name = sys.argv[i+1]
|
|
||||||
if not name.startswith('devices/'):
|
|
||||||
name = f'devices/{name}'
|
|
||||||
i += 2
|
|
||||||
else:
|
|
||||||
controlflow.invalid_argument_exit(sys.argv[i], f'gam {action} device')
|
|
||||||
if not name:
|
|
||||||
controlflow.system_error_exit(3, f'id is a required argument for "gam {action} device".')
|
|
||||||
op = gapi.call(endpoint, action, name=name, **kwargs)
|
op = gapi.call(endpoint, action, name=name, **kwargs)
|
||||||
print(op)
|
print(op)
|
||||||
|
|
||||||
@ -113,11 +113,12 @@ def wipe_user():
|
|||||||
|
|
||||||
def print_():
|
def print_():
|
||||||
ci = gapi_cloudidentity.build_dwd()
|
ci = gapi_cloudidentity.build_dwd()
|
||||||
customer = f'customers/{GC_Values[GC_CUSTOMER_ID]}'
|
customer = _get_device_customerid()
|
||||||
parent = 'devices/-'
|
parent = 'devices/-'
|
||||||
device_filter = None
|
device_filter = None
|
||||||
get_device_users = True
|
get_device_users = True
|
||||||
get_device_views = ['COMPANY_INVENTORY', 'USER_ASSIGNED_DEVICES']
|
get_device_views = ['COMPANY_INVENTORY', 'USER_ASSIGNED_DEVICES']
|
||||||
|
orderByList = []
|
||||||
titles = []
|
titles = []
|
||||||
csvRows = []
|
csvRows = []
|
||||||
todrive = False
|
todrive = False
|
||||||
@ -134,9 +135,31 @@ def print_():
|
|||||||
elif myarg == 'nopersonaldevices':
|
elif myarg == 'nopersonaldevices':
|
||||||
get_device_views.remove('USER_ASSIGNED_DEVICES')
|
get_device_views.remove('USER_ASSIGNED_DEVICES')
|
||||||
i += 1
|
i += 1
|
||||||
|
elif myarg == 'nodeviceusers':
|
||||||
|
get_device_users = False
|
||||||
|
i += 1
|
||||||
elif myarg == 'todrive':
|
elif myarg == 'todrive':
|
||||||
todrive = True
|
todrive = True
|
||||||
i += 1
|
i += 1
|
||||||
|
elif myarg == 'orderby':
|
||||||
|
fieldName = sys.argv[i + 1].lower()
|
||||||
|
i += 2
|
||||||
|
if fieldName in DEVICE_ORDERBY_CHOICES_MAP:
|
||||||
|
fieldName = DEVICE_ORDERBY_CHOICES_MAP[fieldName]
|
||||||
|
orderBy = ''
|
||||||
|
if i < len(sys.argv):
|
||||||
|
orderBy = sys.argv[i].lower()
|
||||||
|
if orderBy in SORTORDER_CHOICES_MAP:
|
||||||
|
orderBy = SORTORDER_CHOICES_MAP[orderBy]
|
||||||
|
i += 1
|
||||||
|
if orderBy != 'DESCENDING':
|
||||||
|
orderByList.append(fieldName)
|
||||||
|
else:
|
||||||
|
orderByList.append(f'{fieldName} desc')
|
||||||
|
else:
|
||||||
|
controlflow.expected_argument_exit(
|
||||||
|
'orderby', ', '.join(sorted(DEVICE_ORDERBY_CHOICES_MAP)),
|
||||||
|
fieldName)
|
||||||
elif myarg == 'sortheaders':
|
elif myarg == 'sortheaders':
|
||||||
sortHeaders = True
|
sortHeaders = True
|
||||||
i += 1
|
i += 1
|
||||||
@ -146,13 +169,17 @@ def print_():
|
|||||||
'COMPANY_INVENTORY': 'Company Devices',
|
'COMPANY_INVENTORY': 'Company Devices',
|
||||||
'USER_ASSIGNED_DEVICES': 'Personal Devices',
|
'USER_ASSIGNED_DEVICES': 'Personal Devices',
|
||||||
}
|
}
|
||||||
|
if orderByList:
|
||||||
|
orderBy = ','.join(orderByList)
|
||||||
|
else:
|
||||||
|
orderBy = None
|
||||||
devices = []
|
devices = []
|
||||||
for view in get_device_views:
|
for view in get_device_views:
|
||||||
view_name = view_name_map.get(view, 'Devices')
|
view_name = view_name_map.get(view, 'Devices')
|
||||||
page_message = gapi.got_total_items_msg(view_name, '...\n')
|
page_message = gapi.got_total_items_msg(view_name, '...\n')
|
||||||
devices += gapi.get_all_pages(ci.devices(), 'list', 'devices',
|
devices += gapi.get_all_pages(ci.devices(), 'list', 'devices',
|
||||||
customer=customer, page_message=page_message,
|
customer=customer, page_message=page_message,
|
||||||
pageSize=100, filter=device_filter, view=view)
|
pageSize=100, filter=device_filter, view=view, orderBy=orderBy)
|
||||||
if get_device_users:
|
if get_device_users:
|
||||||
page_message = gapi.got_total_items_msg('Device Users', '...\n')
|
page_message = gapi.got_total_items_msg('Device Users', '...\n')
|
||||||
device_users = gapi.get_all_pages(ci.devices().deviceUsers(), 'list',
|
device_users = gapi.get_all_pages(ci.devices().deviceUsers(), 'list',
|
||||||
@ -180,13 +207,13 @@ def sync():
|
|||||||
ci = gapi_cloudidentity.build_dwd()
|
ci = gapi_cloudidentity.build_dwd()
|
||||||
device_types = gapi.get_enum_values_minus_unspecified(
|
device_types = gapi.get_enum_values_minus_unspecified(
|
||||||
ci._rootDesc['schemas']['GoogleAppsCloudidentityDevicesV1Device']['properties']['deviceType']['enum'])
|
ci._rootDesc['schemas']['GoogleAppsCloudidentityDevicesV1Device']['properties']['deviceType']['enum'])
|
||||||
customer = f'customers/{GC_Values[GC_CUSTOMER_ID]}'
|
customer = _get_device_customerid()
|
||||||
device_filter = None
|
device_filter = None
|
||||||
csv_file = None
|
csv_file = None
|
||||||
serialnumber_column = 'serialNumber'
|
serialnumber_column = 'serialNumber'
|
||||||
devicetype_column = 'deviceType'
|
devicetype_column = 'deviceType'
|
||||||
static_devicetype = None
|
static_devicetype = None
|
||||||
assetid_column = None
|
assettag_column = None
|
||||||
unassigned_missing_action = 'delete'
|
unassigned_missing_action = 'delete'
|
||||||
assigned_missing_action = 'donothing'
|
assigned_missing_action = 'donothing'
|
||||||
missing_actions = ['delete', 'wipe', 'donothing']
|
missing_actions = ['delete', 'wipe', 'donothing']
|
||||||
@ -212,8 +239,8 @@ def sync():
|
|||||||
', '.join(device_types),
|
', '.join(device_types),
|
||||||
sys.argv[i+1])
|
sys.argv[i+1])
|
||||||
i += 2
|
i += 2
|
||||||
elif myarg == 'assetidcolumn':
|
elif myarg in {'assettagcolumn', 'assetidcolumn'}:
|
||||||
assetid_column = sys.argv[i+1]
|
assettag_column = sys.argv[i+1]
|
||||||
i += 2
|
i += 2
|
||||||
elif myarg == 'unassignedmissingaction':
|
elif myarg == 'unassignedmissingaction':
|
||||||
unassigned_missing_action = sys.argv[i+1].lower().replace('_', '')
|
unassigned_missing_action = sys.argv[i+1].lower().replace('_', '')
|
||||||
@ -240,8 +267,8 @@ def sync():
|
|||||||
controlflow.csv_field_error_exit(serialnumber_column, 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:
|
if not static_devicetype and devicetype_column not in input_file.fieldnames:
|
||||||
controlflow.csv_field_error_exit(devicetype_column, input_file.fieldnames)
|
controlflow.csv_field_error_exit(devicetype_column, input_file.fieldnames)
|
||||||
if assetid_column and assetid_column not in input_file.fieldnames:
|
if assettag_column and assettag_column not in input_file.fieldnames:
|
||||||
controlflow.csv_field_error_exit(assetid_column, input_file.fieldnames)
|
controlflow.csv_field_error_exit(assettag_column, input_file.fieldnames)
|
||||||
local_devices = []
|
local_devices = []
|
||||||
for row in input_file:
|
for row in input_file:
|
||||||
# upper() is very important to comparison since Google
|
# upper() is very important to comparison since Google
|
||||||
@ -252,13 +279,13 @@ def sync():
|
|||||||
local_device['deviceType'] = static_devicetype
|
local_device['deviceType'] = static_devicetype
|
||||||
else:
|
else:
|
||||||
local_device['deviceType'] = row[devicetype_column].strip()
|
local_device['deviceType'] = row[devicetype_column].strip()
|
||||||
if assetid_column:
|
if assettag_column:
|
||||||
local_device['assetTag'] = row[assetid_column].strip()
|
local_device['assetTag'] = row[assettag_column].strip()
|
||||||
local_devices.append(local_device)
|
local_devices.append(local_device)
|
||||||
fileutils.close_file(f)
|
fileutils.close_file(f)
|
||||||
page_message = gapi.got_total_items_msg('Company Devices', '...\n')
|
page_message = gapi.got_total_items_msg('Company Devices', '...\n')
|
||||||
device_fields = ['serialNumber', 'deviceType', 'lastSyncTime', 'name']
|
device_fields = ['serialNumber', 'deviceType', 'lastSyncTime', 'name']
|
||||||
if assetid_column:
|
if assettag_column:
|
||||||
device_fields.append('assetTag')
|
device_fields.append('assetTag')
|
||||||
fields = f'nextPageToken,devices({",".join(device_fields)})'
|
fields = f'nextPageToken,devices({",".join(device_fields)})'
|
||||||
remote_devices = gapi.get_all_pages(ci.devices(), 'list', 'devices',
|
remote_devices = gapi.get_all_pages(ci.devices(), 'list', 'devices',
|
||||||
|
@ -367,6 +367,15 @@ CALENDAR_NOTIFICATION_TYPES_MAP = {
|
|||||||
'agenda': 'agenda',
|
'agenda': 'agenda',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEVICE_ORDERBY_CHOICES_MAP = {
|
||||||
|
'createtime': 'create_time',
|
||||||
|
'devicetype': 'device_type',
|
||||||
|
'lastsynctime': 'last_sync_time',
|
||||||
|
'model': 'model',
|
||||||
|
'osversion': 'os_version',
|
||||||
|
'serialnumber': 'serial_number'
|
||||||
|
}
|
||||||
|
|
||||||
DRIVEFILE_FIELDS_CHOICES_MAP = {
|
DRIVEFILE_FIELDS_CHOICES_MAP = {
|
||||||
'alternatelink': 'alternateLink',
|
'alternatelink': 'alternateLink',
|
||||||
'appdatacontents': 'appDataContents',
|
'appdatacontents': 'appDataContents',
|
||||||
|
Reference in New Issue
Block a user