break out reports, customer and cros

This commit is contained in:
Jay Lee
2020-03-10 21:47:22 -04:00
parent 4213b4739e
commit 5d02d73737
7 changed files with 1245 additions and 1323 deletions

View File

@@ -1,256 +0,0 @@
{
"acer ac700": "2016-08-01T00:00:00.000Z",
"acer c7 chromebook": "2017-10-01T00:00:00.000Z",
"acer c7 chromebook (c710)": "2017-10-01T00:00:00.000Z",
"acer c720 chromebook": "2019-06-01T00:00:00.000Z",
"acer c740 chromebook": "2019-06-01T00:00:00.000Z",
"acer chromebase": "2020-08-01T00:00:00.000Z",
"acer chromebase 24": "2021-06-01T00:00:00.000Z",
"acer chromebook 11 (c720, c720p)": "2019-06-01T00:00:00.000Z",
"acer chromebook 11 (c732, c732t, c732l, c732lt)": "2023-11-01T00:00:00.000Z",
"acer chromebook 11 (c740)": "2020-06-01T00:00:00.000Z",
"acer chromebook 11 (c771, c771t)": "2022-11-01T00:00:00.000Z",
"acer chromebook 11 (cb3-111, c730, c730e)": "2019-08-01T00:00:00.000Z",
"acer chromebook 11 (cb3-131, c735)": "2021-01-01T00:00:00.000Z",
"acer chromebook 11 (cb311-8h, cb311-8ht)": "2023-11-01T00:00:00.000Z",
"acer chromebook 11 n7 (c731, c731t)": "2022-01-01T00:00:00.000Z",
"acer chromebook 13 (cb5-311)": "2019-09-01T00:00:00.000Z",
"acer chromebook 13 (cb713-1w)": "2024-06-01T00:00:00.000Z",
"acer chromebook 13(cb5-311, c810)": "2019-09-01T00:00:00.000Z",
"acer chromebook 14 (cb3-431)": "2021-06-01T00:00:00.000Z",
"acer chromebook 14 for work (cp5-471)": "2022-11-01T00:00:00.000Z",
"acer chromebook 15 (c910 / cb5-571)": "2020-06-01T00:00:00.000Z",
"acer chromebook 15 (cb3-531)": "2020-06-01T00:00:00.000Z",
"acer chromebook 15 (cb3-532)": "2021-08-01T00:00:00.000Z",
"acer chromebook 15 (cb315-1h,cb315-1ht)": "2023-11-01T00:00:00.000Z",
"acer chromebook 15 (cb5-571, c910)": "2020-06-01T00:00:00.000Z",
"acer chromebook 15 (cb515-1h,cb515-1ht)": "2023-11-01T00:00:00.000Z",
"acer chromebook 311": "2025-06-01T00:00:00.000Z",
"acer chromebook 311 (c721, c733, c733u, c733t)": "2025-06-01T00:00:00.000Z",
"acer chromebook 315": "2025-06-01T00:00:00.000Z",
"acer chromebook 315 (cb315-2h)": "2025-06-01T00:00:00.000Z",
"acer chromebook 512 (c851, c851t)": "2025-06-01T00:00:00.000Z",
"acer chromebook 514": "2023-11-01T00:00:00.000Z",
"acer chromebook 714 (cb714-1w / cb714-1wt)": "2024-06-01T00:00:00.000Z",
"acer chromebook 715 (cb715-1w / cb715-1wt)": "2024-06-01T00:00:00.000Z",
"acer chromebook r11 (cb5-132t, c738t)": "2021-06-01T00:00:00.000Z",
"acer chromebook r13 (cb5-312t)": "2021-09-01T00:00:00.000Z",
"acer chromebook spin 11 (cp311-h1, cp311-1hn)": "2023-11-01T00:00:00.000Z",
"acer chromebook spin 11 (r751t)": "2023-11-01T00:00:00.000Z",
"acer chromebook spin 13 (cp713-1wn)": "2024-06-01T00:00:00.000Z",
"acer chromebook spin 15 (cp315)": "2023-11-01T00:00:00.000Z",
"acer chromebook spin 311 (r721t)": "2025-06-01T00:00:00.000Z",
"acer chromebook spin 511": "2025-06-01T00:00:00.000Z",
"acer chromebook spin 511 (r752t, r752tn)": "2025-06-01T00:00:00.000Z",
"acer chromebook spin 512 (r851tn)": "2025-06-01T00:00:00.000Z",
"acer chromebook tab 10": "2023-08-01T00:00:00.000Z",
"acer chromebox": "2019-09-01T00:00:00.000Z",
"acer chromebox cxi2": "2020-06-01T00:00:00.000Z",
"acer chromebox cxi2 / cxv2": "2020-06-01T00:00:00.000Z",
"acer chromebox cxi3": "2024-06-01T00:00:00.000Z",
"aopen chromebase commercial": "2020-09-01T00:00:00.000Z",
"aopen chromebase mini": "2022-02-01T00:00:00.000Z",
"aopen chromebox commercial": "2020-09-01T00:00:00.000Z",
"aopen chromebox commercial 2": "2024-06-01T00:00:00.000Z",
"aopen chromebox mini": "2022-02-01T00:00:00.000Z",
"asi chromebook": "2020-06-01T00:00:00.000Z",
"asus chromebit cs10": "2020-11-01T00:00:00.000Z",
"asus chromebook c200": "2019-06-01T00:00:00.000Z",
"asus chromebook c200ma": "2019-06-01T00:00:00.000Z",
"asus chromebook c201pa": "2020-06-01T00:00:00.000Z",
"asus chromebook c202sa": "2021-06-01T00:00:00.000Z",
"asus chromebook c204": "2025-06-01T00:00:00.000Z",
"asus chromebook c213na": "2023-11-01T00:00:00.000Z",
"asus chromebook c223": "2023-11-01T00:00:00.000Z",
"asus chromebook c300": "2019-08-01T00:00:00.000Z",
"asus chromebook c300ma": "2019-08-01T00:00:00.000Z",
"asus chromebook c300sa / c301sa": "2021-06-01T00:00:00.000Z",
"asus chromebook c403": "2023-11-01T00:00:00.000Z",
"asus chromebook c423": "2023-11-01T00:00:00.000Z",
"asus chromebook c523": "2023-11-01T00:00:00.000Z",
"asus chromebook flip c100pa": "2020-07-01T00:00:00.000Z",
"asus chromebook flip c101pa": "2023-08-01T00:00:00.000Z",
"asus chromebook flip c213": "2023-11-01T00:00:00.000Z",
"asus chromebook flip c214": "2025-06-01T00:00:00.000Z",
"asus chromebook flip c302": "2022-11-01T00:00:00.000Z",
"asus chromebook flip c434": "2024-06-01T00:00:00.000Z",
"asus chromebook tablet ct100": "2023-08-01T00:00:00.000Z",
"asus chromebox (cn60)": "2019-09-01T00:00:00.000Z",
"asus chromebox 2 (cn62)": "2021-06-01T00:00:00.000Z",
"asus chromebox 3": "2024-06-01T00:00:00.000Z",
"asus chromebox 3 (cn65)": "2024-06-01T00:00:00.000Z",
"asus chromebox cn60": "2019-09-01T00:00:00.000Z",
"asus chromebox cn62": "2021-06-01T00:00:00.000Z",
"bobicus chromebook 11": "2020-06-01T00:00:00.000Z",
"chromebook 11 (c730 / cb3-111)": "2019-08-01T00:00:00.000Z",
"chromebook 11 (c735)": "2021-01-01T00:00:00.000Z",
"chromebook 15 (cb515 - 1ht / 1h)": "2023-11-01T00:00:00.000Z",
"chromebook 311 (c721)": "2025-06-01T00:00:00.000Z",
"chromebook pcm-116e": "2020-06-01T00:00:00.000Z",
"consumer chromebook": "2020-06-01T00:00:00.000Z",
"cr-48": "2015-12-01T00:00:00.000Z",
"crambo chromebook": "2020-06-01T00:00:00.000Z",
"ctl chromebook j41 / j41t": "2023-11-01T00:00:00.000Z",
"ctl chromebook nl7": "2023-11-01T00:00:00.000Z",
"ctl chromebook nl7t-360 / nl7tw-360": "2023-11-01T00:00:00.000Z",
"ctl chromebook tab tx1": "2023-08-01T00:00:00.000Z",
"ctl chromebook tablet tx1 for education": "2023-08-01T00:00:00.000Z",
"ctl chromebox cbx1": "2024-06-01T00:00:00.000Z",
"ctl j2 / j4 chromebook": "2020-06-01T00:00:00.000Z",
"ctl j5 chromebook": "2021-08-01T00:00:00.000Z",
"ctl n6 education chromebook": "2020-06-01T00:00:00.000Z",
"ctl nl61 chromebook": "2021-08-01T00:00:00.000Z",
"dell chromebook 11": "2019-06-01T00:00:00.000Z",
"dell chromebook 11 (3120)": "2020-06-01T00:00:00.000Z",
"dell chromebook 11 (3180)": "2022-05-01T00:00:00.000Z",
"dell chromebook 11 (5190)": "2023-11-01T00:00:00.000Z",
"dell chromebook 11 2-in-1 (3189)": "2022-05-01T00:00:00.000Z",
"dell chromebook 11 2-in-1 (5190)": "2023-11-01T00:00:00.000Z",
"dell chromebook 13 (3380)": "2022-11-01T00:00:00.000Z",
"dell chromebook 13 (7310)": "2020-09-01T00:00:00.000Z",
"dell chromebook 3100": "2025-06-01T00:00:00.000Z",
"dell chromebook 3100 2-in-1": "2025-06-01T00:00:00.000Z",
"dell chromebook 3400": "2025-06-01T00:00:00.000Z",
"dell chromebox": "2019-09-01T00:00:00.000Z",
"dell inspiron chromebook 14 2-in-1 (7486)": "2024-06-01T00:00:00.000Z",
"edugear chromebook k": "2020-06-01T00:00:00.000Z",
"edugear chromebook m": "2020-06-01T00:00:00.000Z",
"edugear chromebook r": "2020-06-01T00:00:00.000Z",
"edugear cmt chromebook": "2021-08-01T00:00:00.000Z",
"edxis chromebook": "2020-06-01T00:00:00.000Z",
"edxis education chromebook": "2020-06-01T00:00:00.000Z",
"epik 11.6\" chromebook elb1101": "2020-06-01T00:00:00.000Z",
"google chromebook pixel": "2018-06-01T00:00:00.000Z",
"google chromebook pixel (2015)": "2020-06-01T00:00:00.000Z",
"google cr-48": "2015-12-01T00:00:00.000Z",
"google pixel slate": "2024-06-01T00:00:00.000Z",
"google pixelbook": "2024-06-01T00:00:00.000Z",
"haier chromebook 11": "2020-06-01T00:00:00.000Z",
"haier chromebook 11 c": "2021-08-01T00:00:00.000Z",
"haier chromebook 11 g2": "2020-09-01T00:00:00.000Z",
"haier chromebook 11e": "2020-06-01T00:00:00.000Z",
"hexa chromebook pi": "2020-06-01T00:00:00.000Z",
"hisense chromebook 11": "2020-06-01T00:00:00.000Z",
"hp chromebook 11 1100-1199 / hp chromebook 11 g1": "2018-10-01T00:00:00.000Z",
"hp chromebook 11 2000-2099 / hp chromebook 11 g2": "2019-06-01T00:00:00.000Z",
"hp chromebook 11 2100-2199 / hp chromebook 11 g3": "2020-06-01T00:00:00.000Z",
"hp chromebook 11 2200-2299 / hp chromebook 11 g4/g4 ee": "2020-06-01T00:00:00.000Z",
"hp chromebook 11 g1": "2018-10-01T00:00:00.000Z",
"hp chromebook 11 g2": "2019-06-01T00:00:00.000Z",
"hp chromebook 11 g3": "2020-06-01T00:00:00.000Z",
"hp chromebook 11 g4/g4 ee": "2020-06-01T00:00:00.000Z",
"hp chromebook 11 g5": "2021-07-01T00:00:00.000Z",
"hp chromebook 11 g5 / hp chromebook 11-vxxx": "2021-07-01T00:00:00.000Z",
"hp chromebook 11 g5 ee": "2022-01-01T00:00:00.000Z",
"hp chromebook 11 g6 ee": "2023-11-01T00:00:00.000Z",
"hp chromebook 11 g7 ee": "2025-06-01T00:00:00.000Z",
"hp chromebook 11a g6 ee": "2025-06-01T00:00:00.000Z",
"hp chromebook 13 g1": "2022-11-01T00:00:00.000Z",
"hp chromebook 14": "2019-06-01T00:00:00.000Z",
"hp chromebook 14 / hp chromebook 14 g5": "2023-11-01T00:00:00.000Z",
"hp chromebook 14 ak000-099 / hp chromebook 14 g4": "2021-09-01T00:00:00.000Z",
"hp chromebook 14 db0000-db0999": "2025-06-01T00:00:00.000Z",
"hp chromebook 14 g3": "2019-10-01T00:00:00.000Z",
"hp chromebook 14 g4": "2021-09-01T00:00:00.000Z",
"hp chromebook 14 g5": "2023-11-01T00:00:00.000Z",
"hp chromebook 14 x000-x999 / hp chromebook 14 g3": "2019-10-01T00:00:00.000Z",
"hp chromebook 14a g5": "2025-06-01T00:00:00.000Z",
"hp chromebook 15 g1": "2024-06-01T00:00:00.000Z",
"hp chromebook x2 ": "2024-06-01T00:00:00.000Z",
"hp chromebook x360 11 g1 ee": "2023-11-01T00:00:00.000Z",
"hp chromebook x360 11 g2 ee": "2025-06-01T00:00:00.000Z",
"hp chromebook x360 14": "2024-06-01T00:00:00.000Z",
"hp chromebook x360 14 g1": "2024-06-01T00:00:00.000Z",
"hp chromebox cb1-(000-099) / hp chromebox g1/ hp chromebox for meetings": "2019-09-01T00:00:00.000Z",
"hp chromebox g1": "2019-09-01T00:00:00.000Z",
"hp chromebox g2": "2024-06-01T00:00:00.000Z",
"hp pavilion chromebook 14": "2018-02-01T00:00:00.000Z",
"jp sa couto chromebook": "2020-06-01T00:00:00.000Z",
"lava xolo chromebook": "2020-06-01T00:00:00.000Z",
"lenovo 100e chromebook": "2023-11-01T00:00:00.000Z",
"lenovo 100e chromebook 2nd gen": "2025-06-01T00:00:00.000Z",
"lenovo 100e chromebook 2nd gen mtk": "2025-06-01T00:00:00.000Z",
"lenovo 100s chromebook": "2020-09-01T00:00:00.000Z",
"lenovo 14e chromebook": "2025-06-01T00:00:00.000Z",
"lenovo 300e chromebook": "2025-06-01T00:00:00.000Z",
"lenovo 300e chromebook 2nd gen": "2025-06-01T00:00:00.000Z",
"lenovo 300e chromebook 2nd gen mtk": "2025-06-01T00:00:00.000Z",
"lenovo 500e chromebook": "2023-11-01T00:00:00.000Z",
"lenovo 500e chromebook 2nd gen": "2025-06-01T00:00:00.000Z",
"lenovo chromebook c330": "2022-06-01T00:00:00.000Z",
"lenovo chromebook s330": "2022-06-01T00:00:00.000Z",
"lenovo flex 11 chromebook": "2022-06-01T00:00:00.000Z",
"lenovo ideapad c330 chromebook": "2022-06-01T00:00:00.000Z",
"lenovo ideapad s330 chromebook": "2022-06-01T00:00:00.000Z",
"lenovo n20 chromebook": "2019-06-01T00:00:00.000Z",
"lenovo n21 chromebook": "2020-06-01T00:00:00.000Z",
"lenovo n22 chromebook": "2021-06-01T00:00:00.000Z",
"lenovo n23 chromebook": "2021-06-01T00:00:00.000Z",
"lenovo n23 yoga chromebook": "2022-06-01T00:00:00.000Z",
"lenovo n42 chromebook": "2021-06-01T00:00:00.000Z",
"lenovo thinkcentre chromebox": "2020-06-01T00:00:00.000Z",
"lenovo thinkpad 11e 3rd gen chromebook": "2021-06-01T00:00:00.000Z",
"lenovo thinkpad 11e 4th gen chromebook": "2023-11-01T00:00:00.000Z",
"lenovo thinkpad 11e chromebook": "2019-06-01T00:00:00.000Z",
"lenovo thinkpad 11e chromebook (4th gen)/lenovo thinkpad yoga 11e chromebook (4th gen)": "2023-11-01T00:00:00.000Z",
"lenovo thinkpad 13": "2022-11-01T00:00:00.000Z",
"lenovo thinkpad x131e chromebook": "2018-06-01T00:00:00.000Z",
"lenovo yoga c630 chromebook": "2024-06-01T00:00:00.000Z",
"lg chromebase (22cb25s)": "2020-06-01T00:00:00.000Z",
"lg chromebase (22cv241)": "2019-06-01T00:00:00.000Z",
"lumos education chromebook": "2020-06-01T00:00:00.000Z",
"m&a chromebook": "2020-06-01T00:00:00.000Z",
"mecer chromebook": "2020-06-01T00:00:00.000Z",
"mecer v2 chromebook": "2021-08-01T00:00:00.000Z",
"medion chromebook akoya s2013 ": "2020-06-01T00:00:00.000Z",
"medion chromebook s2015": "2020-06-01T00:00:00.000Z",
"multilaser chromebook m11c": "2021-08-01T00:00:00.000Z",
"ncomputing chromebook cx100": "2020-06-01T00:00:00.000Z",
"ncomputing chromebook cx110": "2020-06-01T00:00:00.000Z",
"nexian chromebook 11.6\"": "2020-06-01T00:00:00.000Z",
"pcmerge chromebook al116": "2023-11-01T00:00:00.000Z",
"pcmerge chromebookpcm-116e/pcm-116eb": "2020-06-01T00:00:00.000Z",
"pcmerge chromebookpcm-116t-432b": "2021-08-01T00:00:00.000Z",
"poin2 chromebook 11": "2020-06-01T00:00:00.000Z",
"poin2 chromebook 11c": "2022-11-01T00:00:00.000Z",
"poin2 chromebook 14": "2022-03-01T00:00:00.000Z",
"positivo chromebook c216b": "2021-08-01T00:00:00.000Z",
"positivo chromebook ch1190": "2020-06-01T00:00:00.000Z",
"promethean chromebox": "2024-06-01T00:00:00.000Z",
"prowise 11.6\" entry line chromebook": "2020-06-01T00:00:00.000Z",
"prowise chromebook eduline": "2023-11-01T00:00:00.000Z",
"prowise chromebook entryline": "2020-06-01T00:00:00.000Z",
"prowise chromebook proline": "2021-08-01T00:00:00.000Z",
"prowise proline chromebook": "2021-08-01T00:00:00.000Z",
"rgs education chromebook": "2020-06-01T00:00:00.000Z",
"samsung chromebook": "2018-07-01T00:00:00.000Z",
"samsung chromebook - xe303": "2018-07-01T00:00:00.000Z",
"samsung chromebook 2 11": "2019-06-01T00:00:00.000Z",
"samsung chromebook 2 11 - xe500c12": "2020-06-01T00:00:00.000Z",
"samsung chromebook 2 13": "2019-06-01T00:00:00.000Z",
"samsung chromebook 3": "2021-06-01T00:00:00.000Z",
"samsung chromebook plus": "2023-08-01T00:00:00.000Z",
"samsung chromebook plus (lte)": "2024-06-01T00:00:00.000Z",
"samsung chromebook plus (v2)": "2024-06-01T00:00:00.000Z",
"samsung chromebook pro": "2022-11-01T00:00:00.000Z",
"samsung chromebook series 5": "2016-06-01T00:00:00.000Z",
"samsung chromebook series 5 550": "2017-05-01T00:00:00.000Z",
"samsung chromebox series 3": "2018-03-01T00:00:00.000Z",
"sector 5 e1 rugged chromebook": "2020-06-01T00:00:00.000Z",
"sector 5 e3 chromebook": "2023-11-01T00:00:00.000Z",
"senkatel c1101 chromebook": "2020-06-01T00:00:00.000Z",
"thinkpad 11e chromebook 3rd gen (yoga/clamshell)": "2021-06-01T00:00:00.000Z",
"thinkpad 13 chromebook": "2022-11-01T00:00:00.000Z",
"toshiba chromebook": "2019-06-01T00:00:00.000Z",
"toshiba chromebook 2": "2020-06-01T00:00:00.000Z",
"toshiba chromebook 2 (2015 edition)": "2020-09-01T00:00:00.000Z",
"true idc chromebook": "2020-06-01T00:00:00.000Z",
"true idc chromebook 11": "2020-06-01T00:00:00.000Z",
"videonet chromebook": "2020-06-01T00:00:00.000Z",
"videonet chromebook bl10": "2020-06-01T00:00:00.000Z",
"viewsonic nmp660 chromebox": "2024-06-01T00:00:00.000Z",
"viglen chromebook 11": "2020-06-01T00:00:00.000Z",
"viglen chromebook 11c": "2023-11-01T00:00:00.000Z",
"viglen chromebook 360": "2021-08-01T00:00:00.000Z",
"xolo chromebook": "2020-06-01T00:00:00.000Z"
}

