phase 2 continued

This commit is contained in:
Jay Lee
2026-07-03 19:26:10 -04:00
parent 34e946d1d2
commit 7c639d3487
7 changed files with 136 additions and 561 deletions

View File

@@ -228,373 +228,22 @@ def redactable_debug_print(*args):
# Multiprocessing lock # Multiprocessing lock
mplock = None mplock = None
# stdin/stdout/stderr — extracted to gam.util.output # Imports used by __init__.py's own dispatch tables and functions
from util.output import readStdin # noqa: E402 from util.output import setSysExitRC, systemErrorExit, printErrorMessage # noqa: E402
from util.output import stdErrorExit # noqa: E402 from util.output import writeStderr, formatKeyValueList # noqa: E402
from util.output import writeStdout # noqa: E402
from util.output import flushStdout # noqa: E402
from util.output import writeStderr # noqa: E402
from util.output import flushStderr # noqa: E402
from util.output import setSysExitRC # noqa: E402
from util.output import stderrErrorMsg # noqa: E402
from util.output import stderrWarningMsg # noqa: E402
from util.output import systemErrorExit # noqa: E402
from util.output import printErrorMessage # noqa: E402
from util.output import printWarningMessage # noqa: E402
from util.output import supportsColoredText # noqa: E402
from util.output import createColoredText # noqa: E402
from util.output import createRedText # noqa: E402
from util.output import createGreenText # noqa: E402
from util.output import createYellowText # noqa: E402
from util.output import executeBatch # noqa: E402
from util.output import _stripControlCharsFromName # noqa: E402
from util.output import currentCount # noqa: E402
from util.output import currentCountNL # noqa: E402
from util.output import formatKeyValueList # noqa: E402
# File I/O — extracted to gam.util.fileio
from util.fileio import cleanFilename # noqa: E402
from util.fileio import setFilePath # noqa: E402
from util.fileio import uniqueFilename # noqa: E402
from util.fileio import cleanFilepath # noqa: E402
from util.fileio import fileErrorMessage # noqa: E402
from util.fileio import fdErrorMessage # noqa: E402
from util.fileio import setEncoding # noqa: E402
from util.fileio import StringIOobject # noqa: E402
from util.fileio import openFile # noqa: E402
from util.fileio import closeFile # noqa: E402
from util.fileio import readFile # noqa: E402
from util.fileio import writeFile # noqa: E402
from util.fileio import writeFileReturnError # noqa: E402
from util.fileio import deleteFile # noqa: E402
from util.fileio import getGDocSheetDataRetryWarning # noqa: E402
from util.fileio import getGDocSheetDataFailedExit # noqa: E402
from util.fileio import incrAPICallsRetryData # noqa: E402
from util.fileio import initAPICallsRateCheck # noqa: E402
from util.fileio import checkAPICallsRate # noqa: E402
from util.fileio import openGAMCommandLog # noqa: E402
from util.fileio import writeGAMCommandLog # noqa: E402
from util.fileio import closeGAMCommandLog # noqa: E402
# Display / warning / action — extracted to gam.util.display
from util.display import badRequestWarning # noqa: E402
from util.display import emptyQuery # noqa: E402
from util.display import invalidQuery # noqa: E402
from util.display import invalidMember # noqa: E402
from util.display import invalidUserSchema # noqa: E402
from util.display import userServiceNotEnabledWarning # noqa: E402
from util.display import userAlertsServiceNotEnabledWarning # noqa: E402
from util.display import userAnalyticsServiceNotEnabledWarning # noqa: E402
from util.display import userCalServiceNotEnabledWarning # noqa: E402
from util.display import userChatServiceNotEnabledWarning # noqa: E402
from util.display import userContactDelegateServiceNotEnabledWarning # noqa: E402
from util.display import userDriveServiceNotEnabledWarning # noqa: E402
from util.display import userKeepServiceNotEnabledWarning # noqa: E402
from util.display import userGmailServiceNotEnabledWarning # noqa: E402
from util.display import userLookerStudioServiceNotEnabledWarning # noqa: E402
from util.display import userPeopleServiceNotEnabledWarning # noqa: E402
from util.display import userTasksServiceNotEnabledWarning # noqa: E402
from util.display import userYouTubeServiceNotEnabledWarning # noqa: E402
from util.display import entityServiceNotApplicableWarning # noqa: E402
from util.display import entityDoesNotExistWarning # noqa: E402
from util.display import entityListDoesNotExistWarning # noqa: E402
from util.display import entityDoesNotHaveItemWarning # noqa: E402
from util.display import entityDuplicateWarning # noqa: E402
from util.display import entityActionFailedWarning # noqa: E402
from util.display import entityModifierItemValueListActionFailedWarning # noqa: E402
from util.display import entityModifierActionFailedWarning # noqa: E402
from util.display import entityModifierNewValueActionFailedWarning # noqa: E402
from util.display import entityNumEntitiesActionFailedWarning # noqa: E402
from util.display import entityActionNotPerformedWarning # noqa: E402
from util.display import entityItemValueListActionNotPerformedWarning # noqa: E402
from util.display import entityModifierItemValueListActionNotPerformedWarning # noqa: E402
from util.display import entityNumEntitiesActionNotPerformedWarning # noqa: E402
from util.display import entityBadRequestWarning # noqa: E402
from util.display import printGettingAllAccountEntities # noqa: E402
from util.display import printGotAccountEntities # noqa: E402
from util.display import setGettingAllEntityItemsForWhom # noqa: E402
from util.display import printGettingAllEntityItemsForWhom # noqa: E402
from util.display import printGotEntityItemsForWhom # noqa: E402
from util.display import printGettingEntityItem # noqa: E402
from util.display import printGettingEntityItemForWhom # noqa: E402
from util.display import stderrEntityMessage # noqa: E402
from util.display import FIRST_ITEM_MARKER # noqa: E402
from util.display import LAST_ITEM_MARKER # noqa: E402
from util.display import TOTAL_ITEMS_MARKER # noqa: E402
from util.display import getPageMessage # noqa: E402
from util.display import getPageMessageForWhom # noqa: E402
from util.display import printLine # noqa: E402
from util.display import printBlankLine # noqa: E402
from util.display import printKeyValueList # noqa: E402
from util.display import printKeyValueListWithCount # noqa: E402
from util.display import printKeyValueDict # noqa: E402
from util.display import printKeyValueWithCRsNLs # noqa: E402
from util.display import printJSONKey # noqa: E402
from util.display import printJSONValue # noqa: E402
from util.display import printEntity # noqa: E402
from util.display import printEntityMessage # noqa: E402
from util.display import printEntitiesCount # noqa: E402
from util.display import printEntityKVList # noqa: E402
from util.display import performAction # noqa: E402
from util.display import performActionNumItems # noqa: E402
from util.display import performActionModifierNumItems # noqa: E402
from util.display import actionPerformedNumItems # noqa: E402
from util.display import actionFailedNumItems # noqa: E402
from util.display import actionNotPerformedNumItemsWarning # noqa: E402
from util.display import entityPerformAction # noqa: E402
from util.display import entityPerformActionNumItems # noqa: E402
from util.display import entityPerformActionModifierNumItems # noqa: E402
from util.display import entityPerformActionNumItemsModifier # noqa: E402
from util.display import entityPerformActionSubItemModifierNumItems # noqa: E402
from util.display import entityPerformActionSubItemModifierNumItemsModifierNewValue # noqa: E402
from util.display import entityPerformActionModifierNumItemsModifier # noqa: E402
from util.display import entityPerformActionModifierItemValueList # noqa: E402
from util.display import entityPerformActionModifierNewValue # noqa: E402
from util.display import entityPerformActionModifierNewValueItemValueList # noqa: E402
from util.display import entityPerformActionItemValue # noqa: E402
from util.display import entityPerformActionInfo # noqa: E402
from util.display import entityActionPerformed # noqa: E402
from util.display import entityActionPerformedMessage # noqa: E402
from util.display import entityNumItemsActionPerformed # noqa: E402
from util.display import entityModifierActionPerformed # noqa: E402
from util.display import entityModifierItemValueListActionPerformed # noqa: E402
from util.display import entityModifierNewValueActionPerformed # noqa: E402
from util.display import entityModifierNewValueItemValueListActionPerformed # noqa: E402
from util.display import entityModifierNewValueKeyValueActionPerformed # noqa: E402
from util.errors import invalidClientSecretsJsonExit # noqa: E402
from util.errors import invalidOauth2serviceJsonExit # noqa: E402
from util.errors import invalidOauth2TxtExit # noqa: E402
from util.errors import expiredRevokedOauth2TxtExit # noqa: E402
from util.errors import invalidDiscoveryJsonExit # noqa: E402
from util.errors import entityActionFailedExit # noqa: E402
from util.errors import entityDoesNotExistExit # noqa: E402
from util.errors import entityDoesNotHaveItemExit # noqa: E402
from util.errors import entityIsNotUniqueExit # noqa: E402
from util.errors import usageErrorExit # noqa: E402
from util.errors import csvFieldErrorExit # noqa: E402
from util.errors import csvDataAlreadySavedErrorExit # noqa: E402
from util.errors import unknownArgumentExit # noqa: E402 from util.errors import unknownArgumentExit # noqa: E402
from util.errors import expectedArgumentExit # noqa: E402 from util.args import getArgument, getChoice, getInteger, getStringReturnInList # noqa: E402
from util.errors import blankArgumentExit # noqa: E402 from util.args import checkArgumentPresent, normalizeEmailAddressOrUID, NO_DEFAULT # noqa: E402
from util.errors import emptyArgumentExit # noqa: E402 from util.connection import doCheckConnection, doComment, doVersion, doUsage # noqa: E402
from util.errors import invalidArgumentExit # noqa: E402 from util.entity import getEntityArgument, getEntityList, getEntityToModify # noqa: E402
from util.errors import missingArgumentExit # noqa: E402
from util.errors import deprecatedArgument # noqa: E402
from util.errors import deprecatedArgumentExit # noqa: E402
from util.errors import deprecatedCommandExit # noqa: E402
from util.errors import formatChoiceList # noqa: E402
from util.errors import invalidChoiceExit # noqa: E402
from util.errors import missingChoiceExit # noqa: E402
from util.args import * # noqa: E402,F403 - re-exports ~155 symbols
from util.connection import getLocalGoogleTimeOffset # noqa: E402
from util.connection import _getServerTLSUsed # noqa: E402
from util.connection import getOSPlatform # noqa: E402
from util.connection import inspect_untrusted_cert # noqa: E402
from util.connection import doCheckConnection # noqa: E402
from util.connection import doComment # noqa: E402
from util.connection import doVersion # noqa: E402
from util.connection import doUsage # noqa: E402
from util.connection import MACOS_CODENAMES # noqa: E402
# API transport, service builders, and call wrappers — extracted to gam.util.api
from util.api import handleServerError # noqa: E402
from util.api import getHttpObj # noqa: E402
from util.api import _force_user_agent # noqa: E402
from util.api import transportAgentRequest # noqa: E402
from util.api import transportAuthorizedHttp # noqa: E402
from util.api import transportCreateRequest # noqa: E402
from util.api import doGAMCheckForUpdates # noqa: E402
from util.api import signjwtJWTCredentials # noqa: E402
from util.api import signjwtCredentials # noqa: E402
from util.api import get_adc_request # noqa: E402
from util.api import signjwtSignJwt # noqa: E402
from util.api import handleOAuthTokenError # noqa: E402
from util.api import getOauth2TxtCredentials # noqa: E402
from util.api import _getValueFromOAuth # noqa: E402
from util.api import _getAdminEmail # noqa: E402
from util.api import writeClientCredentials # noqa: E402
from util.api import shortenURL # noqa: E402
from util.api import runSqliteQuery # noqa: E402
from util.api import refreshCredentialsWithReauth # noqa: E402
from util.api import getClientCredentials # noqa: E402
from util.api import waitOnFailure # noqa: E402
from util.api import clearServiceCache # noqa: E402
from util.api import getAPIService # noqa: E402
from util.api import getService # noqa: E402
from util.api import defaultSvcAcctScopes # noqa: E402
from util.api import _getSvcAcctData # noqa: E402
from util.api import getSvcAcctCredentials # noqa: E402
from util.api import getGDataOAuthToken # noqa: E402
from util.api import checkGDataError # noqa: E402
from util.api import callGData # noqa: E402
from util.api import callGDataPages # noqa: E402
from util.api import checkGAPIError # noqa: E402
from util.api import callGAPI # noqa: E402
from util.api import _showGAPIpagesResult # noqa: E402
from util.api import callGAPIpages # noqa: E402
from util.api import yieldGAPIpages # noqa: E402
from util.api import callGAPIitems # noqa: E402
from util.api import readDiscoveryFile # noqa: E402
from util.api import buildGAPIObject # noqa: E402
from util.api import buildGAPIServiceObject # noqa: E402
from util.api import buildGAPIObjectNoAuthentication # noqa: E402
from util.api import initGDataObject # noqa: E402
from util.api import getGDataUserCredentials # noqa: E402
from util.api import getContactsObject # noqa: E402
from util.api import getContactsQuery # noqa: E402
from util.api import getEmailAuditObject # noqa: E402
from util.api import _processGAPIpagesResult # noqa: E402
from util.api import _finalizeGAPIpagesResult # noqa: E402
from util.api import _setMaxArgResults # noqa: E402
from util.api import writeGotMessage # noqa: E402
from util.api import getSaUser # noqa: E402
from util.api import chooseSaAPI # noqa: E402
# Entity resolution — extracted to gam.util.entity
from util.entity import getUserEmailFromID # noqa: E402
from util.entity import getGroupEmailFromID # noqa: E402
from util.entity import getServiceAccountEmailFromID # noqa: E402
from util.entity import convertUIDtoEmailAddressWithType # noqa: E402
from util.entity import NON_EMAIL_MEMBER_PREFIXES # noqa: E402
from util.entity import convertUIDtoEmailAddress # noqa: E402
from util.entity import convertEmailAddressToUID # noqa: E402
from util.entity import convertUserIDtoEmail # noqa: E402
from util.entity import splitEmailAddressOrUID # noqa: E402
from util.entity import convertOrgUnitIDtoPath # noqa: E402
from util.entity import shlexSplitList # noqa: E402
from util.entity import shlexSplitListStatus # noqa: E402
from util.entity import getQueries # noqa: E402
from util.entity import _validateDeviceQuery # noqa: E402
from util.entity import getDeviceQueries # noqa: E402
from util.entity import convertEntityToList # noqa: E402
from util.entity import GROUP_ROLES_MAP # noqa: E402
from util.entity import ALL_GROUP_ROLES # noqa: E402
from util.entity import _getRoleVerification # noqa: E402
from util.entity import _getCIRoleVerification # noqa: E402
from util.entity import _checkMemberStatusIsSuspendedIsArchived # noqa: E402
from util.entity import _checkMemberIsSuspendedIsArchived # noqa: E402
from util.entity import _checkMemberRole # noqa: E402
from util.entity import _checkMemberRoleIsSuspendedIsArchived # noqa: E402
from util.entity import _checkMemberCategory # noqa: E402
from util.entity import _checkCIMemberCategory # noqa: E402
from util.entity import getCIGroupMemberRoleFixType # noqa: E402
from util.entity import getCIGroupTransitiveMemberRoleFixType # noqa: E402
from util.entity import convertGroupCloudIDToEmail # noqa: E402
from util.entity import convertGroupEmailToCloudID # noqa: E402
from util.entity import CIGROUP_DISCUSSION_FORUM_LABEL # noqa: E402
from util.entity import CIGROUP_DYNAMIC_LABEL # noqa: E402
from util.entity import CIGROUP_SECURITY_LABEL # noqa: E402
from util.entity import CIGROUP_LOCKED_LABEL # noqa: E402
from util.entity import getCIGroupMembershipGraph # noqa: E402
from util.entity import checkGroupExists # noqa: E402
from util.entity import getItemsToModify # noqa: E402
from util.entity import splitEntityList # noqa: E402
from util.entity import splitEntityListShlex # noqa: E402
from util.entity import fileDataErrorExit # noqa: E402
from util.entity import getEntitiesFromFile # noqa: E402
from util.entity import getEntitiesFromCSVFile # noqa: E402
from util.entity import getEntitiesFromCSVbyField # noqa: E402
from util.entity import mapEntityType # noqa: E402
from util.entity import getEntityArgument # noqa: E402
from util.entity import getEntityToModify # noqa: E402
from util.entity import getEntitySelector # noqa: E402
from util.entity import getEntitySelection # noqa: E402
from util.entity import getEntityList # noqa: E402
from util.entity import getNormalizedEmailAddressEntity # noqa: E402
from util.entity import getUserObjectEntity # noqa: E402
from util.entity import _validateUserGetObjectList # noqa: E402
from util.entity import _validateUserGetMessageIds # noqa: E402
from util.entity import checkUserExists # noqa: E402
from util.entity import checkUserSuspended # noqa: E402
# CSV Print Framework — extracted to gam.util.csv_pf
from util.csv_pf import addFieldToFieldsList # noqa: E402
from util.csv_pf import _getFieldsList # noqa: E402
from util.csv_pf import _getRawFields # noqa: E402
from util.csv_pf import CheckInputRowFilterHeaders # noqa: E402
from util.csv_pf import RowFilterMatch # noqa: E402
from util.csv_pf import getFieldsList # noqa: E402
from util.csv_pf import getFieldsFromFieldsList # noqa: E402
from util.csv_pf import getItemFieldsFromFieldsList # noqa: E402
from util.csv_pf import CSVPrintFile # noqa: E402
from util.csv_pf import writeEntityNoHeaderCSVFile # noqa: E402
from util.csv_pf import getTodriveOnly # noqa: E402
from util.csv_pf import DEFAULT_SKIP_OBJECTS # noqa: E402
from util.csv_pf import cleanJSON # noqa: E402
from util.csv_pf import flattenJSON # noqa: E402
from util.csv_pf import showJSON # noqa: E402
from util.csv_pf import FormatJSONQuoteChar # noqa: E402
from util.csv_pf import RI_ENTITY # noqa: E402
from util.csv_pf import RI_I # noqa: E402
from util.csv_pf import RI_COUNT # noqa: E402
from util.csv_pf import RI_J # noqa: E402
from util.csv_pf import RI_JCOUNT # noqa: E402
from util.csv_pf import RI_ITEM # noqa: E402
from util.csv_pf import RI_ROLE # noqa: E402
from util.csv_pf import RI_OPTION # noqa: E402
from util.csv_pf import batchRequestID # noqa: E402
# OrgUnit helpers — extracted to gam.util.orgunits
from util.orgunits import getOrgUnitItem # noqa: E402
from util.orgunits import getTopLevelOrgId # noqa: E402
from util.orgunits import getOrgUnitId # noqa: E402
from util.orgunits import getAllParentOrgUnitsForUser # noqa: E402
# GDoc/GSheet/Storage/CSV readers — extracted to gam.util.gdoc
from util.gdoc import GDOC_FORMAT_MIME_TYPES # noqa: E402
from util.gdoc import getGDocData # noqa: E402
from util.gdoc import HTML_TITLE_PATTERN # noqa: E402
from util.gdoc import getGSheetData # noqa: E402
from util.gdoc import BUCKET_OBJECT_PATTERNS # noqa: E402
from util.gdoc import getBucketObjectName # noqa: E402
from util.gdoc import GCS_FORMAT_MIME_TYPES # noqa: E402
from util.gdoc import getStorageFileData # noqa: E402
from util.gdoc import openCSVFileReader # noqa: E402
# Configuration — extracted to gam.util.config
from util.config import SetGlobalVariables # noqa: E402 from util.config import SetGlobalVariables # noqa: E402
# Batch/multiprocess infrastructure — extracted to gam.util.batch from util.fileio import closeGAMCommandLog, writeGAMCommandLog # noqa: E402
from util.batch import NullHandler # noqa: E402 from util.batch import ( # noqa: E402
from util.batch import initializeLogging # noqa: E402 batchWriteStderr, doBatch, doThreadBatch, doAutoBatch,
from util.batch import saveNonPickleableValues # noqa: E402 doCSV, doCSVTest, doLoop, doListType, doListCrOS, doListUser,
from util.batch import restoreNonPickleableValues # noqa: E402 showCountCrOS, showCountUser,
from util.batch import CSVFileQueueHandler # noqa: E402 )
from util.batch import initializeCSVFileQueueHandler # noqa: E402
from util.batch import terminateCSVFileQueueHandler # noqa: E402
from util.batch import StdQueueHandler # noqa: E402
from util.batch import initializeStdQueueHandler # noqa: E402
from util.batch import batchWriteStderr # noqa: E402
from util.batch import writeStdQueueHandler # noqa: E402
from util.batch import terminateStdQueueHandler # noqa: E402
from util.batch import ProcessGAMCommandMulti # noqa: E402
from util.batch import checkChildProcessRC # noqa: E402
from util.batch import initGamWorker # noqa: E402
from util.batch import MultiprocessGAMCommands # noqa: E402
from util.batch import threadBatchWorker # noqa: E402
from util.batch import ThreadBatchGAMCommands # noqa: E402
from util.batch import _getShowCommands # noqa: E402
from util.batch import _getSkipRows # noqa: E402
from util.batch import _getMaxRows # noqa: E402
from util.batch import doBatch # noqa: E402
from util.batch import doThreadBatch # noqa: E402
from util.batch import doAutoBatch # noqa: E402
from util.batch import getSubFields # noqa: E402
from util.batch import processSubFields # noqa: E402
from util.batch import doCSV # noqa: E402
from util.batch import doCSVTest # noqa: E402
from util.batch import doLoop # noqa: E402
from util.batch import _doList # noqa: E402
from util.batch import doListType # noqa: E402
from util.batch import doListCrOS # noqa: E402
from util.batch import doListUser # noqa: E402
from util.batch import _showCount # noqa: E402
from util.batch import showCountCrOS # noqa: E402
from util.batch import showCountUser # noqa: E402
# Command module re-exports for routing tables
# Command function references (lazy-loaded at first call)
# These replace the old `from gam.cmd.X import func` re-exports
# gam.cmd.admin
# Command module imports # Command module imports
from gam.cmd.admin import ( from gam.cmd.admin import (
@@ -1504,46 +1153,7 @@ def doResetYubiKeyPIV():
yk.reset_piv() yk.reset_piv()
# Audit command utilities
def ACLRuleDict(rule):
if rule['scope']['type'] != 'default':
return {'Scope': f'{rule["scope"]["type"]}:{rule["scope"]["value"]}', 'Role': rule['role']}
return {'Scope': f'{rule["scope"]["type"]}', 'Role': rule['role']}
def ACLRuleKeyValueList(rule):
if rule['scope']['type'] != 'default':
return ['Scope', f'{rule["scope"]["type"]}:{rule["scope"]["value"]}', 'Role', rule['role']]
return ['Scope', f'{rule["scope"]["type"]}', 'Role', rule['role']]
def formatACLRule(rule):
return formatKeyValueList('(', ACLRuleKeyValueList(rule), ')')
def formatACLScopeRole(scope, role):
if role:
return formatKeyValueList('(', ['Scope', scope, 'Role', role], ')')
return formatKeyValueList('(', ['Scope', scope], ')')
def normalizeRuleId(ruleId):
ruleIdParts = ruleId.split(':', 1)
if (len(ruleIdParts) == 1) or not ruleIdParts[1]:
if ruleIdParts[0] == 'default':
return ruleId
if ruleIdParts[0] == 'domain':
return f'domain:{GC.Values[GC.DOMAIN]}'
return f'user:{normalizeEmailAddressOrUID(ruleIdParts[0], noUid=True)}'
if ruleIdParts[0] in {'user', 'group'}:
return f'{ruleIdParts[0]}:{normalizeEmailAddressOrUID(ruleIdParts[1], noUid=True)}'
return ruleId
def makeRoleRuleIdBody(role, ruleId):
ruleIdParts = ruleId.split(':', 1)
if len(ruleIdParts) == 1:
if ruleIdParts[0] == 'default':
return {'role': role, 'scope': {'type': ruleIdParts[0]}}
if ruleIdParts[0] == 'domain':
return {'role': role, 'scope': {'type': ruleIdParts[0], 'value': GC.Values[GC.DOMAIN]}}
return {'role': role, 'scope': {'type': 'user', 'value': ruleIdParts[0]}}
return {'role': role, 'scope': {'type': ruleIdParts[0], 'value': ruleIdParts[1]}}
BUILDING_ADDRESS_FIELD_MAP = { BUILDING_ADDRESS_FIELD_MAP = {
'address': 'addressLines', 'address': 'addressLines',

View File

@@ -22,9 +22,10 @@ import platform
import sys import sys
import gam import gam
from gam.util.batch import initializeLogging
def main(): def main():
gam.initializeLogging() initializeLogging()
rc = gam.ProcessGAMCommand(sys.argv) rc = gam.ProcessGAMCommand(sys.argv)
try: try:
sys.stdout.flush() sys.stdout.flush()

View File

@@ -25,10 +25,7 @@ import string
import sys import sys
from gam import mplock from gam import mplock
from gam.util.output import systemErrorExit, readStdin, writeStdout
from gam import systemErrorExit
from gam import readStdin
from gam import writeStdout
from gam.gamlib import glmsgs as Msg from gam.gamlib import glmsgs as Msg

View File

@@ -76,6 +76,7 @@ import calendar
import datetime import datetime
import json import json
import re import re
import shlex
import sys import sys
import arrow import arrow
@@ -1629,3 +1630,22 @@ def substituteQueryTimes(queries, queryTimes):
def _getFilterDateTime(): def _getFilterDateTime():
filterDate = getYYYYMMDD(returnDateTime=True) filterDate = getYYYYMMDD(returnDateTime=True)
return (filterDate, filterDate.replace(tzinfo='UTC')) return (filterDate, filterDate.replace(tzinfo='UTC'))
def shlexSplitList(entity, dataDelimiter=' ,'):
lexer = shlex.shlex(entity, posix=True)
lexer.whitespace = dataDelimiter
lexer.whitespace_split = True
try:
return list(lexer)
except ValueError as e:
Cmd.Backup()
usageErrorExit(str(e))
def shlexSplitListStatus(entity, dataDelimiter=' ,'):
lexer = shlex.shlex(entity, posix=True)
lexer.whitespace = dataDelimiter
lexer.whitespace_split = True
try:
return (True, list(lexer))
except ValueError as e:
return (False, str(e))

View File

@@ -37,70 +37,38 @@ from util.args import integerLimits
from util.args import LOCALE_CODES_MAP from util.args import LOCALE_CODES_MAP
from util.args import LANGUAGE_CODES_MAP from util.args import LANGUAGE_CODES_MAP
from util.args import TIMEZONE_FORMAT_REQUIRED from util.args import TIMEZONE_FORMAT_REQUIRED
from util.args import (
checkArgumentPresent, getArgument, getBoolean, getCharacter, getChoice,
getFloat, getInteger, getLanguageCode, getREPattern, getString,
shlexSplitList, shlexSplitListStatus,
Cmd, FALSE, FALSE_VALUES, TRUE, TRUE_FALSE, TRUE_VALUES, UTF8,
)
from util.csv_pf import CSVPrintFile from util.csv_pf import CSVPrintFile
from util.display import printKeyValueList, printLine
from util.entity import getEntitiesFromCSVFile from util.entity import getEntitiesFromCSVFile
from util.entity import getEntitiesFromFile from util.entity import getEntitiesFromFile
from util.fileio import initAPICallsRateCheck from util.errors import formatChoiceList, usageErrorExit, USAGE_ERROR_RC
from util.fileio import openGAMCommandLog from util.fileio import (
from util.fileio import StringIOobject initAPICallsRateCheck, openGAMCommandLog, StringIOobject,
deleteFile, fileErrorMessage, openFile, readFile, setFilePath, writeFile,
FILE_ERROR_RC,
def _getMain(): )
return sys.modules['gam'] from util.output import (
ERROR_PREFIX, WARNING, WARNING_PREFIX,
formatKeyValueList, printErrorMessage, stderrErrorMsg, systemErrorExit,
writeStderr,
)
from gam.constants import (
CONFIG_ERROR_RC, DEFAULT_FILE_APPEND_MODE, DEFAULT_FILE_READ_MODE,
DEFAULT_FILE_WRITE_MODE, EV_GAMCFGDIR, EV_GAMCFGSECTION, EV_OLDGAMPATH,
FN_GAM_CFG, GAM,
)
def SetGlobalVariables(): def SetGlobalVariables():
_main = _getMain() # redactable_debug_print is defined in gam.__init__ — access at call time
Cmd = _main.Cmd # to avoid circular import (gam imports from us during init)
checkArgumentPresent = _main.checkArgumentPresent redactable_debug_print = sys.modules['gam'].redactable_debug_print
getBoolean = _main.getBoolean
getCharacter = _main.getCharacter
getChoice = _main.getChoice
getString = _main.getString
getInteger = _main.getInteger
getFloat = _main.getFloat
getLanguageCode = _main.getLanguageCode
getREPattern = _main.getREPattern
getArgument = _main.getArgument
systemErrorExit = _main.systemErrorExit
stderrErrorMsg = _main.stderrErrorMsg
printErrorMessage = _main.printErrorMessage
printKeyValueList = _main.printKeyValueList
printLine = _main.printLine
writeStderr = _main.writeStderr
openFile = _main.openFile
readFile = _main.readFile
writeFile = _main.writeFile
deleteFile = _main.deleteFile
fileErrorMessage = _main.fileErrorMessage
setFilePath = _main.setFilePath
usageErrorExit = _main.usageErrorExit
formatChoiceList = _main.formatChoiceList
formatKeyValueList = _main.formatKeyValueList
shlexSplitList = _main.shlexSplitList
shlexSplitListStatus = _main.shlexSplitListStatus
FN_GAM_CFG = _main.FN_GAM_CFG
UTF8 = _main.UTF8
USAGE_ERROR_RC = _main.USAGE_ERROR_RC
CONFIG_ERROR_RC = _main.CONFIG_ERROR_RC
FILE_ERROR_RC = _main.FILE_ERROR_RC
# Constants from __init__.py needed by SetGlobalVariables
GAM = _main.GAM
TRUE = _main.TRUE
FALSE = _main.FALSE
TRUE_VALUES = _main.TRUE_VALUES
FALSE_VALUES = _main.FALSE_VALUES
TRUE_FALSE = _main.TRUE_FALSE
ERROR_PREFIX = _main.ERROR_PREFIX
WARNING = _main.WARNING
WARNING_PREFIX = _main.WARNING_PREFIX
EV_GAMCFGDIR = _main.EV_GAMCFGDIR
EV_GAMCFGSECTION = _main.EV_GAMCFGSECTION
EV_OLDGAMPATH = _main.EV_OLDGAMPATH
DEFAULT_FILE_APPEND_MODE = _main.DEFAULT_FILE_APPEND_MODE
DEFAULT_FILE_READ_MODE = _main.DEFAULT_FILE_READ_MODE
DEFAULT_FILE_WRITE_MODE = _main.DEFAULT_FILE_WRITE_MODE
redactable_debug_print = _main.redactable_debug_print
def _stringInQuotes(value): def _stringInQuotes(value):

View File

@@ -21,29 +21,30 @@ from gamlib import glglobals as GM
from gamlib import glmsgs as Msg from gamlib import glmsgs as Msg
from gamlib import glverlibs from gamlib import glverlibs
from gam.constants import (
FN_GAMCOMMANDS_TXT, GAM, GAM_URL, GAM_WIKI,
GOOGLE_TIMECHECK_LOCATION, MAX_LOCAL_GOOGLE_TIME_OFFSET, NETWORK_ERROR_RC,
SECONDS_PER_DAY, SECONDS_PER_HOUR, SECONDS_PER_MINUTE,
)
from util.args import ISOformatTimeStamp, getArgument, getString, todaysTime
from util.display import printBlankLine, printKeyValueList
from util.errors import unknownArgumentExit
from util.output import (
createGreenText, createRedText, createYellowText,
flushStdout, stderrWarningMsg, systemErrorExit, writeStdout,
)
from util.api import doGAMCheckForUpdates, getHttpObj, getService, handleServerError, waitOnFailure
class _InstanceProxy: # gam.__init__ attributes that can't be imported at module level
"""Lazy proxy that delegates attribute access to a named instance in the gam module.""" # (connection.py is imported BY __init__.py during init)
def __init__(self, name): _gam = lambda: sys.modules['gam']
self._name = name
def __getattr__(self, attr):
return getattr(getattr(sys.modules['gam'], self._name), attr)
Cmd = _InstanceProxy('Cmd')
def _getEnt():
return sys.modules['gam'].Ent
def _getMain():
return sys.modules['gam']
# --- Constants --- # --- Constants ---
def _buildTimeOffsetUnits(): def _buildTimeOffsetUnits():
m = _getMain() return [('day', SECONDS_PER_DAY), ('hour', SECONDS_PER_HOUR),
return [('day', m.SECONDS_PER_DAY), ('hour', m.SECONDS_PER_HOUR), ('minute', SECONDS_PER_MINUTE), ('second', 1)]
('minute', m.SECONDS_PER_MINUTE), ('second', 1)]
MACOS_CODENAMES = { MACOS_CODENAMES = {
10: { 10: {
@@ -70,31 +71,30 @@ MACOS_CODENAMES = {
# --- Functions --- # --- Functions ---
def getLocalGoogleTimeOffset(testLocation=None): def getLocalGoogleTimeOffset(testLocation=None):
m = _getMain()
if testLocation is None: if testLocation is None:
testLocation = m.GOOGLE_TIMECHECK_LOCATION testLocation = GOOGLE_TIMECHECK_LOCATION
TIME_OFFSET_UNITS = _buildTimeOffsetUnits() TIME_OFFSET_UNITS = _buildTimeOffsetUnits()
# If local time is well off, it breaks https because the server certificate will be seen as too old or new and thus invalid; http doesn't have that issue. # If local time is well off, it breaks https because the server certificate will be seen as too old or new and thus invalid; http doesn't have that issue.
# Try with http first, if time is close (<MAX_LOCAL_GOOGLE_TIME_OFFSET seconds), retry with https as it should be OK # Try with http first, if time is close (<MAX_LOCAL_GOOGLE_TIME_OFFSET seconds), retry with https as it should be OK
httpObj = m.getHttpObj() httpObj = getHttpObj()
for prot in ['http', 'https']: for prot in ['http', 'https']:
try: try:
headerData = httpObj.request(f'{prot}://'+testLocation, 'HEAD') headerData = httpObj.request(f'{prot}://'+testLocation, 'HEAD')
googleUTC = arrow.Arrow.strptime(headerData[0]['date'], '%a, %d %b %Y %H:%M:%S %Z', tzinfo='UTC') googleUTC = arrow.Arrow.strptime(headerData[0]['date'], '%a, %d %b %Y %H:%M:%S %Z', tzinfo='UTC')
except (httplib2.HttpLib2Error, RuntimeError) as e: except (httplib2.HttpLib2Error, RuntimeError) as e:
m.handleServerError(e) handleServerError(e)
except httplib2.socks.HTTPError as e: except httplib2.socks.HTTPError as e:
# If user has specified an HTTPS proxy, the http request will probably fail as httplib2 # If user has specified an HTTPS proxy, the http request will probably fail as httplib2
# turns a GET into a CONNECT which is not valid for an http address # turns a GET into a CONNECT which is not valid for an http address
if prot == 'http': if prot == 'http':
continue continue
m.handleServerError(e) handleServerError(e)
except (ValueError, KeyError): except (ValueError, KeyError):
if prot == 'http': if prot == 'http':
continue continue
m.systemErrorExit(m.NETWORK_ERROR_RC, Msg.INVALID_HTTP_HEADER.format(str(headerData))) systemErrorExit(NETWORK_ERROR_RC, Msg.INVALID_HTTP_HEADER.format(str(headerData)))
offset = remainder = int(abs((arrow.utcnow()-googleUTC).total_seconds())) offset = remainder = int(abs((arrow.utcnow()-googleUTC).total_seconds()))
if offset < m.MAX_LOCAL_GOOGLE_TIME_OFFSET and prot == 'http': if offset < MAX_LOCAL_GOOGLE_TIME_OFFSET and prot == 'http':
continue continue
timeoff = [] timeoff = []
for tou in TIME_OFFSET_UNITS: for tou in TIME_OFFSET_UNITS:
@@ -107,23 +107,22 @@ def getLocalGoogleTimeOffset(testLocation=None):
return (offset, nicetime) return (offset, nicetime)
def _getServerTLSUsed(location): def _getServerTLSUsed(location):
m = _getMain()
url = 'https://'+location url = 'https://'+location
_, netloc, _, _, _, _ = urlparse(url) _, netloc, _, _, _, _ = urlparse(url)
conn = 'https:'+netloc conn = 'https:'+netloc
httpObj = m.getHttpObj() httpObj = getHttpObj()
triesLimit = 5 triesLimit = 5
for n in range(1, triesLimit+1): for n in range(1, triesLimit+1):
try: try:
httpObj.request(url, headers={'user-agent': m.GAM_USER_AGENT}) httpObj.request(url, headers={'user-agent': _gam().GAM_USER_AGENT})
cipher_name, tls_ver, _ = httpObj.connections[conn].sock.cipher() cipher_name, tls_ver, _ = httpObj.connections[conn].sock.cipher()
return tls_ver, cipher_name return tls_ver, cipher_name
except (httplib2.HttpLib2Error, RuntimeError) as e: except (httplib2.HttpLib2Error, RuntimeError) as e:
if n != triesLimit: if n != triesLimit:
httpObj.connections = {} httpObj.connections = {}
m.waitOnFailure(n, triesLimit, m.NETWORK_ERROR_RC, str(e)) waitOnFailure(n, triesLimit, NETWORK_ERROR_RC, str(e))
continue continue
m.handleServerError(e) handleServerError(e)
def getOSPlatform(): def getOSPlatform():
myos = platform.system() myos = platform.system()
@@ -175,7 +174,6 @@ def inspect_untrusted_cert(url):
# gam checkconnection # gam checkconnection
def doCheckConnection(): def doCheckConnection():
m = _getMain()
def check_host(host): def check_host(host):
nonlocal try_count, okay, not_okay, success_count nonlocal try_count, okay, not_okay, success_count
@@ -189,10 +187,10 @@ def doCheckConnection():
except Exception as e: except Exception as e:
dns_err = f'{not_okay}\n Unknown DNS failure: {str(e)}\n' dns_err = f'{not_okay}\n Unknown DNS failure: {str(e)}\n'
check_line = f'Checking {host} ({ip}) ({try_count})...' check_line = f'Checking {host} ({ip}) ({try_count})...'
m.writeStdout(f'{check_line:<100}') writeStdout(f'{check_line:<100}')
m.flushStdout() flushStdout()
if dns_err: if dns_err:
m.writeStdout(dns_err) writeStdout(dns_err)
return return
gen_firewall = 'You probably have security software or a firewall on your machine or network that is preventing GAM from making Internet connections. Check your network configuration or try running GAM on a hotspot or home network to see if the problem exists only on your organization\'s network.' gen_firewall = 'You probably have security software or a firewall on your machine or network that is preventing GAM from making Internet connections. Check your network configuration or try running GAM on a hotspot or home network to see if the problem exists only on your organization\'s network.'
try: try:
@@ -202,37 +200,37 @@ def doCheckConnection():
url = f'https://{host}:443/' url = f'https://{host}:443/'
httpObj.request(url, 'HEAD', headers=headers) httpObj.request(url, 'HEAD', headers=headers)
success_count += 1 success_count += 1
m.writeStdout(f'{okay}\n') writeStdout(f'{okay}\n')
except ConnectionRefusedError: except ConnectionRefusedError:
m.writeStdout(f'{not_okay}\n Connection refused. {gen_firewall}\n') writeStdout(f'{not_okay}\n Connection refused. {gen_firewall}\n')
except ConnectionResetError: except ConnectionResetError:
m.writeStdout(f'{not_okay}\n Connection reset by peer. {gen_firewall}\n') writeStdout(f'{not_okay}\n Connection reset by peer. {gen_firewall}\n')
except httplib2.error.ServerNotFoundError: except httplib2.error.ServerNotFoundError:
m.writeStdout(f'{not_okay}\n Failed to find server. Your DNS is probably misconfigured.\n') writeStdout(f'{not_okay}\n Failed to find server. Your DNS is probably misconfigured.\n')
except ssl.SSLCertVerificationError as e: except ssl.SSLCertVerificationError as e:
diag_info = inspect_untrusted_cert(host) diag_info = inspect_untrusted_cert(host)
# e.verify_message contains the specific OpenSSL error string # e.verify_message contains the specific OpenSSL error string
m.writeStdout(f'{not_okay}\n Certificate verification failed: {e.verify_message}\n Diagnostic Info:\n {diag_info}\nIf you are behind a firewall / proxy server that does TLS / SSL inspection you may need to point GAM at your certificate authority file by setting cacerts_pem = /path/to/your/certauth.pem in gam.cfg.\n') writeStdout(f'{not_okay}\n Certificate verification failed: {e.verify_message}\n Diagnostic Info:\n {diag_info}\nIf you are behind a firewall / proxy server that does TLS / SSL inspection you may need to point GAM at your certificate authority file by setting cacerts_pem = /path/to/your/certauth.pem in gam.cfg.\n')
except ssl.SSLError as e: except ssl.SSLError as e:
if e.reason == 'SSLV3_ALERT_HANDSHAKE_FAILURE': if e.reason == 'SSLV3_ALERT_HANDSHAKE_FAILURE':
m.writeStdout(f'{not_okay}\n GAM expects to connect with TLS 1.3 or newer and that failed. If your firewall / proxy server is not compatible with TLS 1.3 then you can tell GAM to allow TLS 1.2 by setting tls_min_version = TLSv1.2 in gam.cfg.\n') writeStdout(f'{not_okay}\n GAM expects to connect with TLS 1.3 or newer and that failed. If your firewall / proxy server is not compatible with TLS 1.3 then you can tell GAM to allow TLS 1.2 by setting tls_min_version = TLSv1.2 in gam.cfg.\n')
elif e.reason == 'CERTIFICATE_VERIFY_FAILED': elif e.reason == 'CERTIFICATE_VERIFY_FAILED':
m.writeStdout(f'{not_okay}\n Certificate verification failed. If you are behind a firewall / proxy server that does TLS / SSL inspection you may need to point GAM at your certificate authority file by setting cacerts_pem = /path/to/your/certauth.pem in gam.cfg.\n') writeStdout(f'{not_okay}\n Certificate verification failed. If you are behind a firewall / proxy server that does TLS / SSL inspection you may need to point GAM at your certificate authority file by setting cacerts_pem = /path/to/your/certauth.pem in gam.cfg.\n')
elif e.strerror and e.strerror.startswith('TLS/SSL connection has been closed\n'): elif e.strerror and e.strerror.startswith('TLS/SSL connection has been closed\n'):
m.writeStdout(f'{not_okay}\n TLS connection was closed. {gen_firewall}\n') writeStdout(f'{not_okay}\n TLS connection was closed. {gen_firewall}\n')
else: else:
m.writeStdout(f'{not_okay}\n {str(e)}\n') writeStdout(f'{not_okay}\n {str(e)}\n')
except TimeoutError: except TimeoutError:
m.writeStdout(f'{not_okay}\n Timed out trying to connect to host\n') writeStdout(f'{not_okay}\n Timed out trying to connect to host\n')
except Exception as e: except Exception as e:
m.writeStdout(f'{not_okay}\n {str(e)}\n') writeStdout(f'{not_okay}\n {str(e)}\n')
try_count = 0 try_count = 0
httpObj = m.getHttpObj(timeout=30) httpObj = getHttpObj(timeout=30)
httpObj.follow_redirects = False httpObj.follow_redirects = False
headers = {'user-agent': m.GAM_USER_AGENT} headers = {'user-agent': _gam().GAM_USER_AGENT}
okay = m.createGreenText('OK') okay = createGreenText('OK')
not_okay = m.createRedText('ERROR') not_okay = createRedText('ERROR')
success_count = 0 success_count = 0
initial_hosts = ['api.github.com', initial_hosts = ['api.github.com',
'raw.githubusercontent.com', 'raw.githubusercontent.com',
@@ -265,34 +263,33 @@ def doCheckConnection():
for api in API._INFO: for api in API._INFO:
if api in [API.CONTACTS, API.EMAIL_AUDIT]: if api in [API.CONTACTS, API.EMAIL_AUDIT]:
continue continue
svc = m.getService(api, httpObj) svc = getService(api, httpObj)
base_url = svc._rootDesc.get('baseUrl') base_url = svc._rootDesc.get('baseUrl')
parsed_base_url = urlparse(base_url) parsed_base_url = urlparse(base_url)
base_host = parsed_base_url.netloc base_host = parsed_base_url.netloc
if base_host not in checked_hosts: if base_host not in checked_hosts:
m.writeStdout(f'Checking {base_host} for {api}\n') writeStdout(f'Checking {base_host} for {api}\n')
check_host(base_host) check_host(base_host)
checked_hosts.append(base_host) checked_hosts.append(base_host)
if success_count == try_count: if success_count == try_count:
m.writeStdout(m.createGreenText('All hosts passed!\n')) writeStdout(createGreenText('All hosts passed!\n'))
else: else:
m.systemErrorExit(3, m.createYellowText('Some hosts failed to connect! Please follow the recommendations for those hosts to correct any issues and try again.')) systemErrorExit(3, createYellowText('Some hosts failed to connect! Please follow the recommendations for those hosts to correct any issues and try again.'))
# gam comment # gam comment
def doComment(): def doComment():
m = _getMain() writeStdout(_gam().Cmd.QuotedArgumentList(_gam().Cmd.Remaining())+'\n')
m.writeStdout(Cmd.QuotedArgumentList(Cmd.Remaining())+'\n')
# gam version [check|checkrc|simple|extended] [timeoffset] [nooffseterror] [location <HostName>] # gam version [check|checkrc|simple|extended] [timeoffset] [nooffseterror] [location <HostName>]
def doVersion(checkForArgs=True): def doVersion(checkForArgs=True):
m = _getMain() Ent = _gam().Ent
Ent = _getEnt() Cmd = _gam().Cmd
forceCheck = 0 forceCheck = 0
extended = noOffsetError = timeOffset = simple = False extended = noOffsetError = timeOffset = simple = False
testLocation = m.GOOGLE_TIMECHECK_LOCATION testLocation = GOOGLE_TIMECHECK_LOCATION
if checkForArgs: if checkForArgs:
while Cmd.ArgumentsRemaining(): while Cmd.ArgumentsRemaining():
myarg = m.getArgument() myarg = getArgument()
if myarg == 'check': if myarg == 'check':
forceCheck = 1 forceCheck = 1
elif myarg == 'checkrc': elif myarg == 'checkrc':
@@ -306,46 +303,45 @@ def doVersion(checkForArgs=True):
elif myarg == 'nooffseterror': elif myarg == 'nooffseterror':
noOffsetError = True noOffsetError = True
elif myarg == 'location': elif myarg == 'location':
testLocation = m.getString(Cmd.OB_HOST_NAME) testLocation = getString(Cmd.OB_HOST_NAME)
else: else:
m.unknownArgumentExit() unknownArgumentExit()
if simple: if simple:
m.writeStdout(m.__version__) writeStdout(_gam().__version__)
return return
m.writeStdout((f'{m.GAM} {m.__version__} - {m.GAM_URL} - {GM.Globals[GM.GAM_TYPE]}\n' writeStdout((f'{GAM} {_gam().__version__} - {GAM_URL} - {GM.Globals[GM.GAM_TYPE]}\n'
f'{m.__author__}\n' f'{_gam().__author__}\n'
f'Python {sys.version_info[0]}.{sys.version_info[1]}.{sys.version_info[2]} {struct.calcsize("P")*8}-bit {sys.version_info[3]}\n' f'Python {sys.version_info[0]}.{sys.version_info[1]}.{sys.version_info[2]} {struct.calcsize("P")*8}-bit {sys.version_info[3]}\n'
f'{getOSPlatform()} {platform.machine()}\n' f'{getOSPlatform()} {platform.machine()}\n'
f'Path: {GM.Globals[GM.GAM_PATH]}\n' f'Path: {GM.Globals[GM.GAM_PATH]}\n'
f'{Ent.Singular(Ent.CONFIG_FILE)}: {GM.Globals[GM.GAM_CFG_FILE]}, {Ent.Singular(Ent.SECTION)}: {GM.Globals[GM.GAM_CFG_SECTION_NAME]}, ' f'{Ent.Singular(Ent.CONFIG_FILE)}: {GM.Globals[GM.GAM_CFG_FILE]}, {Ent.Singular(Ent.SECTION)}: {GM.Globals[GM.GAM_CFG_SECTION_NAME]}, '
f'{GC.CUSTOMER_ID}: {GC.Values[GC.CUSTOMER_ID]}, {GC.DOMAIN}: {GC.Values[GC.DOMAIN]}\n' f'{GC.CUSTOMER_ID}: {GC.Values[GC.CUSTOMER_ID]}, {GC.DOMAIN}: {GC.Values[GC.DOMAIN]}\n'
f'Time: {m.ISOformatTimeStamp(m.todaysTime())}\n' f'Time: {ISOformatTimeStamp(todaysTime())}\n'
)) ))
if sys.platform.startswith('win') and str(struct.calcsize('P')*8).find('32') != -1 and platform.machine().find('64') != -1: if sys.platform.startswith('win') and str(struct.calcsize('P')*8).find('32') != -1 and platform.machine().find('64') != -1:
m.printKeyValueList([Msg.UPDATE_GAM_TO_64BIT]) printKeyValueList([Msg.UPDATE_GAM_TO_64BIT])
if timeOffset: if timeOffset:
offsetSeconds, offsetFormatted = getLocalGoogleTimeOffset(testLocation) offsetSeconds, offsetFormatted = getLocalGoogleTimeOffset(testLocation)
m.printKeyValueList([Msg.YOUR_SYSTEM_TIME_DIFFERS_FROM_GOOGLE.format(testLocation, offsetFormatted)]) printKeyValueList([Msg.YOUR_SYSTEM_TIME_DIFFERS_FROM_GOOGLE.format(testLocation, offsetFormatted)])
if offsetSeconds > m.MAX_LOCAL_GOOGLE_TIME_OFFSET: if offsetSeconds > MAX_LOCAL_GOOGLE_TIME_OFFSET:
if not noOffsetError: if not noOffsetError:
m.systemErrorExit(m.NETWORK_ERROR_RC, Msg.PLEASE_CORRECT_YOUR_SYSTEM_TIME) systemErrorExit(NETWORK_ERROR_RC, Msg.PLEASE_CORRECT_YOUR_SYSTEM_TIME)
m.stderrWarningMsg(Msg.PLEASE_CORRECT_YOUR_SYSTEM_TIME) stderrWarningMsg(Msg.PLEASE_CORRECT_YOUR_SYSTEM_TIME)
if forceCheck: if forceCheck:
m.doGAMCheckForUpdates(forceCheck) doGAMCheckForUpdates(forceCheck)
if extended: if extended:
m.printKeyValueList([ssl.OPENSSL_VERSION]) printKeyValueList([ssl.OPENSSL_VERSION])
tls_ver, cipher_name = _getServerTLSUsed(testLocation) tls_ver, cipher_name = _getServerTLSUsed(testLocation)
for lib in glverlibs.GAM_VER_LIBS: for lib in glverlibs.GAM_VER_LIBS:
try: try:
m.writeStdout(f'{lib} {lib_version(lib)}\n') writeStdout(f'{lib} {lib_version(lib)}\n')
except: except:
pass pass
m.printKeyValueList([f'{testLocation} connects using {tls_ver} {cipher_name}']) printKeyValueList([f'{testLocation} connects using {tls_ver} {cipher_name}'])
# gam help # gam help
def doUsage(): def doUsage():
m = _getMain() printBlankLine()
m.printBlankLine()
doVersion(checkForArgs=False) doVersion(checkForArgs=False)
m.writeStdout(Msg.HELP_SYNTAX.format(os.path.join(GM.Globals[GM.GAM_PATH], m.FN_GAMCOMMANDS_TXT))) writeStdout(Msg.HELP_SYNTAX.format(os.path.join(GM.Globals[GM.GAM_PATH], FN_GAMCOMMANDS_TXT)))
m.writeStdout(Msg.HELP_WIKI.format(m.GAM_WIKI)) writeStdout(Msg.HELP_WIKI.format(GAM_WIKI))

View File

@@ -227,24 +227,7 @@ def convertOrgUnitIDtoPath(cd, orgUnitId):
GM.Globals[GM.MAP_ORGUNIT_ID_TO_NAME][orgUnitId] = orgUnitPath GM.Globals[GM.MAP_ORGUNIT_ID_TO_NAME][orgUnitId] = orgUnitPath
return orgUnitPath return orgUnitPath
def shlexSplitList(entity, dataDelimiter=' ,'): from util.args import shlexSplitList, shlexSplitListStatus # noqa: E402,F401 - moved to args, re-exported for compat
lexer = shlex.shlex(entity, posix=True)
lexer.whitespace = dataDelimiter
lexer.whitespace_split = True
try:
return list(lexer)
except ValueError as e:
_getMain().Cmd.Backup()
_getMain().usageErrorExit(str(e))
def shlexSplitListStatus(entity, dataDelimiter=' ,'):
lexer = shlex.shlex(entity, posix=True)
lexer.whitespace = dataDelimiter
lexer.whitespace_split = True
try:
return (True, list(lexer))
except ValueError as e:
return (False, str(e))
def getQueries(myarg): def getQueries(myarg):
if myarg in {'query', 'filter'}: if myarg in {'query', 'filter'}: