# API reference

## Client and Monitor

class pyxs.client.Client(unix_socket_path=None, xen_bus_path=None, router=None)

  XenStore client.

  Parameters:

    - unix_socket_path (str) – path to XenStore Unix domain socket.

    - xen_bus_path (str) – path to XenBus device.

  If `unix_socket_path` is given or `Client` was created with no arguments, XenStore is accessed via `UnixSocketConnection`; otherwise, `XenBusConnection` is used.

  Each client has a `Router` thread running in the background. The goal of the router is to multiplex requests from different transaction through a single XenStore connection.

  Changed in version 0.4.0: The constructor no longer accepts `connection` argument. If you wan’t to force the use of a specific connection class, wrap it in a `Router`:

      from pyxs import Router, Client
      from pyxs.connection import XenBusConnection

      router = Router(XenBusConnection())
      with Client(router=router) as c:
          do_something(c)

  Warning

  Always finalize the client either explicitly by calling `close()` or implicitly via a context manager to prevent data loss.

  See also

  Xenstore protocol specification for a description of the protocol, implemented by `Client`.

  connect()

    Connects to the XenStore daemon.

    Raises:

      pyxs.exceptions.ConnectionError – if the connection could not be opened. This could happen either because XenStore is not running on the machine or due to the lack of permissions.

    Warning

    This method is unsafe. Please use client as a context manager to ensure it is properly finalized.

  close()

    Finalizes the client.

    Warning

    This method is unsafe. Please use client as a context manager to ensure it is properly finalized.

  read(path, default=None)

    Reads data from a given path.

    Parameters:

      - path (bytes) – a path to read from.

      - default (bytes) – default value, to be used if path doesn’t exist.

  write(path, value)

    Writes data to a given path.

    Parameters:

      - value (bytes) – data to write.

      - path (bytes) – a path to write to.

  mkdir(path)

    Ensures that a given path exists, by creating it and any missing parents with empty values. If path or any parent already exist, its value is left unchanged.

    Parameters:

      path (bytes) – path to directory to create.

  delete(path)

    Ensures that a given does not exist, by deleting it and all of its children. It is not an error if path doesn’t exist, but it is an error if path’s immediate parent does not exist either.

    Parameters:

      path (bytes) – path to directory to remove.

  list(path)

    Returns a list of names of the immediate children of path.

    Parameters:

      path (bytes) – path to list.

  exists(path)

    Checks if a given path exists.

    Parameters:

      path (bytes) – path to check.

  get_perms(path)

    Returns a list of permissions for a given path, see `InvalidPermission` for details on permission format.

    Parameters:

      path (bytes) – path to get permissions for.

  set_perms(path, perms)

    Sets a access permissions for a given path, see `InvalidPermission` for details on permission format.

    Parameters:

      - path (bytes) – path to set permissions for.

      - perms (list) – a list of permissions to set.

  walk(top, topdown=True)

    Walk XenStore, yielding 3-tuples `(path, value, children)` for each node in the tree, rooted at node top.

    Parameters:

      - top (bytes) – node to start from.

      - topdown (bool) – see `os.walk()` for details.

  get_domain_path(domid)

    Returns the domain’s base path, as used for relative requests: e.g. `b"/local/domain/<domid>"`. If a given domid doesn’t exists the answer is undefined.

    Parameters:

      domid (int) – domain to get base path for.

  is_domain_introduced(domid)

    Returns `True` if `xenstored` is in communication with the domain; that is when INTRODUCE for the domain has not yet been followed by domain destruction or explicit RELEASE; and `False` otherwise.

    Parameters:

      domid (int) – domain to check status for.

  introduce_domain(domid, mfn, eventchn)

    Tells `xenstored` to communicate with this domain.

    Parameters:

      - domid (int) – a real domain id, (`0` is forbidden).

      - mfn (int) – address of xenstore page in domid.

      - eventchn (int) – an unbound event chanel in domid.

  release_domain(domid)

    Manually requests `xenstored` to disconnect from the domain.

    Parameters:

      domid (int) – domain to disconnect.

    Note

    `xenstored` will in any case detect domain destruction and disconnect by itself.

  resume_domain(domid)

    Tells `xenstored` to clear its shutdown flag for a domain. This ensures that a subsequent shutdown will fire the appropriate watches.

    Parameters:

      domid (int) – domain to resume.

  set_target(domid, target)

    Tells `xenstored` that a domain is targetting another one, so it should let it tinker with it. This grants domain domid full access to paths owned by target. Domain domid also inherits all permissions granted to target on all other paths.

    Parameters:

      - domid (int) – domain to set target for.

      - target (int) – target domain (yours truly, Captain).

  transaction()

    Starts a new transaction.

    Returns int:

      transaction handle.

    Raises:

      pyxs.exceptions.PyXSError – with `errno.EALREADY` if this client is already in a transaction.

    Warning

    Currently `xenstored` has a bug that after 2**32 transactions it will allocate id 0 for an actual transaction.

  rollback()

    Rolls back a transaction currently in progress.

  commit()

    Commits a transaction currently in progress.

    Returns bool:

      `False` if commit failed because of the intervening writes and `True` otherwise. In any case transaction is invalidated. The caller is responsible for starting a new transaction, repeating all of the operations a re-committing.

  monitor()

    Returns a new `Monitor` instance, which is currently the only way of doing PUBSUB.

    The monitor shares the router with its parent client. Thus closing the client invalidates the monitor. Closing the monitor, on the other hand, had no effect on the router state.

    Note

    Using `monitor()` over `XenBusConnection` is currently unsupported, because XenBus does not obey XenStore protocol specification. See xen-devel discussion for details.

