lce_service.remote_toolbox.dispatch module

lce_service.remote_toolbox.dispatch.queue_toolbox_command(dbc: silo_cursor, module_id: int, command: str, user: User, tool_id: int, policy_id: int = -1, device_id: int = 0, description: str = 'Remote Toolbox command') → int

Queues one command for the Remote Toolbox on a collector and returns its process id.

The command is stored in the platform’s spool table under AES_ENCRYPT and is picked up by the Remote Toolbox running on the target appliance. The collector polls the database for its work, so nothing has to be reachable inbound on the collector for this to succeed, which is what makes the path usable for collectors behind a firewall or NAT.

Two writes happen here and both have to land on the same connection. The process id is read back with LAST_INSERT_ID, which is connection scoped, and the ownership row that authorises a later read is keyed by that id. The endpoint layer holds a single cursor for the request, so passing the same cursor through satisfies both.

Both writes are also one unit of work, and they are wrapped in a transaction to make them one. The platform’s cursor forces autocommit on, so without it the queued command is committed as soon as the procedure returns and the collector’s outbound poll can pick the job up before the ownership row exists; a later failure would then leave output in a table shared by every toolbox tool with nobody recorded as its owner, for the whole 31 day retention. Rows written inside a transaction are invisible to the collector’s connection until it commits, so the transaction prevents the orphan rather than narrowing the window on it. This is the same unit of work device_tools_run.inc commits for the platform’s own toolbox tools.

Everything that can be refused is refused before anything is queued. Every check is a pure in memory comparison and needs no round trip, and a queued command cannot be recalled, so checking after the procedure call would cost a command that really ran on a collector. A command that cannot be run as given, because it carries the toolbox marker or is too long to store, is reported as a request error rather than a database one, since it is the request that has to change.

Parameters:
  • dbc – A silo_cursor instance used to queue the command and record its ownership.

  • module_id – The appliance id of the collector the command should run on.

  • command – The command to run, without the Remote Toolbox marker, which is prepended here. The collector side toolbox takes the last occurrence of the marker and refuses a payload with anything before it, so a command that already carries the marker is refused rather than queued to be refused on the collector.

  • user – The User instance the queued command is attributed to. The user id is written to the ownership row and is what authorises reading the output later.

  • tool_id – The Remote Toolbox tool id, stored as the spool row’s Xtype and on the ownership row. Reads check both, so it is what keeps one tool’s output from being read through another tool’s endpoint.

  • policy_id – The policy the command acts on, stored as the spool row’s Xid, or NO_POLICY_ID when there is none.

  • device_id – The device the command acts on, stored on the ownership row, or NO_DEVICE_ID when there is none.

  • description – What the command is, in the caller’s terms, such as “collector log command”, used in every error message so a refusal reads as the API the caller used rather than as this shared layer.

Returns:

The process id the platform assigned to the queued command.

Raises:
  • InvalidToolboxRequestError – Raised when the command carries the Remote Toolbox marker, or is too long for the spool table to hold once encrypted.

  • DatabaseExecutionError – Raised when the appliance id would broadcast, when the user cannot be identified, when the command cannot be queued, when the platform does not report a usable process id, or when the ownership row cannot be written. A failure to record ownership is treated as a failure of the whole dispatch and rolls the queued command back with it, because output that nobody can be shown to own must not be left behind.