lce_service.sf_tools_api.core module

exception lce_service.sf_tools_api.core.CollectorConflictError(message: str)

Bases: InvalidSFToolRequestError

Exception 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.core.InvalidSFToolRequestError(message: str)

Bases: InvalidToolboxRequestError

Exception 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.core.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: NamedTuple

One 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.core.SFToolJobNotAccessible(proc_id: int)

Bases: ToolboxJobNotAccessible

Exception 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.core.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: NamedTuple

A 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

tool: SFTool

Alias for field number 0

lce_service.sf_tools_api.core.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.core.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.core.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.core.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:
lce_service.sf_tools_api.core.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.core.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.core.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.