ScheduleGenericPolling
Called by the GenericPolling playbook, schedules the polling task.
python · Common Scripts
Source
import uuid import demistomock as demisto # noqa: F401 from CommonServerPython import * # noqa: F401 # Constant to verify the minimum build number and version for the new polling feature (stopScheduleEntry feature). # MINIMUM_XSIAM_VERSION = '8.3.0' # MINIMUM_BUILD_NUMBER_XSIAM = 313276 MINIMUM_XSOAR_VERSION = "8.2.0" MINIMUM_BUILD_NUMBER_XSOAR = 309463 # Order is important! See is_command_sanitized implementation SANITIZED_ARG_NAMES = [ "additionalPollingCommandArgValues", "additionalPollingCommandArgNames", "pollingCommandArgName", "pollingCommand", ] # Returns a comma-separated string representation of a list # Possible inputs: null, int, str, bytes, ["","",...], [int, int], 'a,b,...', '"a","b",...', '["","",...]' def parseIds(idsArg): if idsArg is None: return None if isinstance(idsArg, list): return ",".join(map(str, idsArg)) if isinstance(idsArg, str): return ",".join(argToList(idsArg)) if isinstance(idsArg, bytes): return ",".join(argToList(idsArg.decode("utf-8"))) return str(idsArg) def should_run_with_guid(): # pragma: no cover """ The function verifies that the server has the right version in order to support the stopScheduleEntry command and the add-on of the GUID to the Schedule command. """ res_version = demisto.demistoVersion() build_number = res_version.get("buildNumber") platform = res_version.get("platform") # conditions to add when the feature is supported in XSIAM: # (platform == "x2" and is_demisto_version_ge(MINIMUM_XSIAM_VERSION) and int( # build_number) >= MINIMUM_BUILD_NUMBER_XSIAM) # The try/except mechanism is to support development and to ignore cast errors. try: return ( platform == "xsoar" and is_demisto_version_ge(MINIMUM_XSOAR_VERSION) and int(build_number) >= MINIMUM_BUILD_NUMBER_XSOAR ) except ValueError as e: demisto.debug(f"[ScheduleGenericPolling] Error parsing version or build number: {e}") return False def calculate_end_time(timeout): now = get_current_time() end_time = now + timedelta(minutes=timeout) short_format = "%Y-%m-%d %H:%M:%S" return end_time.strftime(short_format) def is_value_sanitized(value): return all(current_arg_name not in value for current_arg_name in SANITIZED_ARG_NAMES) def is_command_sanitized(command): malformed_args = [] command_lower = command.lower() for current_sanitized_arg_name in SANITIZED_ARG_NAMES: arg_name_lower = current_sanitized_arg_name.lower() if command_lower.count(arg_name_lower) > 1: malformed_args.append(current_sanitized_arg_name) command_lower = command_lower.replace(arg_name_lower, "") if malformed_args: return False, f'The value of {", ".join(malformed_args)} is malformed.' return True, None def get_command_string( ids, pollingCommand, pollingCommandArgName, playbookId, dt, interval, timeout, tag, args_names, args_values, extract_mode ): command_string = '''!GenericPollingScheduledTask ids="{}" pollingCommand="{}" pollingCommandArgName="{}"{} \ pendingIds="{}" interval="{}" timeout="{}" tag="{}" additionalPollingCommandArgNames="{}" \ additionalPollingCommandArgValues="{}"'''.format( ids.replace('"', r"\""), pollingCommand, pollingCommandArgName, playbookId, dt.replace('"', r"\""), interval, timeout, tag, args_names.replace('"', r"\""), args_values.replace('"', r"\""), ) if extract_mode: command_string += f" auto-extract={extract_mode} extractMode={extract_mode}" return command_string def main(): # pragma: no cover args = demisto.args() ids = parseIds(args.get("ids")) if not is_value_sanitized(ids): return_error("The value of ids is malformed") dt = args.get("dt") pollingCommand = args.get("pollingCommand") pollingCommandArgName = args.get("pollingCommandArgName") tag = args.get("tag") if playbookId := args.get("playbookId", ""): playbookId = f' playbookId="{playbookId}"' interval = int(args.get("interval")) timeout = int(args.get("timeout")) extract_mode = args.get("extractMode") if interval <= 0 or timeout <= 0: return_error("Interval and timeout must be positive numbers") args_names = (args.get("additionalPollingCommandArgNames", "") or "").strip() args_values = (args.get("additionalPollingCommandArgValues", "") or "").strip() demisto.debug(f"[ScheduleGenericPolling] Processed arguments: ids={ids}, interval={interval}, timeout={timeout}") # Verify correct dt path (does not verify condition!) demisto.debug(f"[ScheduleGenericPolling] Starting dt path validation. args={args}") if not demisto.dt(demisto.context(), dt): demisto.debug("[ScheduleGenericPolling] dt evaluation returned empty/null. Checking if dt path exists without condition.") if not demisto.dt(demisto.context(), re.sub(r"\(.*\)", "", dt)): demisto.debug(f"[ScheduleGenericPolling] ERROR: dt path not found in context. dt='{dt}'") demisto.debug(f"Could not find the dt path: {dt} in the context: {demisto.context()}") return_error(f"Incorrect dt path {dt}: no ids found in the context: {demisto.context()}") demisto.debug(f"[ScheduleGenericPolling] WARNING: dt path exists but no IDs match the condition. dt='{dt}'") demisto.results( "Warning: no ids matching the dt condition were found.\nVerify that the condition is correct and " "that all ids have finished running." ) command_string = get_command_string( ids, pollingCommand, pollingCommandArgName, playbookId, dt, interval, timeout, tag, args_names, args_values, extract_mode ) demisto.debug(f"[ScheduleGenericPolling] Generated command string: {command_string[:500]}") command_sanitized, message = is_command_sanitized(command_string) demisto.debug(f"[ScheduleGenericPolling] Command sanitization check: sanitized={command_sanitized}, message={message}") if not command_sanitized: return_error(message) demisto.debug( f"[ScheduleGenericPolling] Scheduling polling task. use_guid={should_run_with_guid()}, " f"interval={interval}, timeout={timeout}" ) schedule_command_args = {"command": command_string, "cron": f"*/{interval} * * * *", "times": 1} if should_run_with_guid(): demisto.debug("[ScheduleGenericPolling] Entering GUID flow (XSOAR)") # Generate a GUID for the scheduled entry and add it to the command. entryGuid = str(uuid.uuid4()) command_string = f'{command_string} scheduledEntryGuid="{entryGuid}" endTime="{calculate_end_time(timeout)}"' schedule_command_args["command"] = command_string # Set the times to be the number of times the polling command should run (using the cron job functionally). # Adding extra iterations to verify that the polling command will stop the schedule entry. # See XSUP-36162 for the reason adding 2 schedule_command_args["times"] = (timeout // interval) + 2 schedule_command_args["scheduledEntryGuid"] = entryGuid demisto.debug( f"[ScheduleGenericPolling] GUID flow details: entryGuid={entryGuid}, times={schedule_command_args['times']}" ) demisto.debug(f"[ScheduleGenericPolling] Executing ScheduleCommand with args: {schedule_command_args}") res = demisto.executeCommand("ScheduleCommand", schedule_command_args) demisto.debug(f"[ScheduleGenericPolling] ScheduleCommand result: {res}") if isError(res[0]): return_error(res) if __name__ in ("__main__", "__builtin__", "builtins"): main()
README
Schedules the polling task. This script is called by the GenericPolling playbook.
Script Data
| Name | Description |
|---|---|
| Script Type | python |
| Tags | - |
| Cortex XSOAR Version | 4.0.0+ |
Inputs
| Argument Name | Description |
|---|---|
| ids | The list of IDs to poll. |
| pollingCommand | The name of the polling command to run. |
| pollingCommandArgName | The name of the argument of the polling command. |
| dt | The DT filter for polling IDs. |
| playbookId | The ID of the playbook that contains the manual task which will be completed once the polling is done. |
| interval | The frequency to poll. How often the polling command should run (in minutes). |
| timeout | The amount of time to poll before declaring a timeout and resume the playbook (in minutes). |
| tag | The tag of the blocking manual task (“Wait For Polling Task To Finish”). |
| additionalPollingCommandArgNames | The names of additional arguments for the polling command. For example, “arg1,arg2,…”. |
| additionalPollingCommandArgValues | The values of the additional arguments for the polling command. For example, “value1,value2,…”. |
Outputs
There are no outputs for this script.