File diff suppressed because it is too large Load Diff

795
src/gapi/directory/cros.py Normal file
View File

@@ -0,0 +1,795 @@
import datetime
from var import *
import __main__
import controlflow
import display
import fileutils
import gapi
import gapi.directory
import utils
def doUpdateCros():
cd = gapi.directory.buildGAPIObject()
i, devices = getCrOSDeviceEntity(3, cd)
update_body = {}
action_body = {}
orgUnitPath = None
ack_wipe = False
while i < len(sys.argv):
myarg = sys.argv[i].lower().replace('_', '')
if myarg == 'user':
update_body['annotatedUser'] = sys.argv[i+1]
i += 2
elif myarg == 'location':
update_body['annotatedLocation'] = sys.argv[i+1]
i += 2
elif myarg == 'notes':
update_body['notes'] = sys.argv[i+1].replace('\\n', '\n')
i += 2
elif myarg in ['tag', 'asset', 'assetid']:
update_body['annotatedAssetId'] = sys.argv[i+1]
i += 2
elif myarg in ['ou', 'org']:
orgUnitPath = __main__.getOrgUnitItem(sys.argv[i+1])
i += 2
elif myarg == 'action':
action = sys.argv[i+1].lower().replace('_', '').replace('-', '')
deprovisionReason = None
if action in ['deprovisionsamemodelreplace',
'deprovisionsamemodelreplacement']:
action = 'deprovision'
deprovisionReason = 'same_model_replacement'
elif action in ['deprovisiondifferentmodelreplace',
'deprovisiondifferentmodelreplacement']:
action = 'deprovision'
deprovisionReason = 'different_model_replacement'
elif action in ['deprovisionretiringdevice']:
action = 'deprovision'
deprovisionReason = 'retiring_device'
elif action not in ['disable', 'reenable']:
controlflow.system_error_exit(2, f'expected action of ' \
f'deprovision_same_model_replace, ' \
f'deprovision_different_model_replace, ' \
f'deprovision_retiring_device, disable or reenable,'
f' got {action}')
action_body = {'action': action}
if deprovisionReason:
action_body['deprovisionReason'] = deprovisionReason
i += 2
elif myarg == 'acknowledgedevicetouchrequirement':
ack_wipe = True
i += 1
else:
controlflow.invalid_argument_exit(sys.argv[i], "gam update cros")
i = 0
count = len(devices)
if action_body:
if action_body['action'] == 'deprovision' and not ack_wipe:
print(f'WARNING: Refusing to deprovision {count} devices because '
'acknowledge_device_touch_requirement not specified. ' \
'Deprovisioning a device means the device will have to ' \
'be physically wiped and re-enrolled to be managed by ' \
'your domain again. This requires physical access to ' \
'the device and is very time consuming to perform for ' \
'each device. Please add ' \
'"acknowledge_device_touch_requirement" to the GAM ' \
'command if you understand this and wish to proceed ' \
'with the deprovision. Please also be aware that ' \
'deprovisioning can have an effect on your device ' \
'license count. See ' \
'https://support.google.com/chrome/a/answer/3523633 '\
'for full details.')
sys.exit(3)
for deviceId in devices:
i += 1
cur_count = __main__.currentCount(i, count)
print(f' performing action {action} for {deviceId}{cur_count}')
gapi.call(cd.chromeosdevices(), function='action',
customerId=GC_Values[GC_CUSTOMER_ID],
resourceId=deviceId, body=action_body)
else:
if update_body:
for deviceId in devices:
i += 1
current_count = __main__.currentCount(i, count)
print(f' updating {deviceId}{current_count}')
gapi.call(cd.chromeosdevices(), 'update',
customerId=GC_Values[GC_CUSTOMER_ID],
deviceId=deviceId, body=update_body)
if orgUnitPath:
# split moves into max 50 devices per batch
for l in range(0, len(devices), 50):
move_body = {'deviceIds': devices[l:l+50]}
print(f' moving {len(move_body["deviceIds"])} devices to ' \
f'{orgUnitPath}')
gapi.call(cd.chromeosdevices(), 'moveDevicesToOu',
customerId=GC_Values[GC_CUSTOMER_ID],
orgUnitPath=orgUnitPath, body=move_body)
def doGetCrosInfo():
cd = gapi.directory.buildGAPIObject()
i, devices = getCrOSDeviceEntity(3, cd)
downloadfile = None
targetFolder = GC_Values[GC_DRIVE_DIR]
projection = None
fieldsList = []
noLists = False
startDate = endDate = None
listLimit = 0
while i < len(sys.argv):
myarg = sys.argv[i].lower().replace('_', '')
if myarg == 'nolists':
noLists = True
i += 1
elif myarg == 'listlimit':
listLimit = __main__.getInteger(sys.argv[i+1], myarg, minVal=-1)
i += 2
elif myarg in CROS_START_ARGUMENTS:
startDate = _getFilterDate(sys.argv[i+1])
i += 2
elif myarg in CROS_END_ARGUMENTS:
endDate = _getFilterDate(sys.argv[i+1])
i += 2
elif myarg == 'allfields':
projection = 'FULL'
fieldsList = []
i += 1
elif myarg in PROJECTION_CHOICES_MAP:
projection = PROJECTION_CHOICES_MAP[myarg]
if projection == 'FULL':
fieldsList = []
else:
fieldsList = CROS_BASIC_FIELDS_LIST[:]
i += 1
elif myarg in CROS_ARGUMENT_TO_PROPERTY_MAP:
fieldsList.extend(CROS_ARGUMENT_TO_PROPERTY_MAP[myarg])
i += 1
elif myarg == 'fields':
fieldNameList = sys.argv[i+1]
for field in fieldNameList.lower().replace(',', ' ').split():
if field in CROS_ARGUMENT_TO_PROPERTY_MAP:
fieldsList.extend(CROS_ARGUMENT_TO_PROPERTY_MAP[field])
if field in CROS_ACTIVE_TIME_RANGES_ARGUMENTS + \
CROS_DEVICE_FILES_ARGUMENTS + \
CROS_RECENT_USERS_ARGUMENTS:
projection = 'FULL'
noLists = False
else:
controlflow.invalid_argument_exit(
field, "gam info cros fields")
i += 2
elif myarg == 'downloadfile':
downloadfile = sys.argv[i+1]
if downloadfile.lower() == 'latest':
downloadfile = downloadfile.lower()
i += 2
elif myarg == 'targetfolder':
targetFolder = os.path.expanduser(sys.argv[i+1])
if not os.path.isdir(targetFolder):
os.makedirs(targetFolder)
i += 2
else:
controlflow.invalid_argument_exit(sys.argv[i], "gam info cros")
if fieldsList:
fieldsList.append('deviceId')
fields = ','.join(set(fieldsList)).replace('.', '/')
else:
fields = None
i = 0
device_count = len(devices)
for deviceId in devices:
i += 1
cros = gapi.call(cd.chromeosdevices(), 'get',
customerId=GC_Values[GC_CUSTOMER_ID],
deviceId=deviceId, projection=projection,
fields=fields)
print(f'CrOS Device: {deviceId} ({i} of {device_count})')
if 'notes' in cros:
cros['notes'] = cros['notes'].replace('\n', '\\n')
if 'autoUpdateExpiration' in cros:
cros['autoUpdateExpiration'] = utils.formatTimestampYMD(
cros['autoUpdateExpiration'])
_checkTPMVulnerability(cros)
for up in CROS_SCALAR_PROPERTY_PRINT_ORDER:
if up in cros:
if isinstance(cros[up], str):
print(f' {up}: {cros[up]}')
else:
sys.stdout.write(f' {up}:')
display.print_json(cros[up], ' ')
if not noLists:
activeTimeRanges = _filterTimeRanges(
cros.get('activeTimeRanges', []), startDate, endDate)
lenATR = len(activeTimeRanges)
if lenATR:
print(' activeTimeRanges')
num_ranges = min(lenATR, listLimit or lenATR)
for activeTimeRange in activeTimeRanges[:num_ranges]:
active_date = activeTimeRange["date"]
active_time = activeTimeRange["activeTime"]
duration = utils.formatMilliSeconds(active_time)
minutes = active_time // 60000
print(f' date: {active_date}')
print(f' activeTime: {active_time}')
print(f' duration: {duration}')
print(f' minutes: {minutes}')
recentUsers = cros.get('recentUsers', [])
lenRU = len(recentUsers)
if lenRU:
print(' recentUsers')
num_ranges = min(lenRU, listLimit or lenRU)
for recentUser in recentUsers[:num_ranges]:
useremail = recentUser.get("email")
if not useremail:
if recentUser["type"] == "USER_TYPE_UNMANAGED":
useremail = 'UnmanagedUser'
else:
useremail = 'Unknown'
print(f' type: {recentUser["type"]}')
print(f' email: {useremail}')
deviceFiles = _filterCreateReportTime(
cros.get('deviceFiles', []), 'createTime', startDate, endDate)
lenDF = len(deviceFiles)
if lenDF:
num_ranges = min(lenDF, listLimit or lenDF)
print(' deviceFiles')
for deviceFile in deviceFiles[:num_ranges]:
device_type = deviceFile['type']
create_time = deviceFile['createTime']
print(f' {device_type}: {create_time}')
if downloadfile:
deviceFiles = cros.get('deviceFiles', [])
lenDF = len(deviceFiles)
if lenDF:
if downloadfile == 'latest':
deviceFile = deviceFiles[-1]
else:
for deviceFile in deviceFiles:
if deviceFile['createTime'] == downloadfile:
break
else:
print(f'ERROR: file {downloadfile} not ' \
f'available to download.')
deviceFile = None
if deviceFile:
created = deviceFile["createTime"]
downloadfile = f'cros-logs-{deviceId}-{created}.zip'
downloadfilename = os.path.join(targetFolder,
downloadfile)
dl_url = deviceFile['downloadUrl']
_, content = cd._http.request(dl_url)
fileutils.write_file(downloadfilename, content,
mode='wb',
continue_on_error=True)
print(f'Downloaded: {downloadfilename}')
elif downloadfile:
print('ERROR: no files to download.')
cpuStatusReports = _filterCreateReportTime(
cros.get('cpuStatusReports', []),
'reportTime',
startDate,
endDate)
lenCSR = len(cpuStatusReports)
if lenCSR:
print(' cpuStatusReports')
num_ranges = min(lenCSR, listLimit or lenCSR)
for cpuStatusReport in cpuStatusReports[:num_ranges]:
print(f' reportTime: {cpuStatusReport["reportTime"]}')
print(' cpuTemperatureInfo')
tempInfos = cpuStatusReport.get('cpuTemperatureInfo', [])
for tempInfo in tempInfos:
temp_label = tempInfo['label'].strip()
temperature = tempInfo['temperature']
print(f' {temp_label}: {temperature}')
pct_info = cpuStatusReport["cpuUtilizationPercentageInfo"]
util = ",".join([str(x) for x in pct_info])
print(f' cpuUtilizationPercentageInfo: {util}')
diskVolumeReports = cros.get('diskVolumeReports', [])
lenDVR = len(diskVolumeReports)
if lenDVR:
print(' diskVolumeReports')
print(' volumeInfo')
num_ranges = min(lenDVR, listLimit or lenDVR)
for diskVolumeReport in diskVolumeReports[:num_ranges]:
volumeInfo = diskVolumeReport['volumeInfo']
for volume in volumeInfo:
vid = volume['volumeId']
vstorage_free = volume['storageFree']
vstorage_total = volume['storageTotal']
print(f' volumeId: {vid}')
print(f' storageFree: {vstorage_free}')
print(f' storageTotal: {vstorage_total}')
systemRamFreeReports = _filterCreateReportTime(
cros.get('systemRamFreeReports', []),
'reportTime', startDate, endDate)
lenSRFR = len(systemRamFreeReports)
if lenSRFR:
print(' systemRamFreeReports')
num_ranges = min(lenSRFR, listLimit or lenSRFR)
for systemRamFreeReport in systemRamFreeReports[:num_ranges]:
report_time = systemRamFreeReport["reportTime"]
free_info = systemRamFreeReport["systemRamFreeInfo"]
free_ram = ",".join(free_info)
print(f' reportTime: {report_time}')
print(f' systemRamFreeInfo: {free_ram}')
def doPrintCrosActivity():
cd = gapi.directory.buildGAPIObject()
todrive = False
titles = ['deviceId', 'annotatedAssetId',
'annotatedLocation', 'serialNumber', 'orgUnitPath']
csvRows = []
fieldsList = ['deviceId', 'annotatedAssetId',
'annotatedLocation', 'serialNumber', 'orgUnitPath']
startDate = endDate = None
selectActiveTimeRanges = selectDeviceFiles = selectRecentUsers = False
listLimit = 0
delimiter = ','
orgUnitPath = None
queries = [None]
i = 3
while i < len(sys.argv):
myarg = sys.argv[i].lower().replace('_', '')
if myarg in ['query', 'queries']:
queries = __main__.getQueries(myarg, sys.argv[i+1])
i += 2
elif myarg == 'limittoou':
orgUnitPath = __main__.getOrgUnitItem(sys.argv[i+1])
i += 2
elif myarg == 'todrive':
todrive = True
i += 1
elif myarg in CROS_ACTIVE_TIME_RANGES_ARGUMENTS:
selectActiveTimeRanges = True
i += 1
elif myarg in CROS_DEVICE_FILES_ARGUMENTS:
selectDeviceFiles = True
i += 1
elif myarg in CROS_RECENT_USERS_ARGUMENTS:
selectRecentUsers = True
i += 1
elif myarg == 'both':
selectActiveTimeRanges = selectRecentUsers = True
i += 1
elif myarg == 'all':
selectActiveTimeRanges = selectDeviceFiles = True
selectRecentUsers = True
i += 1
elif myarg in CROS_START_ARGUMENTS:
startDate = _getFilterDate(sys.argv[i+1])
i += 2
elif myarg in CROS_END_ARGUMENTS:
endDate = _getFilterDate(sys.argv[i+1])
i += 2
elif myarg == 'listlimit':
listLimit = __main__.getInteger(sys.argv[i+1], myarg, minVal=0)
i += 2
elif myarg == 'delimiter':
delimiter = sys.argv[i+1]
i += 2
else:
controlflow.invalid_argument_exit(
sys.argv[i], "gam print crosactivity")
if not selectActiveTimeRanges and \
not selectDeviceFiles and \
not selectRecentUsers:
selectActiveTimeRanges = selectRecentUsers = True
if selectRecentUsers:
fieldsList.append('recentUsers')
display.add_titles_to_csv_file(['recentUsers.email', ], titles)
if selectActiveTimeRanges:
fieldsList.append('activeTimeRanges')
titles_to_add = ['activeTimeRanges.date',
'activeTimeRanges.duration',
'activeTimeRanges.minutes']
display.add_titles_to_csv_file(titles_to_add, titles)
if selectDeviceFiles:
fieldsList.append('deviceFiles')
titles_to_add = ['deviceFiles.type', 'deviceFiles.createTime']
display.add_titles_to_csv_file(titles_to_add, titles)
fields = f'nextPageToken,chromeosdevices({",".join(fieldsList)})'
for query in queries:
__main__.printGettingAllItems('CrOS Devices', query)
page_message = gapi.got_total_items_msg('CrOS Devices', '...\n')
all_cros = gapi.get_all_pages(cd.chromeosdevices(), 'list',
'chromeosdevices',
page_message=page_message,
query=query,
customerId=GC_Values[GC_CUSTOMER_ID],
projection='FULL',
fields=fields, orgUnitPath=orgUnitPath)
for cros in all_cros:
row = {}
skip_attribs = ['recentUsers', 'activeTimeRanges', 'deviceFiles']
for attrib in cros:
if attrib not in skip_attribs:
row[attrib] = cros[attrib]
if selectActiveTimeRanges:
activeTimeRanges = _filterTimeRanges(
cros.get('activeTimeRanges', []), startDate, endDate)
lenATR = len(activeTimeRanges)
num_ranges = min(lenATR, listLimit or lenATR)
for activeTimeRange in activeTimeRanges[:num_ranges]:
newrow = row.copy()
newrow['activeTimeRanges.date'] = activeTimeRange['date']
active_time = activeTimeRange['activeTime']
newrow['activeTimeRanges.duration'] = \
utils.formatMilliSeconds(active_time)
newrow['activeTimeRanges.minutes'] = \
activeTimeRange['activeTime']//60000
csvRows.append(new_row)
if selectRecentUsers:
recentUsers = cros.get('recentUsers', [])
lenRU = len(recentUsers)
num_ranges = min(lenRU, listLimit or lenRU)
recent_users = []
for recentUser in recentUsers[:num_ranges]:
useremail = recentUser.get("email")
if not useremail:
if recentUser["type"] == "USER_TYPE_UNMANAGED":
useremail = 'UnmanagedUser'
else:
useremail = 'Unknown'
recent_users.append(useremail)
row['recentUsers.email'] = delimiter.join(recent_users)
csvRows.append(row)
if selectDeviceFiles:
deviceFiles = _filterCreateReportTime(
cros.get('deviceFiles', []),
'createTime', startDate, endDate)
lenDF = len(deviceFiles)
num_ranges = min(lenDF, listLimit or lenDF)
for deviceFile in deviceFiles[:num_ranges]:
new_row = row.copy()
new_row['deviceFiles.type'] = deviceFile['type']
create_time = deviceFile['createTime']
new_row['deviceFiles.createTime'] = create_time
csvRows.append(new_row)
display.write_csv_file(csvRows, titles, 'CrOS Activity', todrive)
def _checkTPMVulnerability(cros):
if 'tpmVersionInfo' in cros and \
'firmwareVersion' in cros['tpmVersionInfo']:
firmware_version = cros['tpmVersionInfo']['firmwareVersion']
if firmware_version in CROS_TPM_VULN_VERSIONS:
cros['tpmVersionInfo']['tpmVulnerability'] = 'VULNERABLE'
elif firmware_version in CROS_TPM_FIXED_VERSIONS:
cros['tpmVersionInfo']['tpmVulnerability'] = 'UPDATED'
else:
cros['tpmVersionInfo']['tpmVulnerability'] = 'NOT IMPACTED'
def doPrintCrosDevices():
def _getSelectedLists(myarg):
if myarg in CROS_ACTIVE_TIME_RANGES_ARGUMENTS:
selectedLists['activeTimeRanges'] = True
elif myarg in CROS_RECENT_USERS_ARGUMENTS:
selectedLists['recentUsers'] = True
elif myarg in CROS_DEVICE_FILES_ARGUMENTS:
selectedLists['deviceFiles'] = True
elif myarg in CROS_CPU_STATUS_REPORTS_ARGUMENTS:
selectedLists['cpuStatusReports'] = True
elif myarg in CROS_DISK_VOLUME_REPORTS_ARGUMENTS:
selectedLists['diskVolumeReports'] = True
elif myarg in CROS_SYSTEM_RAM_FREE_REPORTS_ARGUMENTS:
selectedLists['systemRamFreeReports'] = True
cd = gapi.directory.buildGAPIObject()
todrive = False
fieldsList = []
fieldsTitles = {}
titles = []
csvRows = []
display.add_field_to_csv_file(
'deviceid', CROS_ARGUMENT_TO_PROPERTY_MAP, fieldsList, fieldsTitles, titles)
projection = orderBy = sortOrder = orgUnitPath = None
queries = [None]
noLists = sortHeaders = False
selectedLists = {}
startDate = endDate = None
listLimit = 0
i = 3
while i < len(sys.argv):
myarg = sys.argv[i].lower().replace('_', '')
if myarg in ['query', 'queries']:
queries = __main__.getQueries(myarg, sys.argv[i+1])
i += 2
elif myarg == 'limittoou':
orgUnitPath = __main__.getOrgUnitItem(sys.argv[i+1])
i += 2
elif myarg == 'todrive':
todrive = True
i += 1
elif myarg == 'nolists':
noLists = True
selectedLists = {}
i += 1
elif myarg == 'listlimit':
listLimit = __main__.getInteger(sys.argv[i+1], myarg, minVal=0)
i += 2
elif myarg in CROS_START_ARGUMENTS:
startDate = _getFilterDate(sys.argv[i+1])
i += 2
elif myarg in CROS_END_ARGUMENTS:
endDate = _getFilterDate(sys.argv[i+1])
i += 2
elif myarg == 'orderby':
orderBy = sys.argv[i+1].lower().replace('_', '')
validOrderBy = ['location', 'user', 'lastsync',
'notes', 'serialnumber', 'status', 'supportenddate']
if orderBy not in validOrderBy:
controlflow.expected_argument_exit(
"orderby", ", ".join(validOrderBy), orderBy)
if orderBy == 'location':
orderBy = 'annotatedLocation'
elif orderBy == 'user':
orderBy = 'annotatedUser'
elif orderBy == 'lastsync':
orderBy = 'lastSync'
elif orderBy == 'serialnumber':
orderBy = 'serialNumber'
elif orderBy == 'supportenddate':
orderBy = 'supportEndDate'
i += 2
elif myarg in SORTORDER_CHOICES_MAP:
sortOrder = SORTORDER_CHOICES_MAP[myarg]
i += 1
elif myarg in PROJECTION_CHOICES_MAP:
projection = PROJECTION_CHOICES_MAP[myarg]
sortHeaders = True
if projection == 'FULL':
fieldsList = []
else:
fieldsList = CROS_BASIC_FIELDS_LIST[:]
i += 1
elif myarg == 'allfields':
projection = 'FULL'
sortHeaders = True
fieldsList = []
i += 1
elif myarg == 'sortheaders':
sortHeaders = True
i += 1
elif myarg in CROS_LISTS_ARGUMENTS:
_getSelectedLists(myarg)
i += 1
elif myarg in CROS_ARGUMENT_TO_PROPERTY_MAP:
display.add_field_to_fields_list(
myarg, CROS_ARGUMENT_TO_PROPERTY_MAP, fieldsList)
i += 1
elif myarg == 'fields':
fieldNameList = sys.argv[i+1]
for field in fieldNameList.lower().replace(',', ' ').split():
if field in CROS_LISTS_ARGUMENTS:
_getSelectedLists(field)
elif field in CROS_ARGUMENT_TO_PROPERTY_MAP:
display.add_field_to_fields_list(
field, CROS_ARGUMENT_TO_PROPERTY_MAP, fieldsList)
else:
controlflow.invalid_argument_exit(
field, "gam print cros fields")
i += 2
else:
controlflow.invalid_argument_exit(sys.argv[i], "gam print cros")
if selectedLists:
noLists = False
projection = 'FULL'
for selectList in selectedLists:
display.add_field_to_fields_list(
selectList, CROS_ARGUMENT_TO_PROPERTY_MAP, fieldsList)
if fieldsList:
fieldsList.append('deviceId')
fields = f'nextPageToken,chromeosdevices({",".join(set(fieldsList))})'.replace(
'.', '/')
else:
fields = None
for query in queries:
__main__.printGettingAllItems('CrOS Devices', query)
page_message = gapi.got_total_items_msg('CrOS Devices', '...\n')
all_cros = gapi.get_all_pages(cd.chromeosdevices(), 'list',
'chromeosdevices',
page_message=page_message, query=query,
customerId=GC_Values[GC_CUSTOMER_ID],
projection=projection,
orgUnitPath=orgUnitPath,
orderBy=orderBy, sortOrder=sortOrder,
fields=fields)
for cros in all_cros:
_checkTPMVulnerability(cros)
if not noLists and not selectedLists:
for cros in all_cros:
if 'notes' in cros:
cros['notes'] = cros['notes'].replace('\n', '\\n')
if 'autoUpdateExpiration' in cros:
cros['autoUpdateExpiration'] = utils.formatTimestampYMD(
cros['autoUpdateExpiration'])
for cpuStatusReport in cros.get('cpuStatusReports', []):
tempInfos = cpuStatusReport.get('cpuTemperatureInfo', [])
for tempInfo in tempInfos:
tempInfo['label'] = tempInfo['label'].strip()
display.add_row_titles_to_csv_file(utils.flatten_json(
cros, listLimit=listLimit), csvRows, titles)
continue
for cros in all_cros:
if 'notes' in cros:
cros['notes'] = cros['notes'].replace('\n', '\\n')
if 'autoUpdateExpiration' in cros:
cros['autoUpdateExpiration'] = utils.formatTimestampYMD(
cros['autoUpdateExpiration'])
row = {}
for attrib in cros:
if attrib not in set(['kind', 'etag', 'tpmVersionInfo',
'recentUsers', 'activeTimeRanges',
'deviceFiles', 'cpuStatusReports',
'diskVolumeReports',
'systemRamFreeReports']):
row[attrib] = cros[attrib]
if selectedLists.get('activeTimeRanges'):
timergs = cros.get('activeTimeRanges', [])
else:
timergs = []
activeTimeRanges = _filterTimeRanges(timergs, startDate, endDate)
if selectedLists.get('recentUsers'):
recentUsers = cros.get('recentUsers', [])
else:
recentUsers = []
if selectedLists.get('deviceFiles'):
device_files = cros.get('deviceFiles', [])
else:
device_files = []
deviceFiles = _filterCreateReportTime(device_files, 'createTime',
startDate, endDate)
if selectedLists.get('cpuStatusReports'):
cpu_reports = cros.get('cpuStatusReports', [])
else:
cpu_reports = []
cpuStatusReports = _filterCreateReportTime(cpu_reports,
'reportTime',
startDate, endDate)
if selectedLists.get('diskVolumeReports'):
diskVolumeReports = cros.get('diskVolumeReports', [])
else:
diskVolumeReports = []
if selectedLists.get('systemRamFreeReports'):
ram_reports = cros.get('systemRamFreeReports', [])
else:
ram_reports = []
systemRamFreeReports = _filterCreateReportTime(ram_reports,
'reportTime',
startDate,
endDate)
if noLists or (not activeTimeRanges and \
not recentUsers and \
not deviceFiles and \
not cpuStatusReports and \
not diskVolumeReports and \
not systemRamFreeReports):
display.add_row_titles_to_csv_file(row, csvRows, titles)
continue
lenATR = len(activeTimeRanges)
lenRU = len(recentUsers)
lenDF = len(deviceFiles)
lenCSR = len(cpuStatusReports)
lenDVR = len(diskVolumeReports)
lenSRFR = len(systemRamFreeReports)
max_len = max(lenATR, lenRU, lenDF, lenCSR, lenDVR, lenSRFR)
for i in range(min(max_len, listLimit or max_len)):
nrow = row.copy()
if i < lenATR:
nrow['activeTimeRanges.date'] = \
activeTimeRanges[i]['date']
nrow['activeTimeRanges.activeTime'] = \
str(activeTimeRanges[i]['activeTime'])
active_time = activeTimeRanges[i]['activeTime']
nrow['activeTimeRanges.duration'] = \
utils.formatMilliSeconds(active_time)
nrow['activeTimeRanges.minutes'] = active_time // 60000
if i < lenRU:
nrow['recentUsers.type'] = recentUsers[i]['type']
nrow['recentUsers.email'] = recentUsers[i].get('email')
if not nrow['recentUsers.email']:
if nrow['recentUsers.type'] == 'USER_TYPE_UNMANAGED':
nrow['recentUsers.email'] = 'UnmanagedUser'
else:
nrow['recentUsers.email'] = 'Unknown'
if i < lenDF:
nrow['deviceFiles.type'] = deviceFiles[i]['type']
nrow['deviceFiles.createTime'] = \
deviceFiles[i]['createTime']
if i < lenCSR:
nrow['cpuStatusReports.reportTime'] = \
cpuStatusReports[i]['reportTime']
tempInfos = cpuStatusReports[i].get('cpuTemperatureInfo',
[])
for tempInfo in tempInfos:
temperature = tempInfo['temperature']
label = tempInfo["label"].strip()
base = 'cpuStatusReports.cpuTemperatureInfo.'
nrow[f'{base}{label}'] = tempInfo['temperature']
cpu_field = 'cpuUtilizationPercentageInfo'
cpu_reports = cpuStatusReports[i][cpu_field]
cpu_pcts = [str(x) for x in cpu_reports]
nrow[f'cpuStatusReports.{cpu_field}'] = ','.join(cpu_pcts)
if i < lenDVR:
volumeInfo = diskVolumeReports[i]['volumeInfo']
j = 0
vfield = 'diskVolumeReports.volumeInfo.'
for volume in volumeInfo:
nrow[f'{vfield}{j}.volumeId'] = \
volume['volumeId']
nrow[f'{vfield}{j}.storageFree'] = \
volume['storageFree']
nrow[f'{vfield}{j}.storageTotal'] = \
volume['storageTotal']
j += 1
if i < lenSRFR:
nrow['systemRamFreeReports.reportTime'] = \
systemRamFreeReports[i]['reportTime']
ram_reports = systemRamFreeReports[i]['systemRamFreeInfo']
ram_info = [str(x) for x in ram_reports]
nrow['systenRamFreeReports.systemRamFreeInfo'] = \
','.join(ram_info)
display.add_row_titles_to_csv_file(nrow, csvRows, titles)
if sortHeaders:
display.sort_csv_titles(['deviceId', ], titles)
display.write_csv_file(csvRows, titles, 'CrOS', todrive)
def getCrOSDeviceEntity(i, cd):
myarg = sys.argv[i].lower()
if myarg == 'cros_sn':
return i+2, getUsersToModify('cros_sn', sys.argv[i+1])
if myarg == 'query':
return i+2, getUsersToModify('crosquery', sys.argv[i+1])
if myarg[:6] == 'query:':
query = sys.argv[i][6:]
if query[:12].lower() == 'orgunitpath:':
kwargs = {'orgUnitPath': query[12:]}
else:
kwargs = {'query': query}
fields = 'nextPageToken,chromeosdevices(deviceId)'
devices = gapi.get_all_pages(cd.chromeosdevices(), 'list',
'chromeosdevices',
customerId=GC_Values[GC_CUSTOMER_ID],
fields=fields, **kwargs)
return i+1, [device['deviceId'] for device in devices]
return i+1, sys.argv[i].replace(',', ' ').split()
def _getFilterDate(dateStr):
return datetime.datetime.strptime(dateStr, YYYYMMDD_FORMAT)
def _filterTimeRanges(activeTimeRanges, startDate, endDate):
if startDate is None and endDate is None:
return activeTimeRanges
filteredTimeRanges = []
for timeRange in activeTimeRanges:
activityDate = datetime.datetime.strptime(
timeRange['date'], YYYYMMDD_FORMAT)
if ((startDate is None) or \
(activityDate >= startDate)) and \
((endDate is None) or \
(activityDate <= endDate)):
filteredTimeRanges.append(timeRange)
return filteredTimeRanges
def _filterCreateReportTime(items, timeField, startTime, endTime):
if startTime is None and endTime is None:
return items
filteredItems = []
time_format = '%Y-%m-%dT%H:%M:%S.%fZ'
for item in items:
timeValue = datetime.datetime.strptime(item[timeField], time_format)
if ((startTime is None) or \
(timeValue >= startTime)) and \
((endTime is None) or \
(timeValue <= endTime)):
filteredItems.append(item)
return filteredItems

View File

@@ -0,0 +1,113 @@
import datetime
from var import *
import controlflow
import gapi
import gapi.directory
import gapi.reports
def doGetCustomerInfo():
cd = gapi.directory.buildGAPIObject()
customer_info = gapi.call(cd.customers(), 'get',
customerKey=GC_Values[GC_CUSTOMER_ID])
print(f'Customer ID: {customer_info["id"]}')
print(f'Primary Domain: {customer_info["customerDomain"]}')
result = gapi.call(cd.domains(), 'get', customer=customer_info['id'],
domainName=customer_info['customerDomain'],
fields='verified')
print(f'Primary Domain Verified: {result["verified"]}')
# If customer has changed primary domain customerCreationTime is date
# of current primary being added, not customer create date.
# We should also get all domains and use oldest date
customer_creation = customer_info['customerCreationTime']
date_format = '%Y-%m-%dT%H:%M:%S.%fZ'
oldest = datetime.datetime.strptime(customer_creation, date_format)
domains = gapi.get_items(cd.domains(), 'list', 'domains',
customer=GC_Values[GC_CUSTOMER_ID],
fields='domains(creationTime)')
for domain in domains:
creation_timestamp = int(domain['creationTime'])/1000
domain_creation = datetime.datetime.fromtimestamp(creation_timestamp)
if domain_creation < oldest:
oldest = domain_creation
print(f'Customer Creation Time: {oldest.strftime(date_format)}')
customer_language = customer_info.get('language', 'Unset (defaults to en)')
print(f'Default Language: {customer_language}')
if 'postalAddress' in customer_info:
print('Address:')
for field in ADDRESS_FIELDS_PRINT_ORDER:
if field in customer_info['postalAddress']:
print(f' {field}: {customer_info["postalAddress"][field]}')
if 'phoneNumber' in customer_info:
print(f'Phone: {customer_info["phoneNumber"]}')
print(f'Admin Secondary Email: {customer_info["alternateEmail"]}')
user_counts_map = {
'accounts:num_users': 'Total Users',
'accounts:gsuite_basic_total_licenses': 'G Suite Basic Licenses',
'accounts:gsuite_basic_used_licenses': 'G Suite Basic Users',
'accounts:gsuite_enterprise_total_licenses': 'G Suite Enterprise ' \
'Licenses',
'accounts:gsuite_enterprise_used_licenses': 'G Suite Enterprise ' \
'Users',
'accounts:gsuite_unlimited_total_licenses': 'G Suite Business ' \
'Licenses',
'accounts:gsuite_unlimited_used_licenses': 'G Suite Business Users'
}
parameters = ','.join(list(user_counts_map))
tryDate = datetime.date.today().strftime(YYYYMMDD_FORMAT)
customerId = GC_Values[GC_CUSTOMER_ID]
if customerId == MY_CUSTOMER:
customerId = None
rep = gapi.reports.buildGAPIObject()
usage = None
throw_reasons = [gapi.errors.ErrorReason.INVALID]
while True:
try:
usage = gapi.get_all_pages(rep.customerUsageReports(), 'get',
'usageReports',
throw_reasons=throw_reasons,
customerId=customerId, date=tryDate,
parameters=parameters)
break
except gapi.errors.GapiInvalidError as e:
tryDate = gapi.reports._adjust_date(str(e))
if not usage:
print('No user count data available.')
return
print(f'User counts as of {tryDate}:')
for item in usage[0]['parameters']:
api_name = user_counts_map.get(item['name'])
api_value = int(item.get('intValue', 0))
if api_name and api_value:
print(f' {api_name}: {api_value:,}')
def doUpdateCustomer():
cd = gapi.directory.buildGAPIObject()
body = {}
i = 3
while i < len(sys.argv):
myarg = sys.argv[i].lower().replace('_', '')
if myarg in ADDRESS_FIELDS_ARGUMENT_MAP:
body.setdefault('postalAddress', {})
arg = ADDRESS_FIELDS_ARGUMENT_MAP[myarg]
body['postalAddress'][arg] = sys.argv[i+1]
i += 2
elif myarg in ['adminsecondaryemail', 'alternateemail']:
body['alternateEmail'] = sys.argv[i+1]
i += 2
elif myarg in ['phone', 'phonenumber']:
body['phoneNumber'] = sys.argv[i+1]
i += 2
elif myarg == 'language':
body['language'] = sys.argv[i+1]
i += 2
else:
controlflow.invalid_argument_exit(myarg, "gam update customer")
if not body:
controlflow.system_error_exit(2, 'no arguments specified for "gam '
'update customer"')
gapi.call(cd.customers(), 'patch', customerKey=GC_Values[GC_CUSTOMER_ID],
body=body)
print('Updated customer')

