Skip to content

API Usage

Jacob Callahan edited this page Apr 17, 2026 · 2 revisions

API Usage

Basics

Broker exposes most of the same functionality the CLI provides through a Broker class. To use this class, simply import:

from broker import Broker

The Broker class largely accepts the same arguments as you would pass via the CLI. One key difference is that you need to use underscores instead of dashes. For example, a checkout at the CLI that looks like this

broker checkout --nick rhel7 --args-file tests/data/broker_args.json --environment="VAR1=val1,VAR2=val2"

could look like this in an API usage

rhel7_host = Broker(nick="rhel7", args_file="tests/data/broker_args.json", environment={"VAR1": "val1", "VAR2": "val2"}).checkout()

Broker will carry out its usual actions and package the resulting host in a Host object. This host object will also include some basic functionality, like the ability to execute SSH commands on the host. Executed SSH command results are packaged in a Result object containing status (return code), stdout, and stderr.

result = rhel7_host.execute("rpm -qa")
assert result.status == 0
assert "my-package" in result.stdout

Recommended Basic Use

The Broker class has a built-in context manager that automatically performs a checkout upon enter and checkin upon exit. It is the recommended way of interacting with Broker for host management. In the below two lines of code:

  • a container host is created (pulled if needed or applicable)
  • a Broker Host object is constructed
  • the host object runs a command on the container
  • output is checked
  • the container is checked in
with Broker(container_host="ch-d:rhel7") as container_host:
    assert container_host.hostname in container_host.execute("hostname").stdout

Checking Out Multiple Hosts

Pass _count to check out several hosts of the same type in parallel. checkout() returns a list when _count > 1.

hosts = Broker(nick="rhel9", _count=3).checkout()
# hosts is a list of three Host objects
for host in hosts:
    print(host.hostname)

Broker Class Methods

checkin

Return one or more hosts to their provider.

broker_inst = Broker(nick="rhel9")
host = broker_inst.checkout()
# ... do work ...
broker_inst.checkin(host=host)

# or check in all hosts tracked by this Broker instance
broker_inst.checkin()

# checkin sequentially instead of concurrently
broker_inst.checkin(sequential=True)

execute

Run a provider action that does not result in a host checkout.

result = Broker(workflow="my-reporting-workflow", extra_arg="value").execute()

extend

Extend the lease time for one or more hosts (provider must support it).

broker_inst = Broker(nick="rhel9")
host = broker_inst.checkout()
broker_inst.extend(host=host)

from_inventory

Reconstruct hosts from Broker's local inventory, optionally filtered.

broker_inst = Broker()
all_hosts = broker_inst.from_inventory()

# with a filter expression
rhel_hosts = broker_inst.from_inventory(filter='@inv._broker_provider == "AnsibleTower"')

sync_inventory

Pull the current host list from a provider and update the local inventory.

Broker.sync_inventory("AnsibleTower")

# sync a specific instance
Broker.sync_inventory("AnsibleTower::testing")

multi_manager

Check out multiple different host types simultaneously and handle checkin automatically. All checkouts happen in parallel; all checkins happen in parallel on exit.

from broker import Broker
from myproject.hosts import ContentHost

with Broker.multi_manager(
    rhel8={"host_class": ContentHost, "workflow": "deploy-base-rhel", "deploy_rhel_version": "8"},
    rhel9={"host_class": ContentHost, "workflow": "deploy-base-rhel", "deploy_rhel_version": "9"},
) as host_dict:
    rhel8_host = host_dict["rhel8"][0]
    rhel9_host = host_dict["rhel9"][0]

Custom Host Classes

You are encouraged to build upon the existing Host class Broker provides but need to include it as a base class for Broker to work with it properly. This will allow you to build upon the base functionality Broker already provides while incorporating logic specific to your use cases. Once you have a new class, you can let Broker know to use it during host construction.

from broker import Broker
from broker.hosts import Host

class MyHost(Host):
    ...

with Broker(..., host_class=MyHost) as my_host:
    ...

When checking out multiple host types at once, pass a mapping of type name to class via host_classes:

with Broker(..., host_classes={"host": MyHost, "satellite": SatelliteHost}) as hosts:
    ...

Setup and Teardown

Sometimes you might want to define some behavior to occur after a host is checked out but before Broker gives it to you. Alternatively, you may want to define teardown logic that happens right before a host is checked in.

When using the Broker context manager, Broker will run any setup or teardown method defined on the Host object. Broker will not pass any arguments to the setup or teardown methods, so they must not accept arguments.

class MyHost(Host):
    ...
    def setup(self):
        self.register()

    def teardown(self):
        self.unregister()

To prevent a specific host from being checked in when the context manager exits (for example, to keep it around for debugging), set _skip_context_checkin = True on the host instance before the context exits:

with Broker(nick="rhel9") as host:
    host._skip_context_checkin = True  # keep the host after the with block

The Host Object

