lce_service.sf_tools_api package
Snippet Framework Tools Module.
This module provides the functionality needed to run the platform’s Remote Toolbox tools for Dynamic Applications on a Data Collector and read their results back:
Dynamic App Collection (tool 13), which runs dynamic_single.py and whose output is its log
Snippet Framework Detailed Collection (tool 20)
Snippet Framework Collection Object Graph (tool 21)
Snippet Framework Dynamic App Multi Collection (tool 22)
These are the jobs the platform’s Dynamic Application editor queues through device_tools_run.inc and polls through json_tools.inc. A job runs on the collector its devices are assigned to, which is read from the platform rather than taken from the caller, and the three Snippet Framework tools write a JSON result alongside their log, which is reassembled here once the job finishes.
- exception lce_service.sf_tools_api.CollectorConflictError(message: str)
Bases:
InvalidSFToolRequestErrorException raised when the devices in a request do not resolve to a single collector.
A collector holds the configuration and credentials of its own devices only, so a job sent to any other collector finds nothing to run and finishes with an empty result. That failure would look like a success, which is why a request whose devices span collectors, or whose named collector is not the one its devices are assigned to, is refused instead.
- Parameters:
message – A descriptive error message naming the collectors involved.
- exception lce_service.sf_tools_api.InvalidSFToolRequestError(message: str)
Bases:
InvalidToolboxRequestErrorException raised when a Snippet Framework tool request cannot be turned into a command.
- Parameters:
message – A descriptive error message explaining which value was rejected and what shape was expected, suitable for returning to the caller.
- class lce_service.sf_tools_api.SFTool(key: str, tool_id: int, label: str, script: str, fixed_args: Tuple[str, ...], default_debug: bool, sets_sf_debug: bool, allows_wildcards: bool, max_jobs: int | None, options: FrozenSet[str], framed_result: bool)
Bases:
NamedTupleOne of the platform’s Remote Toolbox tools for running Dynamic Applications.
The tool ids, labels, scripts and fixed arguments are the ones functions_device_tools.inc and device_tools_run.inc define, so a job queued here is the same job the platform’s own Dynamic Application editor queues, and the platform’s toolbox history shows it as that tool.
- Variables:
key – The name a caller uses to select the tool.
tool_id – The Remote Toolbox tool id, recorded as the spool row’s Xtype.
label – The tool’s name in the platform’s toolbox.
script – The backend script the tool runs, relative to BACKEND_DIRECTORY.
fixed_args – Arguments the tool always passes, ahead of any that vary per request.
default_debug – Whether debug logging is on when the caller does not say, matching what the platform’s editor requests for the tool.
sets_sf_debug – Whether the tool’s debug switch also covers the Snippet Framework’s own.
allows_wildcards – Whether a job pair may use a wildcard. dynamic_single.py takes one explicit device and application, so it cannot.
max_jobs – The most job pairs the tool runs at once, or None for no limit of its own.
options – The request fields, beyond the common ones, the tool accepts.
framed_result – Whether the tool writes a JSON result behind CLI_OUTPUT_HEADER, as the three Snippet Framework tools do. Dynamic App Collection writes only its log, which is its result.
- allows_wildcards: bool
Alias for field number 7
- default_debug: bool
Alias for field number 5
- fixed_args: Tuple[str, ...]
Alias for field number 4
- framed_result: bool
Alias for field number 10
- key: str
Alias for field number 0
- label: str
Alias for field number 2
- max_jobs: int | None
Alias for field number 8
- options: FrozenSet[str]
Alias for field number 9
- script: str
Alias for field number 3
- sets_sf_debug: bool
Alias for field number 6
- tool_id: int
Alias for field number 1
- exception lce_service.sf_tools_api.SFToolJobNotAccessible(proc_id: int)
Bases:
ToolboxJobNotAccessibleException raised when a Snippet Framework tool job cannot be read by the requesting user.
The message is the same for every reason, as ToolboxJobNotAccessible requires: the job was never issued, it was queued as a different tool, it belongs to another user, or it aged out.
- Parameters:
proc_id – The process id the caller asked for.
- class lce_service.sf_tools_api.SFToolRequest(tool: SFTool, jobs: List[Tuple[int | str, int | str]], collector: Any, debug: bool, cobj_ids: List[int], disable_cache: bool, graph_type: str | None, dark_mode: bool | None, result_format: str | None, run_local: bool = False)
Bases:
NamedTupleA validated request to run one Snippet Framework tool.
Every field has already been through the validators in this module, so a request instance is safe to turn into a command. Construct one with build_sf_tool_request rather than directly.
- Variables:
tool – The tool to run.
jobs – The (device id, application id) pairs to run, in the order given and without duplicates. Either half may be WILDCARD when the tool allows it.
collector – The collector identifier the caller named, or None to derive it from the devices.
debug – Whether the tool runs with debug logging.
cobj_ids – The collection object ids to restrict a detailed collection to, or empty for every collection object.
disable_cache – Whether a detailed collection skips cache fast-forwarding.
graph_type – The graph format for a collection object graph, DEFAULT_GRAPH_TYPE when the caller did not say, or None for a tool that draws no graph.
dark_mode – Whether a collection object graph uses the dark theme, the light theme, or, when None, the CLI’s default, which is dark.
result_format – The format a detailed collection reports its results in, one of RESULT_FORMAT_FLAGS, or None for a tool that has no such choice.
run_local – Whether the tool runs on this host and is answered directly, rather than queued for the collector’s Remote Toolbox.
- cobj_ids: List[int]
Alias for field number 4
- collector: Any
Alias for field number 2
- dark_mode: bool | None
Alias for field number 7
- debug: bool
Alias for field number 3
- property device_ids: List[int]
The explicit device ids in the request, sorted and without duplicates.
- disable_cache: bool
Alias for field number 5
- graph_type: str | None
Alias for field number 6
- property has_device_wildcard: bool
Whether any job pair leaves the device for the collector to expand.
- jobs: List[Tuple[int | str, int | str]]
Alias for field number 1
- result_format: str | None
Alias for field number 8
- run_local: bool
Alias for field number 9
- class lce_service.sf_tools_api.SFToolResult(result: Any, extracted: Dict[str, Any] | None, error: str | None, chunk_count: int, incomplete: bool = False)
Bases:
NamedTupleThe result a finished Snippet Framework tool wrote, reassembled and parsed.
- Variables:
result – The parsed JSON result exactly as the CLI wrote it, or None when there is none.
extracted – The fields extract_sf_tool_result pulls out of the result, or None.
error – Why no result is available, or None when one is. A tool that finishes without a result, as the CLI does when it finds no jobs to run, reports why in its log.
chunk_count – How many chunks the result arrived in.
incomplete – Whether the chunks that were found do not make a whole result, because one has a length the tool cannot write or the text does not parse. Until the job has been quiet for SETTLE_SECONDS that can mean a batch of chunks is still on its way rather than that it was lost, so callers treat such a result as not yet available rather than as final.
- as_dict() Dict[str, Any]
Returns the result as it is reported to a caller.
- Returns:
A dictionary of the result, the extracted fields and the error.
- chunk_count: int
Alias for field number 3
- error: str | None
Alias for field number 2
- extracted: Dict[str, Any] | None
Alias for field number 1
- incomplete: bool
Alias for field number 4
- result: Any
Alias for field number 0
- lce_service.sf_tools_api.assert_sf_tool_job_is_readable(dbc: silo_cursor, proc_id: int, tool: SFTool, user: User) Dict[str, Any]
Verifies that a process id names a job of this tool that this user queued.
A job is only readable through the endpoint for the tool it was queued as. The output table is shared by every Remote Toolbox tool, so a job of any other tool, including another of the Snippet Framework tools, is refused exactly as a job that does not exist is.
- Parameters:
dbc – A silo_cursor instance used to read the spool and ownership rows.
proc_id – The process id returned when the tool was queued.
tool – The tool named in the request path.
user – The User instance requesting the output.
- Returns:
The job’s spool row, so the caller does not have to read it again.
- Raises:
SFToolJobNotAccessible – Raised when no such job exists, when it was queued as a different tool, when it has no recorded owner, or when the owner is another user.
DatabaseExecutionError – Raised when either check fails to execute.
- lce_service.sf_tools_api.build_sf_tool_command(request: SFToolRequest) str
Builds the command the Remote Toolbox runs for a validated request.
The command is the one device_tools_run.inc builds for the same tool, except that debug logging is turned off by unsetting its variables rather than by setting them to 0, which dynamic_single.py would read as on. Every token is a fixed string, a validated number, WILDCARD or a validated graph type, so none can carry a space, a quote or the toolbox marker. That matters because the toolbox splits the command with shlex and runs it without a shell: a token can never become a second argument, and a wildcard reaches the CLI as a literal asterisk rather than being expanded.
- Parameters:
request – A validated SFToolRequest.
- Returns:
The command to queue, without the Remote Toolbox marker.
- lce_service.sf_tools_api.build_sf_tool_request(tool: SFTool, body: Any) SFToolRequest
Validates a request body for a Snippet Framework tool.
A field the tool does not accept is refused rather than ignored, so a caller that sends a graph type to a detailed collection learns it had no effect instead of assuming it did.
- Parameters:
tool – The tool the request is for.
body – The decoded JSON request body.
- Returns:
A validated SFToolRequest.
- Raises:
InvalidSFToolRequestError – Raised when the body is not an object, carries a field the tool does not accept, or any value fails validation.
- lce_service.sf_tools_api.dispatch_sf_tool(dbc: silo_cursor, appliance: Dict[str, Any], request: SFToolRequest, user: User) int
Queues a Snippet Framework tool run on a collector and returns its process id.
The job is recorded the way device_tools_run.inc records it: as the tool’s own Remote Toolbox tool id, against the first job’s device and with the first job’s application as the policy, so the platform’s toolbox history describes it the same way whichever way it was started. A wildcard has no id to record, so the platform’s “none” sentinel stands in for it.
- Parameters:
dbc – A silo_cursor instance used to queue the command and record its ownership.
appliance – The collecting appliance to run on, as resolve_sf_tool_collector returns it.
request – A validated SFToolRequest.
user – The User instance the queued command is attributed to.
- Returns:
The process id to poll for the tool’s output.
- Raises:
DatabaseExecutionError – Raised when the command cannot be queued or attributed.
- lce_service.sf_tools_api.extract_sf_tool_result(tool: SFTool, result: Any) Dict[str, Any] | None
Pulls the parts of a tool’s result a caller usually wants out of the CLI’s nesting.
The result itself is always returned untouched alongside this; extraction only saves a caller from knowing where the CLI puts things, and never repeats the bulk of the result, which can be many megabytes. It never raises: a result of an unexpected shape just has nothing extracted from it.
The detailed collection and collection object graph results share an envelope of success, message and the device and application pairs the collector expanded the jobs to. That success only says the jobs were scheduled and run, not that any collection object produced data.
A detailed collection keys its results by “<device id>_<application id>” and then by collection object id, each entry holding the collection object’s DetailedCollectionResult under “result”, which is the path the platform’s editor reads. That holds the processed result, every step’s snapshots, the logs and any error. What is extracted is each collection object’s processed result and error, the value a collection object produced and why it did not, leaving the snapshots and logs, the bulk of the result, to the result itself. In the web UI format the processed result is the display string the editor shows; in the standard format it is the value itself.
A collection object graph keys its results by Execution Environment, each holding a graph, and the graphs are extracted as they are. The multi collection result is the Snippet Framework’s raw run output, which has no stable shape to extract from.
- Parameters:
tool – The tool that produced the result.
result – The parsed JSON result.
- Returns:
A dictionary of the extracted fields, or None when the tool’s result has nothing to extract or the result is not of the expected shape.
- lce_service.sf_tools_api.get_device_collectors(dbc: silo_cursor, device_ids: List[int]) Dict[int, int]
Reads the collector each device is assigned to, refusing a device that does not exist.
This is the check every request naming explicit devices passes, whether it is queued for a collector or run on this host, so a device that does not exist is reported the same way either way rather than run and left to find nothing.
- Parameters:
dbc – A silo_cursor instance used to read the devices.
device_ids – The explicit device ids of a request.
- Returns:
The appliance id each device is assigned to, zero for an unassigned device.
- Raises:
MissingResourceError – Raised when any of the devices does not exist.
DatabaseExecutionError – Raised when the devices cannot be read.
- lce_service.sf_tools_api.get_device_organization(dbc: silo_cursor, did: int) int | None
Reads the organization a device belongs to, which is where its tool runs are audited.
- Parameters:
dbc – A silo_cursor instance used to read the device.
did – The device id.
- Returns:
The organization id, or None when the device cannot be found.
- Raises:
DatabaseExecutionError – Raised when the device cannot be read.
- lce_service.sf_tools_api.get_sf_tool(tool_key: str) SFTool
Looks up a Snippet Framework tool by the name a caller uses for it.
- Parameters:
tool_key – The tool name from the request path.
- Returns:
The SFTool with that name.
- Raises:
MissingResourceError – Raised when no tool has that name.
- lce_service.sf_tools_api.poll_sf_tool_output(connect: Callable[[], ContextManager[silo_cursor]], proc_id: int, tool: SFTool, user: User, after_id: int = 0, page_size: int | None = None, wait_seconds: float | None = None) Tuple[OutputPage, JobProgress]
Serves one poll of a tool run: checks access, then reads a page of its log and its progress.
The result chunks are left out of the page and out of the progress. They are read whole by read_sf_tool_result once the run has finished, so they neither spend the page budget, nor get cut by the per record cap, nor appear to a caller as lines of log, and the last output id the progress reports is one a reader of the log can reach. A poll with no wait uses a single connection; a wait opens one per read, as poll_job_output describes.
- Parameters:
connect – Opens a database connection for one read, such as db_manager.
proc_id – The process id returned when the tool was queued.
tool – The tool named in the request path, which the job must have been queued as.
user – The User instance requesting the output.
after_id – Return only rows with an id greater than this.
page_size – The maximum number of rows to return.
wait_seconds – How long to wait for the collector to finish. Defaults to no wait.
- Returns:
The page of log lines and the run’s progress, read after it.
- Raises:
SFToolJobNotAccessible – Raised when the user may not read the run through this tool.
DatabaseExecutionError – Raised when anything cannot be read.
- lce_service.sf_tools_api.read_local_sf_tool_result(run: LocalRun, tool: SFTool) SFToolResult
Reassembles and parses the JSON result a tool run on this host wrote.
The result is read from the rows the run produced by the same rules read_sf_tool_result applies to the rows a collector wrote, so a run gives the same result either way.
- Parameters:
run – The LocalRun of the tool.
tool – The tool that was run.
- Returns:
An SFToolResult, as read_sf_tool_result returns it. A run whose output passed the limit a local run keeps has lost part of its result, so it is withheld.
- lce_service.sf_tools_api.read_sf_tool_result(dbc: silo_cursor, proc_id: int, tool: SFTool) SFToolResult
Reassembles and parses the JSON result a finished Snippet Framework tool wrote.
The CLI cuts its JSON into fixed length chunks and writes each behind CLI_OUTPUT_HEADER, so the result is rebuilt from those rows alone, whole and in order, before it is parsed. The platform’s editor trims every chunk before joining them, which deletes whitespace inside string values wherever a chunk boundary falls next to it; only the line terminator is removed here.
The CLI cuts every chunk but the last to exactly CLI_OUTPUT_CHUNK_SIZE characters, so a chunk of any other length means part of the result was lost or mangled on its way to the database; the collector’s toolbox, for one, can lose the start of a line it was half way through reading when the command exited. Such a result is withheld even when what remains still parses, as it will whenever the loss falls inside a long string, because a result that parses is not the same as the result the tool wrote. A chunk lost whole cannot be detected this way, since the CLI does not say how many it wrote.
- Parameters:
dbc – A silo_cursor instance used to read the output rows.
proc_id – The process id returned when the tool was queued.
tool – The tool the job was queued as.
- Returns:
An SFToolResult. Its error is set, and its result None, when the tool wrote no result, wrote one too large to return, or wrote one that does not parse.
- Raises:
DatabaseExecutionError – Raised when the output rows cannot be read.
- lce_service.sf_tools_api.resolve_sf_tool_collector(dbc: silo_cursor, request: SFToolRequest) Dict[str, Any]
Decides which collector a request runs on.
The collector a device is assigned to is the authority, because a collector only holds the configuration and credentials of its own devices; this is also where the platform’s editor gets the collector it sends. A collector the caller names is therefore checked against the devices rather than trusted, and only decides the collector on its own when every job leaves the device to a wildcard, since there is then no device to derive one from. A wildcard is expanded by the collector against its own configuration, so naming the collector is also what scopes the expansion.
- Parameters:
dbc – A silo_cursor instance used to read the devices and the appliance.
request – A validated SFToolRequest.
- Returns:
The collecting appliance the request runs on, holding its id, name, ip and function.
- Raises:
InvalidSFToolRequestError – Raised when a job uses a device wildcard and no collector was named, or when a device is not assigned to any collector.
CollectorConflictError – Raised when the devices are assigned to different collectors, or the named collector is not the one they are assigned to.
InvalidToolboxRequestError – Raised when the named collector is a value that is neither an id nor a name.
MissingResourceError – Raised when the named collector or a device does not exist.
DatabaseExecutionError – Raised when the devices or the appliance cannot be read.
- lce_service.sf_tools_api.run_sf_tool_locally(request: SFToolRequest) LocalRun
Runs a tool on this host, rather than queueing it, and waits for it to finish.
The command is the one dispatch_sf_tool queues, run the way the collector’s Remote Toolbox runs it, so its log and result read the same either way. Nothing is written to the spool or the ownership table: the output is answered directly and never has to be read back.
- Parameters:
request – A validated SFToolRequest.
- Returns:
The LocalRun of the tool.
- Raises:
InvalidToolboxRequestError – Raised when the command cannot be run as given.
Submodules
- lce_service.sf_tools_api.core module
- lce_service.sf_tools_api.dispatch_tools module
- lce_service.sf_tools_api.retrieve_tools module