325
src/gapi/reports.py Normal file
View File

@@ -0,0 +1,325 @@
import datetime
import sys
import __main__
from var import *
import controlflow
import display
import gapi
import utils
def buildGAPIObject():
return __main__.buildGAPIObject('reports')
REPORT_CHOICE_MAP = {
'access': 'access_transparency',
'accesstransparency': 'access_transparency',
'calendars': 'calendar',
'customers': 'customer',
'doc': 'drive',
'docs': 'drive',
'domain': 'customer',
'enterprisegroups': 'groups_enterprise',
'google+': 'gplus',
'group': 'groups',
'groupsenterprise': 'groups_enterprise',
'hangoutsmeet': 'meet',
'logins': 'login',
'oauthtoken': 'token',
'tokens': 'token',
'users': 'user',
'useraccounts': 'user_accounts',
}
def showReport():
rep = buildGAPIObject()
throw_reasons = [gapi.errors.ErrorReason.INVALID]
report = sys.argv[2].lower()
report = REPORT_CHOICE_MAP.get(report.replace('_', ''), report)
valid_apps = gapi.get_enum_values_minus_unspecified(
rep._rootDesc['resources']['activities']['methods']['list'][
'parameters']['applicationName']['enum'])+['customer', 'user']
if report not in valid_apps:
controlflow.expected_argument_exit(
"report", ", ".join(sorted(valid_apps)), report)
customerId = GC_Values[GC_CUSTOMER_ID]
if customerId == MY_CUSTOMER:
customerId = None
filters = parameters = actorIpAddress = startTime = endTime = eventName = orgUnitId = None
tryDate = datetime.date.today().strftime(YYYYMMDD_FORMAT)
to_drive = False
userKey = 'all'
fullDataRequired = None
i = 3
while i < len(sys.argv):
myarg = sys.argv[i].lower()
if myarg == 'date':
tryDate = utils.get_yyyymmdd(sys.argv[i+1])
i += 2
elif myarg in ['orgunit', 'org', 'ou']:
_, orgUnitId = getOrgUnitId(sys.argv[i+1])
i += 2
elif myarg == 'fulldatarequired':
fullDataRequired = []
fdr = sys.argv[i+1].lower()
if fdr and fdr != 'all':
fullDataRequired = fdr.replace(',', ' ').split()
i += 2
elif myarg == 'start':
startTime = utils.get_time_or_delta_from_now(sys.argv[i+1])
i += 2
elif myarg == 'end':
endTime = utils.get_time_or_delta_from_now(sys.argv[i+1])
i += 2
elif myarg == 'event':
eventName = sys.argv[i+1]
i += 2
elif myarg == 'user':
userKey = __main__.normalizeEmailAddressOrUID(sys.argv[i+1])
i += 2
elif myarg in ['filter', 'filters']:
filters = sys.argv[i+1]
i += 2
elif myarg in ['fields', 'parameters']:
parameters = sys.argv[i+1]
i += 2
elif myarg == 'ip':
actorIpAddress = sys.argv[i+1]
i += 2
elif myarg == 'todrive':
to_drive = True
i += 1
else:
controlflow.invalid_argument_exit(sys.argv[i], "gam report")
if report == 'user':
while True:
try:
if fullDataRequired is not None:
warnings = gapi.get_items(rep.userUsageReport(), 'get',
'warnings',
throw_reasons=throw_reasons,
date=tryDate, userKey=userKey,
customerId=customerId,
orgUnitID=orgUnitId,
fields='warnings')
fullData, tryDate = _check_full_data_available(
warnings, tryDate, fullDataRequired)
if fullData < 0:
print('No user report available.')
sys.exit(1)
if fullData == 0:
continue
page_message = gapi.got_total_items_msg('Users', '...\n')
usage = gapi.get_all_pages(rep.userUsageReport(), 'get',
'usageReports',
page_message=page_message,
throw_reasons=throw_reasons,
date=tryDate, userKey=userKey,
customerId=customerId,
orgUnitID=orgUnitId,
filters=filters,
parameters=parameters)
break
except gapi.errors.GapiInvalidError as e:
tryDate = _adjust_date(str(e))
if not usage:
print('No user report available.')
sys.exit(1)
titles = ['email', 'date']
csvRows = []
ptypes = ['intValue', 'boolValue', 'datetimeValue', 'stringValue']
for user_report in usage:
if 'entity' not in user_report:
continue
row = {'email': user_report['entity']
['userEmail'], 'date': tryDate}
for item in user_report.get('parameters', []):
if 'name' not in item:
continue
name = item['name']
if not name in titles:
titles.append(name)
for ptype in ptypes:
if ptype in item:
row[name] = item[ptype]
break
else:
row[name] = ''
csvRows.append(row)
display.write_csv_file(
csvRows, titles, f'User Reports - {tryDate}', to_drive)
elif report == 'customer':
while True:
try:
if fullDataRequired is not None:
warnings = gapi.get_items(rep.customerUsageReports(),
'get', 'warnings',
throw_reasons=throw_reasons,
customerId=customerId,
date=tryDate,
fields='warnings')
fullData, tryDate = _check_full_data_available(
warnings, tryDate, fullDataRequired)
if fullData < 0:
print('No customer report available.')
sys.exit(1)
if fullData == 0:
continue
usage = gapi.get_all_pages(rep.customerUsageReports(), 'get',
'usageReports',
throw_reasons=throw_reasons,
customerId=customerId,
date=tryDate,
parameters=parameters)
break
except gapi.errors.GapiInvalidError as e:
tryDate = _adjust_date(str(e))
if not usage:
print('No customer report available.')
sys.exit(1)
titles = ['name', 'value', 'client_id']
csvRows = []
auth_apps = list()
for item in usage[0]['parameters']:
if 'name' not in item:
continue
name = item['name']
if 'intValue' in item:
value = item['intValue']
elif 'msgValue' in item:
if name == 'accounts:authorized_apps':
for subitem in item['msgValue']:
app = {}
for an_item in subitem:
if an_item == 'client_name':
app['name'] = 'App: ' + \
subitem[an_item].replace('\n', '\\n')
elif an_item == 'num_users':
app['value'] = f'{subitem[an_item]} users'
elif an_item == 'client_id':
app['client_id'] = subitem[an_item]
auth_apps.append(app)
continue
values = []
for subitem in item['msgValue']:
if 'count' in subitem:
mycount = myvalue = None
for key, value in list(subitem.items()):
if key == 'count':
mycount = value
else:
myvalue = value
if mycount and myvalue:
values.append(f'{myvalue}:{mycount}')
value = ' '.join(values)
elif 'version_number' in subitem \
and 'num_devices' in subitem:
values.append(
f'{subitem["version_number"]}:'
f'{subitem["num_devices"]}')
else:
continue
value = ' '.join(sorted(values, reverse=True))
csvRows.append({'name': name, 'value': value})
for app in auth_apps: # put apps at bottom
csvRows.append(app)
display.write_csv_file(
csvRows, titles, f'Customer Report - {tryDate}', todrive=to_drive)
else:
page_message = gapi.got_total_items_msg('Activities', '...\n')
activities = gapi.get_all_pages(rep.activities(), 'list', 'items',
page_message=page_message,
applicationName=report,
userKey=userKey,
customerId=customerId,
actorIpAddress=actorIpAddress,
startTime=startTime, endTime=endTime,
eventName=eventName, filters=filters,
orgUnitID=orgUnitId)
if activities:
titles = ['name']
csvRows = []
for activity in activities:
events = activity['events']
del activity['events']
activity_row = utils.flatten_json(activity)
purge_parameters = True
for event in events:
for item in event.get('parameters', []):
if set(item) == set(['value', 'name']):
event[item['name']] = item['value']
elif set(item) == set(['intValue', 'name']):
if item['name'] in ['start_time', 'end_time']:
val = item.get('intValue')
if val is not None:
val = int(val)
if val >= 62135683200:
event[item['name']] = \
datetime.datetime.fromtimestamp(
val-62135683200).isoformat()
else:
event[item['name']] = item['intValue']
elif set(item) == set(['boolValue', 'name']):
event[item['name']] = item['boolValue']
elif set(item) == set(['multiValue', 'name']):
event[item['name']] = ' '.join(item['multiValue'])
elif item['name'] == 'scope_data':
parts = {}
for message in item['multiMessageValue']:
for mess in message['parameter']:
value = mess.get('value', ' '.join(
mess.get('multiValue', [])))
parts[mess['name']] = parts.get(
mess['name'], [])+[value]
for part, v in parts.items():
if part == 'scope_name':
part = 'scope'
event[part] = ' '.join(v)
else:
purge_parameters = False
if purge_parameters:
event.pop('parameters', None)
row = utils.flatten_json(event)
row.update(activity_row)
for item in row:
if item not in titles:
titles.append(item)
csvRows.append(row)
display.sort_csv_titles(['name', ], titles)
display.write_csv_file(
csvRows, titles, f'{report.capitalize()} Activity Report',
to_drive)
def _adjust_date(errMsg):
match_date = re.match('Data for dates later than (.*) is not yet '
'available. Please check back later', errMsg)
if not match_date:
match_date = re.match('Start date can not be later than (.*)', errMsg)
if not match_date:
controlflow.system_error_exit(4, errMsg)
return str(match_date.group(1))
def _check_full_data_available(warnings, tryDate, fullDataRequired):
one_day = datetime.timedelta(days=1)
for warning in warnings:
if warning['code'] == 'PARTIAL_DATA_AVAILABLE':
for app in warning['data']:
if app['key'] == 'application' and \
app['value'] != 'docs' and \
(not fullDataRequired or app['value'] in fullDataRequired):
tryDateTime = datetime.datetime.strptime(
tryDate, YYYYMMDD_FORMAT)
tryDateTime -= one_day
return (0, tryDateTime.strftime(YYYYMMDD_FORMAT))
elif warning['code'] == 'DATA_NOT_AVAILABLE':
for app in warning['data']:
if app['key'] == 'application' and \
app['value'] != 'docs' and \
(not fullDataRequired or app['value'] in fullDataRequired):
return (-1, tryDate)
return (1, tryDate)