Every host Broker checks out is an instance of Host (or a subclass). The key attributes set during construction are:

Attribute Description
hostname The hostname or IP address used for SSH
name The provider-assigned name of the host
username SSH username (defaults to root)
password SSH password, if any
port SSH port (defaults to 22)
key_filename Path to an SSH private key file, if any
timeout SSH connection timeout in seconds

Any extra keyword arguments returned by the provider are also set as attributes on the host.

Host Methods

Method Description
host.execute(command, timeout=None) Run a shell command via SSH; returns a Result
host.connect(**kwargs) Explicitly open the SSH connection
host.close() Close the SSH connection
host.setup() Called automatically when entering a Broker context manager
host.teardown() Called automatically when exiting a Broker context manager
host.to_dict() Serialize the host to a dictionary
Host.from_dict(arg_dict) Reconstruct a Host from a dictionary (class method)

The session Property

host.session returns the underlying SSH session object, which is lazily created on first access. For container hosts without an exposed SSH port a ContainerSession is returned instead; for all other hosts an SSH session is returned using the configured backend (see SSH Backends below).

# Accessing the session directly to call lower-level methods
session = host.session
result = session.run("whoami")
print(result.stdout)  # => "root\n"

SSH Session API

The session object (regardless of the backend in use) exposes the following interface. All file-transfer methods accept string or Path arguments.

run

Execute a command and return a Result.

result = host.session.run("uname -r")
print(result.status)   # exit code (int)
print(result.stdout)   # standard output (str)
print(result.stderr)   # standard error (str)

An optional timeout argument (in seconds) can be passed; 0 means no timeout.

scp_read / scp_write

Transfer files using SCP.

# Download a file from the remote host
host.session.scp_read("/etc/hostname")                        # saved to ./hostname
host.session.scp_read("/etc/hostname", destination="/tmp/")   # saved to /tmp/hostname
raw_bytes = host.session.scp_read("/etc/hostname", return_data=True)

# Upload a file to the remote host
host.session.scp_write("/local/path/script.sh")               # uploaded to /local/path/script.sh
host.session.scp_write("/local/path/script.sh", destination="/remote/path/script.sh")

sftp_read / sftp_write

Transfer files using SFTP.

# Download a remote file
host.session.sftp_read("/var/log/messages")                   # saved locally to ./messages
host.session.sftp_read("/var/log/messages", destination="/tmp/messages")
data = host.session.sftp_read("/var/log/messages", return_data=True)  # returns bytes

# Upload a local file
host.session.sftp_write("/local/path/config.conf")            # uploaded to /local/path/config.conf
host.session.sftp_write("/local/path/config.conf", destination="/etc/myapp/config.conf")

Both sftp_write and scp_write accept an ensure_dir=True keyword argument (default True) that will create any missing parent directories on the remote host before the transfer.

shell

Open an interactive shell channel on the remote host.

shell = host.session.shell(pty=False)  # pty=True requests a pseudo-terminal

The returned object is the backend-specific shell/channel; use it for interactive workflows.

tail_file

Context manager that tails a file on the remote host. The contents attribute of the yielded object is populated when the context exits.

with host.session.tail_file("/var/log/messages") as tailer:
    host.execute("systemctl restart myservice")
# tailer.contents holds everything appended to the file during the block
print(tailer.contents)

remote_copy

Copy a file from this host directly to another host (server-side copy between two live sessions).

# copy /tmp/artifact.tar from source_host to dest_host at the same path
source_host.session.remote_copy(
    source="/tmp/artifact.tar",
    dest_host=dest_host,
    dest_path="/tmp/artifact.tar",
)

SSH Backends

Broker supports multiple pluggable SSH backends. The active backend is controlled by the SSH.BACKEND setting in broker_settings.yaml (or the BROKER_SSH__BACKEND environment variable).

Backend Install Extra Notes
hussh broker[hussh] Default; recommended
paramiko broker[paramiko] Pure-Python; widely compatible
ssh2-python broker[ssh2] Libssh2 bindings
pylibssh broker[pylibssh] Ansible's libssh bindings

All backends expose the same Session interface described above. Install the desired backend and set it in your config:

ssh:
  backend: hussh

Error Handling

The Broker class re-exports the most common exceptions for convenience so you do not need to import them separately from broker.exceptions.

from broker import Broker

try:
    host = Broker(nick="rhel9").checkout()
except Broker.AuthenticationError:
    print("SSH authentication failed")
except Broker.ProviderError:
    print("Provider returned an error")
except Broker.BrokerError as e:
    print(f"General broker error: {e}")
Exception When raised
Broker.BrokerError Base class for all Broker exceptions
Broker.AuthenticationError SSH or provider authentication failure
Broker.ProviderError An error returned by the provider
Broker.ConfigurationError Missing or invalid configuration
Broker.PermissionError Insufficient permissions for the action
Broker.UserError Invalid user input

Clone this wiki locally