Provided by: python-pyxs-doc_0.4.2~git20190115.97f14313-5_all bug

NAME

       pyxs - pyxs Documentation

          .---. .-..-..-.,-. .--.
          : .; `: :; :`.  .'`._-.'
          : ._.'`._. ;:_,._;`.__.'
          : :    .-. :
          :_;    `._.'       0.4.2-dev

          -- XenStore access the Python way!

       It's  a pure Python XenStore client implementation, which covers all of the libxs features
       and adds some nice Pythonic sugar on top. Here's a shortlist:

       • pyxs supports both Python 2 and 3,

       • works over a Unix socket or XenBus,

       • has a clean and well-documented API,

       • is written in easy to understand Python,

       • can be used with gevent or eventlet.

       If you have pip you can do the usual:

          pip install --user pyxs

       Otherwise, download the source from GitHub and run:

          python setup.py install

       Fedora users can install the package from the system repository:

          dnf install python2-pyxs
          dnf install python3-pyxs

       RHEL/CentOS users can install the package from the EPEL repository:

          yum install python2-pyxs
          yum install python34-pyxs

       Head over to our brief tutorial or, if you're feeling brave, dive right into the api; pyxs
       also has a couple of examples in the examples directory.

TUTORIAL

   Basics
       Using  pyxs  is  easy!  The  only class you need to import is Client. It provides a simple
       straightforward API to XenStore content with a bit of Python's syntactic  sugar  here  and
       there.

       Generally, if you just need to fetch or update some XenStore items you can do:

          >>> from pyxs import Client
          >>> with Client() as c:
          ...     c[b"/local/domain/0/name"] = b"Ziggy"
          ...     c[b"/local/domain/0/name"]
          b'Ziggy'

       Using Client without the with statement is possible, albeit, not recommended:

       >>> c = Client()
       >>> c.connect()
       >>> c[b"/local/domain/0/name"] = b"It works!"
       >>> c.close()

       The  reason for preferring a context manager is simple: you don't have to DIY. The context
       manager will make sure that a started transaction was either rolled back or committed  and
       close the underlying XenStore connection afterwards.

   Connections
       pyxs supports two ways of communicating with XenStore:

       • over a Unix socket with UnixSocketConnection;

       • over XenBus with XenBusConnection.

       Connection  type  is  determined  from  the  arguments  passed  to Client constructor. For
       example, the following code creates a Client instance, operating over a Unix socket:

          >>> Client(unix_socket_path="/var/run/xenstored/socket_ro")
          Client(UnixSocketConnection('/var/run/xenstored/socket_ro'))
          >>> Client()
          Client(UnixSocketConnection('/var/run/xenstored/socket'))

       Use xen_bus_path argument to initialize a Client with XenBusConnection:

          >>> Client(xen_bus_path="/dev/xen/xenbus")
          Client(XenBusConnection('/dev/xen/xenbus'))

   Transactions
       Transactions allow you to operate on an isolated copy of  XenStore  tree  and  merge  your
       changes  back  atomically  on  commit.  Keep  in mind, however, that changes made within a
       transaction become available to other XenStore clients only if and when committed.  Here's
       an example:

          >>> with Client() as c:
          ...     c.transaction()
          ...     c[b"/foo/bar"] = b"baz"
          ...     c.commit()  # !
          ...     print(c[b"/foo/bar"])
          b'baz'

       The  line  with  an  exclamation  mark is a bit careless, because it ignores the fact that
       committing a transaction might fail. A more robust way to commit a transaction is by using
       a loop:

          >>> with Client() as c:
          ...     success = False
          ...     while not success:
          ...         c.transaction()
          ...         c[b"/foo/bar"] = b"baz"
          ...         success = c.commit()

       You can also abort the current transaction by calling rollback().

   Events
       When  a  new  path  is  created  or an existing path is modified, XenStore fires an event,
       notifying all watching clients that a change has been made.  pyxs implements watching  via
       the Monitor class. To watch a path create a monitor monitor() and call watch() with a path
       you want to watch and a  unique  token.  Right  after  that  the  monitor  will  start  to
       accumulate incoming events.  You can iterate over them via wait():

          >>> with Client() as c:
          ...    m = c.monitor()
          ...    m.watch(b"/foo/bar", b"a unique token")
          ...    next(m.wait())
          Event(b"/foo/bar", b"a unique token")

       XenStore  has  a  notion of special paths, which start with @ and are reserved for special
       occasions:

                         ┌─────────────────┬──────────────────────────────────┐
                         │Path             │ Description                      │
                         ├─────────────────┼──────────────────────────────────┤
                         │@introduceDomain │ Fired  when  a  new  domain   is │
                         │                 │ introduced  to  XenStore  -- you │
                         │                 │ can   also   introduce   domains │
                         │                 │ yourself          with         a │
                         │                 │ introduce_domain() call, but  in │
                         │                 │ most  of  the  cases,  xenstored │
                         │                 │ will do that for you.            │
                         ├─────────────────┼──────────────────────────────────┤
                         │@releaseDomain   │ Fired when XenStore is no longer │
                         │                 │ communicating with a domain, see │
                         │                 │ release_domain().                │
                         └─────────────────┴──────────────────────────────────┘

       Events for both special and ordinary paths are simple two element tuples, where the  first
       element  is  always event target -- a path which triggered the event and second is a token
       passed to watch(). A rather unfortunate consequence of this is that you can't get domid of
       the domain, which triggered @introduceDomain or @releaseDomain from the received event.

   Compatibility API
       pyxs  also provides a compatibility interface, which mimics that of xen.lowlevel.xs --- so
       you don't have to change anything in the code to switch to pyxs:

          >>> from pyxs import xs
          >>> handle = xs()
          >>> handle.read("0", b"/local/domain/0/name")
          b'Domain-0'
          >>> handle.close()

API REFERENCE

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

              Parametersunix_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.

                     Parameterspath (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.

                     Parametersvalue (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.

                     Parameterspath (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.

                     Parameterstop (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.

                     Parametersdomid (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.

                     Parametersdomid (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.

                     Parameterswpath (bytes) -- path to watch.

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

              unwatch(wpath, token)
                     Removes a previously added watch.

                     Parameterswpath (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.

              Parametersop (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   =   Operations(DEBUG=0,  DIRECTORY=1,  READ=2,  GET_PERMS=3,  WATCH=4,
       UNWATCH=5,     TRANSACTION_START=6,     TRANSACTION_END=7,     INTRODUCE=8,     RELEASE=9,
       GET_DOMAIN_PATH=10,  WRITE=11,  MKDIR=12,  RM=13,  SET_PERMS=14, WATCH_EVENT=15, ERROR=16,
       IS_DOMAIN_INTRODUCED=17, RESUME=18, SET_TARGET=19, RESTRICT=128)
              Operations supported by XenStore.

CONTRIBUTING

   Submitting a bug report
       In case you experience issues using pyxs, do not hesitate to report it to the Bug  Tracker
       on GitHub.

   Setting up development environment
       Writing a XenStore client library without having access to a running XenStore instance can
       be troublesome. Luckily, there is a way to setup a development using VirtualBox.

       1. Create a VM running Ubuntu 14.04 or later.

       2. Install Xen hypervisor: sudo apt-get install xen-hypervisor-4.4-amd64.

       3. Configure VM for SSH access.

       4. Done! You can now rsync your changes to the VM and run the tests.

   Running the tests
       Only root is allowed to access XenStore, so the tests require sudo:

          $ sudo python setup.py test

       pyxs strives to work across a range of Python versions. Use tox to run the  tests  on  all
       supported versions:

          $ cat tox.ini
          [tox]
          envlist = py26,py27,py34,py35,pypy

          [testenv]
          commands = python setup.py test
          $ sudo tox

   Style guide
       pyxs follows Pocoo style guide. Please read it before you start implementing your changes.

PYXS CHANGELOG

       Here you can see the full list of changes between each pyxs release.

   Version 0.4.2-dev
       • Allowed values to be empty b"". Thanks to Stephen Czetty. See PR #13 on GitHub.

   Version 0.4.1
       Bugfix release, released on May 11th, 2016

       • Fixed  a  bug in XenBusConnection.create_transport which failed on attribute lookup. See
         PR #7 on GitHub.

   Version 0.4.0
       Released on March 6th, 2016

       • Fixed a bug in Client.set_permissions which coerced permission lists  (e.g.  ["b0"])  to
         repr-strings prior to validation.

       • The API is now based around bytes, which means that all methods which used to accept str
         (or text) now require bytes. XenStore paths and values are specified to be 7-bit  ASCII,
         thus  it makes little sense to allow any Unicode string as input and then validate if it
         matches the spec.

       • Removed transaction argument from Client constructor. The user is  advised  to  use  the
         corresponding methods explicitly.

       • Removed  connection  argument  from Client constructor. The user should now wrap it in a
         Router.

       • Renamed some of the Client methods to more human-readable names:

                                ┌──────────────────┬─────────────────────┐
                                │Old name          │ New name            │
                                ├──────────────────┼─────────────────────┤
                                │ls                │ list                │
                                ├──────────────────┼─────────────────────┤
                                │rm                │ delete              │
                                ├──────────────────┼─────────────────────┤
                                │get_permissions   │ get_perms           │
                                ├──────────────────┼─────────────────────┤
                                │set_permissions   │ set_perms           │
                                ├──────────────────┼─────────────────────┤
                                │transaction_start │ transaction         │
                                ├──────────────────┼─────────────────────┤
                                │transaction_end   │ commit and rollback │
                                └──────────────────┴─────────────────────┘

       • Removed Client.transaction context manager, because it didn't provide a  way  to  handle
         possible commit failure.

       • Added  Client.exists  for one-line path existence checks. See PR #6 on GitHub. Thanks to
         Sandeep Murthy.

       • Removed implicit reconnection logic from  FileDescriptorConnection.   The  user  is  now
         expected to connect manually.

       • Changed  XenBusConnection  to prefer /dev/xen/xenbus on Linux due to a possible deadlock
         in XenBus backend.

       • Changed UnixSocketConnection to use socket.socket  instead  of  the  corresponding  file
         descriptor.

       • Disallowed       calling       Client.monitor       over      XenBusConnection.      See
         http://lists.xen.org/archives/html/xen-devel/2016-02/msg03816 for details.

   Version 0.3.1
       Released on November 29th 2012

       • Added default argument to Client.read(), which acts similar to dict.get().

       • Fixed a lot of minor quirks so pyxs can be Debianized.

   Version 0.3
       Released on September 12th 2011

       • Moved all PUBSUB functionality into a separate Monitor  class,  which  uses  a  separate
         connection.  That  way,  we'll never have to worry about mixing incoming XenStore events
         and command replies.

       • Fixed a couple of nasty bugs in concurrent use of Client.wait() with other commands (see
         above).

   Version 0.2
       Released on August 18th 2011

       • Completely  refactored  validation  --  no  more  @spec  magic,  everything  is  checked
         explicitly inside Client.execute_command().

       • Added a compatibility interface, which mimics xen.lowlevel.xs behaviour, using pyxs as a
         backend, see pyxs/_compat.py.

       • Restricted   SET_TARGET,   INTRODUCE   and   RELEASE   operations   to   Dom0   only  --
         /proc/xen/capabilities is used to check domain role.

       • Fixed  a  bug  in  Client.wait()   --   queued   watch   events   weren't   wrapped   in
         pyxs._internal.Event class, unlike the received ones.

       • Added Client.walk() method for walking XenStore tree -- similar to os.walk()

   Version 0.1
       Initial release, released on July 16th 2011

       • Added  a  complete  implementation of XenStore protocol, including transactions and path
         watching, see pyxs.Client for details.

       • Added generic validation helper -- @spec, which forces arguments  to  match  the  scheme
         from the wire protocol specification.

       • Added  two  connection  backends  -- XenBusConnection for connecting from DomU through a
         block device and UnixSocketConnection, communicating with XenStore  via  a  Unix  domain
         socket.

AUTHOR

       Sergei Lebedev, Fedor Gogolev

COPYRIGHT

       2011-2022, Selectel