View File

@@ -1,102 +0,0 @@
#!/usr/bin/env python3
from xml.etree import ElementTree as ET
import requests
from html.parser import HTMLParser
import string
import sys
import json
import dateutil.parser
class MyHTMLParser(HTMLParser):
def handle_starttag(self, tag, attrs):
global next_data_is_oem, next_data_is_td
if tag == 'h2' and attrs == [('class', 'zippy')]:
next_data_is_oem = True
elif tag == 'td':
next_data_is_td = True
def handle_data(self, data):
global oem, next_data_is_oem, next_data_is_td, data_is_date, model, printable, output_rows
if next_data_is_oem:
oem = ''.join(filter(lambda x: x in printable, data))
next_data_is_oem = False
elif next_data_is_td:
if data_is_date:
if model.lower().startswith(oem.lower()):
fullname = model.lower()
else:
fullname = '%s %s' % (oem, model)
fullname = fullname.lower()
date = dateutil.parser.parse(data).replace(day=1).strftime('%Y-%m-%dT00:00:00.000Z')
output_rows[fullname] = date
if fullname in exceptions:
for value in exceptions[fullname]:
output_rows[value] = date
data_is_date = False
else:
model = ''.join(filter(lambda x: x in printable, data))
data_is_date = True
next_data_is_td = False
global oem, next_data_is_oem, next_data_is_td, data_is_date, model, printable, exceptions, output_rows
output_rows = {}
printable = set(string.printable)
exceptions = {
# 'AUE OEM MODEL': ['API MODEL 1', ...]
'acer c7 chromebook': ['acer c7 chromebook (c710)'],
'acer chromebook 11 (c720, c720p)': ['acer c720 chromebook', 'acer c740 chromebook'],
'acer chromebook 11 (cb3-111, c730, c730e)': ['chromebook 11 (c730 / cb3-111)'],
'acer chromebook 11 (cb3-131, c735)': ['chromebook 11 (c735)'],
'acer chromebook 15 (cb515-1h,cb515-1ht)': ['chromebook 15 (cb515 - 1ht / 1h)'],
'acer chromebook 13(cb5-311, c810)': ['acer chromebook 13 (cb5-311)'],
'acer chromebook 15 (cb5-571, c910)': ['acer chromebook 15 (c910 / cb5-571)'],
'acer chromebook 311 (c721, c733, c733u, c733t)': ['acer chromebook 311', 'chromebook 311 (c721)'],
'acer chromebook 315 (cb315-2h)': ['acer chromebook 315'],
'acer chromebook spin 311 (r721t)': ['acer chromebook 311'],
'acer chromebook spin 511 (r752t, r752tn)': ['acer chromebook spin 511'],
'acer chromebox cxi2 / cxv2': ['acer chromebox cxi2'],
'asus chromebook c200': ['asus chromebook c200ma'],
'asus chromebook c201pa': ['asus chromebook c201pa'],
'asus chromebook c204': ['asus chromebook c204'],
'asus chromebook c300': ['asus chromebook c300ma'],
'asus chromebook flip c213': ['asus chromebook c213na'],
'asus chromebox 2 (cn62)': ['asus chromebox cn62'],
'asus chromebox 3 (cn65)': ['asus chromebox 3'],
'asus chromebox (cn60)': ['asus chromebox cn60'],
'ctl chromebook nl7 / nl7t-360 / nl7tw-360': ['ctl chromebook nl7'],
'ctl chromebook tablet tx1 for education': ['ctl chromebook tab tx1'],
'ctl nl61 chromebook': ['mecer v2 chromebook'],
'google cr-48': ['cr-48'],
'haier chromebook 11e': ['chromebook pcm-116e', 'lumos education chromebook'],
'haier chromebook 11': ['true idc chromebook 11', 'xolo chromebook'],
'hisense chromebook 11': ['epik 11.6" chromebook elb1101', 'mecer chromebook', 'videonet chromebook bl10'],
'hp chromebook 11 g1': ['hp chromebook 11 1100-1199 / hp chromebook 11 g1'],
'hp chromebook 11 g2': ['hp chromebook 11 2000-2099 / hp chromebook 11 g2'],
'hp chromebook 11 g3': ['hp chromebook 11 2100-2199 / hp chromebook 11 g3'],
'hp chromebook 11 g4/g4 ee': ['hp chromebook 11 2200-2299 / hp chromebook 11 g4/g4 ee'],
'hp chromebook 11 g5': ['hp chromebook 11 g5 / hp chromebook 11-vxxx'],
'hp chromebook 14a g5': ['hp chromebook 14 db0000-db0999'],
'hp chromebook 14 g3': ['hp chromebook 14 x000-x999 / hp chromebook 14 g3'],
'hp chromebook 14 g4': ['hp chromebook 14 ak000-099 / hp chromebook 14 g4'],
'hp chromebook 14 g5': ['hp chromebook 14 / hp chromebook 14 g5'],
'hp chromebox g1': ['hp chromebox cb1-(000-099) / hp chromebox g1/ hp chromebox for meetings'],
'lenovo ideapad c330 chromebook': ['lenovo chromebook c330'],
'lenovo ideapad s330 chromebook': ['lenovo chromebook s330'],
'lenovo n21 chromebook': ['asi chromebook', 'crambo chromebook', 'jp sa couto chromebook', 'rgs education chromebook', 'true idc chromebook', 'videonet chromebook', 'consumer chromebook'],
'lenovo thinkpad 11e 3rd gen chromebook': ['thinkpad 11e chromebook 3rd gen (yoga/clamshell)'],
'lenovo thinkpad 11e 4th gen chromebook': ['lenovo thinkpad 11e chromebook (4th gen)/lenovo thinkpad yoga 11e chromebook (4th gen)'],
'lenovo thinkpad 13': ['thinkpad 13 chromebook'],
'poin2 chromebook 14': ['poin2 chromebook 11c'],
'prowise chromebook eduline': ['viglen chromebook 11c'],
'prowise chromebook entryline': ['prowise 11.6\" entry line chromebook'],
'prowise chromebook proline': ['prowise proline chromebook'],
'samsung chromebook - xe303': ['samsung chromebook'],
}
next_data_is_oem = False
next_data_is_td = False
data_is_date = False
auepage = requests.get('https://support.google.com/chrome/a/answer/6220366?hl=en')
parser = MyHTMLParser()
parser.feed(auepage.content.decode('utf-8'))
print(json.dumps(output_rows, indent=2, sort_keys=True))

View File

@@ -623,8 +623,6 @@ CROS_SCALAR_PROPERTY_PRINT_ORDER = [
'manufactureDate',
'supportEndDate',
'autoUpdateExpiration',
'guessedAUEDate',
'guessedAUEModel',
'tpmVersionInfo',
'willAutoRenew',
]