class pyxs.client.Monitor(client)

  Monitor implements minimal PUBSUB functionality on top of XenStore.

      >>> with Client() as c:
      ...    m = c.monitor():
      ...    m.watch("foo/bar")
      ...    print(next(c.wait()))
      Event(...)

  Parameters:

    client (Client) – a reference to the parent client.

  Note

  When used as a context manager the monitor will try to unwatch all watched paths.

  property watched

    A set of paths currently watched by the monitor.

  close()

    Finalizes the monitor by unwatching all watched paths.

  watch(wpath, token)

    Adds a watch.

    Any alteration to the watched path generates an event. This includes path creation, removal, contents change or permission change. An event can also be triggered spuriously.

    Changes made in transactions cause an event only if and when committed.

    Parameters:

      - wpath (bytes) – path to watch.

      - token (bytes) – watch token, returned in watch notification.

  unwatch(wpath, token)

    Removes a previously added watch.

    Parameters:

      - wpath (bytes) – path to unwatch.

      - token (bytes) – watch token, passed to `watch()`.

  wait(unwatched=False)

    Yields events for all of the watched paths.

    An event is a `(path, token)` pair, where the first element is event path, i.e. the actual path that was modified, and the second – a token, passed to `watch()`.

    Parameters:

      unwatched (bool) – if `True` `wait()` might yield spurious unwatched packets, otherwise these are dropped. Defaults to `False`.

pyxs.monitor(*args, **kwargs)

  A simple shortcut for creating `Monitor` instances. All arguments are forwared to `Client` constructor.

## Exceptions

class pyxs.exceptions.PyXSError

  Base class for all `pyxs` exceptions.

class pyxs.exceptions.InvalidOperation

  Exception raised when `Packet` is passed an operation, which isn’t listed in `Op`.

  Parameters:

    operation (int) – invalid operation value.

class pyxs.exceptions.InvalidPayload

  Exception raised when `Packet` is initialized with payload, which exceeds 4096 bytes restriction or contains a trailing `NULL`.

  Parameters:

    operation (bytes) – invalid payload value.

class pyxs.exceptions.InvalidPath

  Exception raised when a path proccessed by a command doesn’t match the following constraints:

  - its length should not exceed 3072 or 2048 for absolute and relative path respectively.

  - it should only consist of ASCII alphanumerics and the four punctuation characters `-/_@` – hyphen, slash, underscore and atsign.

  - it shouldn’t have a trailing `/`, except for the root path.

  Parameters:

    path (bytes) – invalid path value.

class pyxs.exceptions.InvalidPermission

  Exception raised for permission which don’t match the following format:

      w<domid>        write only
      r<domid>        read only
      b<domid>        both read and write
      n<domid>        no access

  Parameters:

    perm (bytes) – invalid permission value.

class pyxs.exceptions.ConnectionError

  Exception raised for failures during socket operations.

class pyxs.exceptions.UnexpectedPacket

  Exception raised when received packet header doesn’t match the header of the packet sent, for example if outgoing packet has `op = Op.READ` the incoming packet is expected to have `op = Op.READ` as well.

## Internals

class pyxs.client.Router(connection)

  Router.

  The goal of the router is to multiplex XenStore connection between multiple clients and monitors.

  Parameters:

    FileDescriptorConnection (connection) – owned by the router. The connection is open when the router is started and remains open until the router is terminated.

  Note

  Python lacks API for interrupting a thread from another thread. This means that when a router cannot be stopped when it is blocked in `select.select()` or `wait()`.

  The following two “hacks” are used to ensure prompt termination.

  1. A router is equipped with a `socket.socketpair()`. The reader-end of the pair is selected in the mainloop alongside the XenStore connection, while the writer-end is used in `terminate()` to force-stop the mainloop.

  2. All operations with `threading.Condition` variables user a 1 second timeout. This “hack” is only relevant for Python prior to 3.2 which didn’t allow one to interrupt lock acquisitions. See issue8844 on CPython issue tracker for details. On Python 3.2 and later no timeout is used.

  property is_connected

    Checks if the underlying connection is active.

  subscribe(token, monitor)

    Subscribes a `monitor` from events with a given `token`.

  unsubscribe(token, monitor)

    Unsubscribes a `monitor` to events with a given `token`.

  send(packet)

    Sends a packet to XenStore.

    Returns RVar:

      a reference to the XenStore response.

  start()

    Starts the router thread.

    Does nothing if the router is already started.

  terminate()

    Terminates the router.

    After termination the router can no longer send or receive packets. Does nothing if the router was already terminated.

class pyxs.connection.XenBusConnection(path=None)

  XenStore connection through XenBus.

  Parameters:

    path (str) – path to XenBus. A predefined OS-specific constant is used, if a value isn’t provided explicitly.

class pyxs.connection.UnixSocketConnection(path=None)

  XenStore connection through Unix domain socket.

  Parameters:

    path (str) – path to XenStore unix domain socket, if not provided explicitly is restored from process environment – similar to what `libxs` does.

class pyxs._internal.Packet(op, payload, rq_id, tx_id=None)

  A message to or from XenStore.

  Parameters:

    - op (int) – an item from `Op`, representing operation, performed by this packet.

    - payload (bytes) – packet payload, should be a valid ASCII-string with characters between `[0x20; 0x7f]`.

    - rq_id (int) – request id – hopefully a unique identifier for this packet, XenStore simply echoes this value back in response.

    - tx_id (int) – transaction id, defaults to `0` , which means no transaction is running.

  Changed in version 0.4.0: `rq_id` no longer defaults to `0` and should be provided explicitly.

pyxs._internal.Op = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 128)

  Operations supported by XenStore.