.\" Man page generated from reStructuredText. . .TH "PYXS" "3" "Dec 05, 2020" "0.4.2" "pyxs" .SH NAME pyxs \- pyxs Documentation . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C \&.\-\-\-. .\-..\-..\-.,\-. .\-\-. : .; \(ga: :; :\(ga. .\(aq\(ga._\-.\(aq : ._.\(aq\(ga._. ;:_,._;\(ga.__.\(aq : : .\-. : :_; \(ga._.\(aq 0.4.2\-dev \-\- XenStore access the Python way! .ft P .fi .UNINDENT .UNINDENT .sp It\(aqs a pure Python XenStore client implementation, which covers all of the \fBlibxs\fP features and adds some nice Pythonic sugar on top. Here\(aqs a shortlist: .INDENT 0.0 .IP \(bu 2 \fBpyxs\fP supports both Python 2 and 3, .IP \(bu 2 works over a Unix socket or XenBus, .IP \(bu 2 has a clean and well\-documented API, .IP \(bu 2 is written in easy to understand Python, .IP \(bu 2 can be used with \fI\%gevent\fP or \fI\%eventlet\fP\&. .UNINDENT .sp If you have \fI\%pip\fP you can do the usual: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C pip install \-\-user pyxs .ft P .fi .UNINDENT .UNINDENT .sp Otherwise, download the source from \fI\%GitHub\fP and run: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C python setup.py install .ft P .fi .UNINDENT .UNINDENT .sp Fedora users can install the package from the system repository: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C dnf install python2\-pyxs dnf install python3\-pyxs .ft P .fi .UNINDENT .UNINDENT .sp RHEL/CentOS users can install the package from the \fI\%EPEL\fP repository: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C yum install python2\-pyxs yum install python34\-pyxs .ft P .fi .UNINDENT .UNINDENT .sp Head over to our brief tutorial or, if you\(aqre feeling brave, dive right into the api; \fBpyxs\fP also has a couple of examples in the \fI\%examples\fP directory. .SH TUTORIAL .SS Basics .sp Using \fBpyxs\fP is easy! The only class you need to import is \fBClient\fP\&. It provides a simple straightforward API to XenStore content with a bit of Python\(aqs syntactic sugar here and there. .sp Generally, if you just need to fetch or update some XenStore items you can do: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C >>> from pyxs import Client >>> with Client() as c: \&... c[b"/local/domain/0/name"] = b"Ziggy" \&... c[b"/local/domain/0/name"] b\(aqZiggy\(aq .ft P .fi .UNINDENT .UNINDENT .sp Using \fBClient\fP without the \fBwith\fP statement is possible, albeit, not recommended: .sp .nf .ft C >>> c = Client() >>> c.connect() >>> c[b"/local/domain/0/name"] = b"It works!" >>> c.close() .ft P .fi .sp The reason for preferring a context manager is simple: you don\(aqt 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. .SS Connections .sp \fBpyxs\fP supports two ways of communicating with XenStore: .INDENT 0.0 .IP \(bu 2 over a Unix socket with \fBUnixSocketConnection\fP; .IP \(bu 2 over \fI\%XenBus\fP with \fBXenBusConnection\fP\&. .UNINDENT .sp Connection type is determined from the arguments passed to \fBClient\fP constructor. For example, the following code creates a \fBClient\fP instance, operating over a Unix socket: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C >>> Client(unix_socket_path="/var/run/xenstored/socket_ro") Client(UnixSocketConnection(\(aq/var/run/xenstored/socket_ro\(aq)) >>> Client() Client(UnixSocketConnection(\(aq/var/run/xenstored/socket\(aq)) .ft P .fi .UNINDENT .UNINDENT .sp Use \fBxen_bus_path\fP argument to initialize a \fBClient\fP with \fBXenBusConnection\fP: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C >>> Client(xen_bus_path="/dev/xen/xenbus") Client(XenBusConnection(\(aq/dev/xen/xenbus\(aq)) .ft P .fi .UNINDENT .UNINDENT .SS Transactions .sp 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\(aqs an example: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C >>> with Client() as c: \&... c.transaction() \&... c[b"/foo/bar"] = b"baz" \&... c.commit() # ! \&... print(c[b"/foo/bar"]) b\(aqbaz\(aq .ft P .fi .UNINDENT .UNINDENT .sp 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: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C >>> with Client() as c: \&... success = False \&... while not success: \&... c.transaction() \&... c[b"/foo/bar"] = b"baz" \&... success = c.commit() .ft P .fi .UNINDENT .UNINDENT .sp You can also abort the current transaction by calling \fBrollback()\fP\&. .SS Events .sp 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. \fBpyxs\fP implements watching via the \fBMonitor\fP class. To watch a path create a monitor \fBmonitor()\fP and call \fBwatch()\fP 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 \fBwait()\fP: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C >>> 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") .ft P .fi .UNINDENT .UNINDENT .sp XenStore has a notion of \fIspecial\fP paths, which start with \fB@\fP and are reserved for special occasions: .TS center; |l|l|. _ T{ Path T} T{ Description T} _ T{ @introduceDomain T} T{ Fired when a \fBnew\fP domain is introduced to XenStore \-\- you can also introduce domains yourself with a \fBintroduce_domain()\fP call, but in most of the cases, \fBxenstored\fP will do that for you. T} _ T{ @releaseDomain T} T{ Fired when XenStore is no longer communicating with a domain, see \fBrelease_domain()\fP\&. T} _ .TE .sp Events for both special and ordinary paths are simple two element tuples, where the first element is always \fIevent target\fP \-\- a path which triggered the event and second is a token passed to \fBwatch()\fP\&. A rather unfortunate consequence of this is that you can\(aqt get \fIdomid\fP of the domain, which triggered @introduceDomain or @releaseDomain from the received event. .SS Compatibility API .sp \fBpyxs\fP also provides a compatibility interface, which mimics that of \fBxen.lowlevel.xs\fP \-\-\- so you don\(aqt have to change anything in the code to switch to \fBpyxs\fP: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C >>> from pyxs import xs >>> handle = xs() >>> handle.read("0", b"/local/domain/0/name") b\(aqDomain\-0\(aq >>> handle.close() .ft P .fi .UNINDENT .UNINDENT .SH API REFERENCE .SS Client and Monitor .INDENT 0.0 .TP .B class pyxs.client.Client(unix_socket_path=None, xen_bus_path=None, router=None) XenStore client. .INDENT 7.0 .TP .B Parameters .INDENT 7.0 .IP \(bu 2 \fBunix_socket_path\fP (\fIstr\fP) \-\- path to XenStore Unix domain socket. .IP \(bu 2 \fBxen_bus_path\fP (\fIstr\fP) \-\- path to XenBus device. .UNINDENT .UNINDENT .sp If \fBunix_socket_path\fP is given or \fI\%Client\fP was created with no arguments, XenStore is accessed via \fI\%UnixSocketConnection\fP; otherwise, \fI\%XenBusConnection\fP is used. .sp Each client has a \fI\%Router\fP thread running in the background. The goal of the router is to multiplex requests from different transaction through a single XenStore connection. .sp Changed in version 0.4.0: The constructor no longer accepts \fBconnection\fP argument. If you wan\(aqt to force the use of a specific connection class, wrap it in a \fI\%Router\fP: .INDENT 7.0 .INDENT 3.5 .sp .nf .ft C from pyxs import Router, Client from pyxs.connection import XenBusConnection router = Router(XenBusConnection()) with Client(router=router) as c: do_something(c) .ft P .fi .UNINDENT .UNINDENT .sp \fBWARNING:\fP .INDENT 7.0 .INDENT 3.5 Always finalize the client either explicitly by calling \fI\%close()\fP or implicitly via a context manager to prevent data loss. .UNINDENT .UNINDENT .sp \fBSEE ALSO:\fP .INDENT 7.0 .INDENT 3.5 \fI\%Xenstore protocol specification\fP for a description of the protocol, implemented by \fBClient\fP\&. .UNINDENT .UNINDENT .INDENT 7.0 .TP .B connect() Connects to the XenStore daemon. .INDENT 7.0 .TP .B Raises \fBpyxs.exceptions.ConnectionError\fP \-\- 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. .UNINDENT .sp \fBWARNING:\fP .INDENT 7.0 .INDENT 3.5 This method is unsafe. Please use client as a context manager to ensure it is properly finalized. .UNINDENT .UNINDENT .UNINDENT .INDENT 7.0 .TP .B close() Finalizes the client. .sp \fBWARNING:\fP .INDENT 7.0 .INDENT 3.5 This method is unsafe. Please use client as a context manager to ensure it is properly finalized. .UNINDENT .UNINDENT .UNINDENT .INDENT 7.0 .TP .B read(path, default=None) Reads data from a given path. .INDENT 7.0 .TP .B Parameters .INDENT 7.0 .IP \(bu 2 \fBpath\fP (\fIbytes\fP) \-\- a path to read from. .IP \(bu 2 \fBdefault\fP (\fIbytes\fP) \-\- default value, to be used if \fIpath\fP doesn\(aqt exist. .UNINDENT .UNINDENT .UNINDENT .INDENT 7.0 .TP .B write(path, value) Writes data to a given path. .INDENT 7.0 .TP .B Parameters .INDENT 7.0 .IP \(bu 2 \fBvalue\fP (\fIbytes\fP) \-\- data to write. .IP \(bu 2 \fBpath\fP (\fIbytes\fP) \-\- a path to write to. .UNINDENT .UNINDENT .UNINDENT .INDENT 7.0 .TP .B mkdir(path) Ensures that a given path exists, by creating it and any missing parents with empty values. If \fIpath\fP or any parent already exist, its value is left unchanged. .INDENT 7.0 .TP .B Parameters \fBpath\fP (\fIbytes\fP) \-\- path to directory to create. .UNINDENT .UNINDENT .INDENT 7.0 .TP .B delete(path) Ensures that a given does not exist, by deleting it and all of its children. It is not an error if \fIpath\fP doesn\(aqt exist, but it \fBis\fP an error if \fIpath\fP\(aqs immediate parent does not exist either. .INDENT 7.0 .TP .B Parameters \fBpath\fP (\fIbytes\fP) \-\- path to directory to remove. .UNINDENT .UNINDENT .INDENT 7.0 .TP .B list(path) Returns a list of names of the immediate children of \fIpath\fP\&. .INDENT 7.0 .TP .B Parameters \fBpath\fP (\fIbytes\fP) \-\- path to list. .UNINDENT .UNINDENT .INDENT 7.0 .TP .B exists(path) Checks if a given \fIpath\fP exists. .INDENT 7.0 .TP .B Parameters \fBpath\fP (\fIbytes\fP) \-\- path to check. .UNINDENT .UNINDENT .INDENT 7.0 .TP .B get_perms(path) Returns a list of permissions for a given \fIpath\fP, see \fI\%InvalidPermission\fP for details on permission format. .INDENT 7.0 .TP .B Parameters \fBpath\fP (\fIbytes\fP) \-\- path to get permissions for. .UNINDENT .UNINDENT .INDENT 7.0 .TP .B set_perms(path, perms) Sets a access permissions for a given \fIpath\fP, see \fI\%InvalidPermission\fP for details on permission format. .INDENT 7.0 .TP .B Parameters .INDENT 7.0 .IP \(bu 2 \fBpath\fP (\fIbytes\fP) \-\- path to set permissions for. .IP \(bu 2 \fBperms\fP (\fIlist\fP) \-\- a list of permissions to set. .UNINDENT .UNINDENT .UNINDENT .INDENT 7.0 .TP .B walk(top, topdown=True) Walk XenStore, yielding 3\-tuples \fB(path, value, children)\fP for each node in the tree, rooted at node \fItop\fP\&. .INDENT 7.0 .TP .B Parameters .INDENT 7.0 .IP \(bu 2 \fBtop\fP (\fIbytes\fP) \-\- node to start from. .IP \(bu 2 \fBtopdown\fP (\fIbool\fP) \-\- see \fBos.walk()\fP for details. .UNINDENT .UNINDENT .UNINDENT .INDENT 7.0 .TP .B get_domain_path(domid) Returns the domain\(aqs base path, as used for relative requests: e.g. \fBb"/local/domain/"\fP\&. If a given \fIdomid\fP doesn\(aqt exists the answer is undefined. .INDENT 7.0 .TP .B Parameters \fBdomid\fP (\fIint\fP) \-\- domain to get base path for. .UNINDENT .UNINDENT .INDENT 7.0 .TP .B is_domain_introduced(domid) Returns \fBTrue\fP if \fBxenstored\fP is in communication with the domain; that is when \fIINTRODUCE\fP for the domain has not yet been followed by domain destruction or explicit \fIRELEASE\fP; and \fBFalse\fP otherwise. .INDENT 7.0 .TP .B Parameters \fBdomid\fP (\fIint\fP) \-\- domain to check status for. .UNINDENT .UNINDENT .INDENT 7.0 .TP .B introduce_domain(domid, mfn, eventchn) Tells \fBxenstored\fP to communicate with this domain. .INDENT 7.0 .TP .B Parameters .INDENT 7.0 .IP \(bu 2 \fBdomid\fP (\fIint\fP) \-\- a real domain id, (\fB0\fP is forbidden). .IP \(bu 2 \fBmfn\fP (\fIint\fP) \-\- address of xenstore page in \fIdomid\fP\&. .IP \(bu 2 \fBeventchn\fP (\fIint\fP) \-\- an unbound event chanel in \fIdomid\fP\&. .UNINDENT .UNINDENT .UNINDENT .INDENT 7.0 .TP .B release_domain(domid) Manually requests \fBxenstored\fP to disconnect from the domain. .INDENT 7.0 .TP .B Parameters \fBdomid\fP (\fIint\fP) \-\- domain to disconnect. .UNINDENT .sp \fBNOTE:\fP .INDENT 7.0 .INDENT 3.5 \fBxenstored\fP will in any case detect domain destruction and disconnect by itself. .UNINDENT .UNINDENT .UNINDENT .INDENT 7.0 .TP .B resume_domain(domid) Tells \fBxenstored\fP to clear its shutdown flag for a domain. This ensures that a subsequent shutdown will fire the appropriate watches. .INDENT 7.0 .TP .B Parameters \fBdomid\fP (\fIint\fP) \-\- domain to resume. .UNINDENT .UNINDENT .INDENT 7.0 .TP .B set_target(domid, target) Tells \fBxenstored\fP that a domain is targetting another one, so it should let it tinker with it. This grants domain \fIdomid\fP full access to paths owned by \fItarget\fP\&. Domain \fIdomid\fP also inherits all permissions granted to \fItarget\fP on all other paths. .INDENT 7.0 .TP .B Parameters .INDENT 7.0 .IP \(bu 2 \fBdomid\fP (\fIint\fP) \-\- domain to set target for. .IP \(bu 2 \fBtarget\fP (\fIint\fP) \-\- target domain (yours truly, Captain). .UNINDENT .UNINDENT .UNINDENT .INDENT 7.0 .TP .B transaction() Starts a new transaction. .INDENT 7.0 .TP .B Returns int transaction handle. .TP .B Raises \fBpyxs.exceptions.PyXSError\fP \-\- with \fBerrno.EALREADY\fP if this client is already in a transaction. .UNINDENT .sp \fBWARNING:\fP .INDENT 7.0 .INDENT 3.5 Currently \fBxenstored\fP has a bug that after 2**32 transactions it will allocate id 0 for an actual transaction. .UNINDENT .UNINDENT .UNINDENT .INDENT 7.0 .TP .B rollback() Rolls back a transaction currently in progress. .UNINDENT .INDENT 7.0 .TP .B commit() Commits a transaction currently in progress. .INDENT 7.0 .TP .B Returns bool \fBFalse\fP if commit failed because of the intervening writes and \fBTrue\fP otherwise. In any case transaction is invalidated. The caller is responsible for starting a new transaction, repeating all of the operations a re\-committing. .UNINDENT .UNINDENT .INDENT 7.0 .TP .B monitor() Returns a new \fI\%Monitor\fP instance, which is currently the only way of doing PUBSUB. .sp 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. .sp \fBNOTE:\fP .INDENT 7.0 .INDENT 3.5 Using \fI\%monitor()\fP over \fI\%XenBusConnection\fP is currently unsupported, because XenBus does not obey XenStore protocol specification. See \fI\%xen\-devel\fP discussion for details. .INDENT 0.0 .INDENT 3.5 .UNINDENT .UNINDENT .UNINDENT .UNINDENT .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class pyxs.client.Monitor(client) Monitor implements minimal PUBSUB functionality on top of XenStore. .sp .nf .ft C >>> with Client() as c: \&... m = c.monitor(): \&... m.watch("foo/bar") \&... print(next(c.wait())) Event(...) .ft P .fi .INDENT 7.0 .TP .B Parameters \fBclient\fP (\fIClient\fP) \-\- a reference to the parent client. .UNINDENT .sp \fBNOTE:\fP .INDENT 7.0 .INDENT 3.5 When used as a context manager the monitor will try to unwatch all watched paths. .UNINDENT .UNINDENT .INDENT 7.0 .TP .B property watched A set of paths currently watched by the monitor. .UNINDENT .INDENT 7.0 .TP .B close() Finalizes the monitor by unwatching all watched paths. .UNINDENT .INDENT 7.0 .TP .B watch(wpath, token) Adds a watch. .sp 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. .sp Changes made in transactions cause an event only if and when committed. .INDENT 7.0 .TP .B Parameters .INDENT 7.0 .IP \(bu 2 \fBwpath\fP (\fIbytes\fP) \-\- path to watch. .IP \(bu 2 \fBtoken\fP (\fIbytes\fP) \-\- watch token, returned in watch notification. .UNINDENT .UNINDENT .UNINDENT .INDENT 7.0 .TP .B unwatch(wpath, token) Removes a previously added watch. .INDENT 7.0 .TP .B Parameters .INDENT 7.0 .IP \(bu 2 \fBwpath\fP (\fIbytes\fP) \-\- path to unwatch. .IP \(bu 2 \fBtoken\fP (\fIbytes\fP) \-\- watch token, passed to \fI\%watch()\fP\&. .UNINDENT .UNINDENT .UNINDENT .INDENT 7.0 .TP .B wait(unwatched=False) Yields events for all of the watched paths. .sp An event is a \fB(path, token)\fP pair, where the first element is event path, i.e. the actual path that was modified, and the second \-\- a token, passed to \fI\%watch()\fP\&. .INDENT 7.0 .TP .B Parameters \fBunwatched\fP (\fIbool\fP) \-\- if \fBTrue\fP \fI\%wait()\fP might yield spurious unwatched packets, otherwise these are dropped. Defaults to \fBFalse\fP\&. .UNINDENT .UNINDENT .UNINDENT .INDENT 0.0 .TP .B pyxs.monitor(*args, **kwargs) A simple shortcut for creating \fI\%Monitor\fP instances. All arguments are forwared to \fI\%Client\fP constructor. .UNINDENT .SS Exceptions .INDENT 0.0 .TP .B class pyxs.exceptions.PyXSError Base class for all \fBpyxs\fP exceptions. .UNINDENT .INDENT 0.0 .TP .B class pyxs.exceptions.InvalidOperation Exception raised when \fI\%Packet\fP is passed an operation, which isn\(aqt listed in \fI\%Op\fP\&. .INDENT 7.0 .TP .B Parameters \fBoperation\fP (\fIint\fP) \-\- invalid operation value. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class pyxs.exceptions.InvalidPayload Exception raised when \fBPacket\fP is initialized with payload, which exceeds 4096 bytes restriction or contains a trailing \fBNULL\fP\&. .INDENT 7.0 .TP .B Parameters \fBoperation\fP (\fIbytes\fP) \-\- invalid payload value. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class pyxs.exceptions.InvalidPath Exception raised when a path proccessed by a command doesn\(aqt match the following constraints: .INDENT 7.0 .IP \(bu 2 its length should not exceed 3072 or 2048 for absolute and relative path respectively. .IP \(bu 2 it should only consist of ASCII alphanumerics and the four punctuation characters \fB\-/_@\fP \-\- \fIhyphen\fP, \fIslash\fP, \fIunderscore\fP and \fIatsign\fP\&. .IP \(bu 2 it shouldn\(aqt have a trailing \fB/\fP, except for the root path. .UNINDENT .INDENT 7.0 .TP .B Parameters \fBpath\fP (\fIbytes\fP) \-\- invalid path value. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class pyxs.exceptions.InvalidPermission Exception raised for permission which don\(aqt match the following format: .INDENT 7.0 .INDENT 3.5 .sp .nf .ft C w write only r read only b both read and write n no access .ft P .fi .UNINDENT .UNINDENT .INDENT 7.0 .TP .B Parameters \fBperm\fP (\fIbytes\fP) \-\- invalid permission value. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class pyxs.exceptions.ConnectionError Exception raised for failures during socket operations. .UNINDENT .INDENT 0.0 .TP .B class pyxs.exceptions.UnexpectedPacket Exception raised when received packet header doesn\(aqt match the header of the packet sent, for example if outgoing packet has \fBop = Op.READ\fP the incoming packet is expected to have \fBop = Op.READ\fP as well. .UNINDENT .SS Internals .INDENT 0.0 .TP .B class pyxs.client.Router(connection) Router. .sp The goal of the router is to multiplex XenStore connection between multiple clients and monitors. .INDENT 7.0 .TP .B Parameters \fBFileDescriptorConnection\fP (\fIconnection\fP) \-\- owned by the router. The connection is open when the router is started and remains open until the router is terminated. .UNINDENT .sp \fBNOTE:\fP .INDENT 7.0 .INDENT 3.5 Python lacks API for interrupting a thread from another thread. This means that when a router cannot be stopped when it is blocked in \fBselect.select()\fP or \fBwait()\fP\&. .sp The following two "hacks" are used to ensure prompt termination. .INDENT 0.0 .IP 1. 3 A router is equipped with a \fBsocket.socketpair()\fP\&. The reader\-end of the pair is selected in the mainloop alongside the XenStore connection, while the writer\-end is used in \fI\%terminate()\fP to force\-stop the mainloop. .IP 2. 3 All operations with \fBthreading.Condition\fP variables user a 1 second timeout. This "hack" is only relevant for Python prior to 3.2 which didn\(aqt allow one to interrupt lock acquisitions. See \fI\%issue8844\fP on CPython issue tracker for details. On Python 3.2 and later no timeout is used. .UNINDENT .INDENT 0.0 .INDENT 3.5 .UNINDENT .UNINDENT .UNINDENT .UNINDENT .INDENT 7.0 .TP .B property is_connected Checks if the underlying connection is active. .UNINDENT .INDENT 7.0 .TP .B subscribe(token, monitor) Subscribes a \fBmonitor\fP from events with a given \fBtoken\fP\&. .UNINDENT .INDENT 7.0 .TP .B unsubscribe(token, monitor) Unsubscribes a \fBmonitor\fP to events with a given \fBtoken\fP\&. .UNINDENT .INDENT 7.0 .TP .B send(packet) Sends a packet to XenStore. .INDENT 7.0 .TP .B Returns RVar a reference to the XenStore response. .UNINDENT .UNINDENT .INDENT 7.0 .TP .B start() Starts the router thread. .sp Does nothing if the router is already started. .UNINDENT .INDENT 7.0 .TP .B terminate() Terminates the router. .sp After termination the router can no longer send or receive packets. Does nothing if the router was already terminated. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class pyxs.connection.XenBusConnection(path=None) XenStore connection through XenBus. .INDENT 7.0 .TP .B Parameters \fBpath\fP (\fIstr\fP) \-\- path to XenBus. A predefined OS\-specific constant is used, if a value isn\(aqt provided explicitly. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class pyxs.connection.UnixSocketConnection(path=None) XenStore connection through Unix domain socket. .INDENT 7.0 .TP .B Parameters \fBpath\fP (\fIstr\fP) \-\- path to XenStore unix domain socket, if not provided explicitly is restored from process environment \-\- similar to what \fBlibxs\fP does. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class pyxs._internal.Packet(op, payload, rq_id, tx_id=None) A message to or from XenStore. .INDENT 7.0 .TP .B Parameters .INDENT 7.0 .IP \(bu 2 \fBop\fP (\fIint\fP) \-\- an item from \fI\%Op\fP, representing operation, performed by this packet. .IP \(bu 2 \fBpayload\fP (\fIbytes\fP) \-\- packet payload, should be a valid ASCII\-string with characters between \fB[0x20; 0x7f]\fP\&. .IP \(bu 2 \fBrq_id\fP (\fIint\fP) \-\- request id \-\- hopefully a \fBunique\fP identifier for this packet, XenStore simply echoes this value back in response. .IP \(bu 2 \fBtx_id\fP (\fIint\fP) \-\- transaction id, defaults to \fB0\fP , which means no transaction is running. .UNINDENT .UNINDENT .sp Changed in version 0.4.0: \fBrq_id\fP no longer defaults to \fB0\fP and should be provided explicitly. .UNINDENT .INDENT 0.0 .TP .B 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. .UNINDENT .SH CONTRIBUTING .SS Submitting a bug report .sp In case you experience issues using \fBpyxs\fP, do not hesitate to report it to the \fI\%Bug Tracker\fP on GitHub. .SS Setting up development environment .sp 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. .INDENT 0.0 .IP 1. 3 Create a VM running Ubuntu 14.04 or later. .IP 2. 3 \fI\%Install\fP Xen hypervisor: \fBsudo apt\-get install xen\-hypervisor\-4.4\-amd64\fP\&. .IP 3. 3 \fI\%Configure\fP VM for SSH access. .IP 4. 3 Done! You can now \fBrsync\fP your changes to the VM and run the tests. .UNINDENT .SS Running the tests .sp Only \fBroot\fP is allowed to access XenStore, so the tests require \fBsudo\fP: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ sudo python setup.py test .ft P .fi .UNINDENT .UNINDENT .sp \fBpyxs\fP strives to work across a range of Python versions. Use \fBtox\fP to run the tests on all supported versions: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ cat tox.ini [tox] envlist = py26,py27,py34,py35,pypy [testenv] commands = python setup.py test $ sudo tox .ft P .fi .UNINDENT .UNINDENT .SS Style guide .sp \fBpyxs\fP follows Pocoo style guide. Please \fI\%read it\fP before you start implementing your changes. .SH PYXS CHANGELOG .sp Here you can see the full list of changes between each pyxs release. .SS Version 0.4.2\-dev .INDENT 0.0 .IP \(bu 2 Allowed values to be empty \fBb""\fP\&. Thanks to Stephen Czetty. See PR #13 on GitHub. .UNINDENT .SS Version 0.4.1 .sp Bugfix release, released on May 11th, 2016 .INDENT 0.0 .IP \(bu 2 Fixed a bug in \fBXenBusConnection.create_transport\fP which failed on attribute lookup. See PR #7 on GitHub. .UNINDENT .SS Version 0.4.0 .sp Released on March 6th, 2016 .INDENT 0.0 .IP \(bu 2 Fixed a bug in \fBClient.set_permissions\fP which coerced permission lists (e.g. \fB["b0"]\fP) to repr\-strings prior to validation. .IP \(bu 2 The API is now based around \fBbytes\fP, which means that all methods which used to accept \fBstr\fP (or text) now require \fBbytes\fP\&. 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. .IP \(bu 2 Removed \fBtransaction\fP argument from \fBClient\fP constructor. The user is advised to use the corresponding methods explicitly. .IP \(bu 2 Removed \fBconnection\fP argument from \fBClient\fP constructor. The user should now wrap it in a \fBRouter\fP\&. .IP \(bu 2 Renamed some of the \fBClient\fP methods to more human\-readable names: .TS center; |l|l|. _ T{ Old name T} T{ New name T} _ T{ ls T} T{ list T} _ T{ rm T} T{ delete T} _ T{ get_permissions T} T{ get_perms T} _ T{ set_permissions T} T{ set_perms T} _ T{ transaction_start T} T{ transaction T} _ T{ transaction_end T} T{ commit and rollback T} _ .TE .IP \(bu 2 Removed \fBClient.transaction\fP context manager, because it didn\(aqt provide a way to handle possible commit failure. .IP \(bu 2 Added \fBClient.exists\fP for one\-line path existence checks. See PR #6 on GitHub. Thanks to Sandeep Murthy. .IP \(bu 2 Removed implicit reconnection logic from \fBFileDescriptorConnection\fP\&. The user is now expected to connect manually. .IP \(bu 2 Changed \fBXenBusConnection\fP to prefer \fB/dev/xen/xenbus\fP on Linux due to a possible deadlock in XenBus backend. .IP \(bu 2 Changed \fBUnixSocketConnection\fP to use \fBsocket.socket\fP instead of the corresponding file descriptor. .IP \(bu 2 Disallowed calling \fBClient.monitor\fP over \fBXenBusConnection\fP\&. See \fI\%http://lists.xen.org/archives/html/xen\-devel/2016\-02/msg03816\fP for details. .UNINDENT .SS Version 0.3.1 .sp Released on November 29th 2012 .INDENT 0.0 .IP \(bu 2 Added \fBdefault\fP argument to \fBClient.read()\fP, which acts similar to \fBdict.get()\fP\&. .IP \(bu 2 Fixed a lot of minor quirks so \fBpyxs\fP can be Debianized. .UNINDENT .SS Version 0.3 .sp Released on September 12th 2011 .INDENT 0.0 .IP \(bu 2 Moved all PUBSUB functionality into a separate \fBMonitor\fP class, which uses a \fIseparate\fP connection. That way, we\(aqll never have to worry about mixing incoming XenStore events and command replies. .IP \(bu 2 Fixed a couple of nasty bugs in concurrent use of \fBClient.wait()\fP with other commands (see above). .UNINDENT .SS Version 0.2 .sp Released on August 18th 2011 .INDENT 0.0 .IP \(bu 2 Completely refactored validation \-\- no more \fI@spec\fP magic, everything is checked explicitly inside \fBClient.execute_command()\fP\&. .IP \(bu 2 Added a compatibility interface, which mimics \fIxen.lowlevel.xs\fP behaviour, using \fBpyxs\fP as a backend, see pyxs/_compat.py. .IP \(bu 2 Restricted \fISET_TARGET\fP, \fIINTRODUCE\fP and \fIRELEASE\fP operations to Dom0 only \-\- \fB/proc/xen/capabilities\fP is used to check domain role. .IP \(bu 2 Fixed a bug in \fBClient.wait()\fP \-\- queued watch events weren\(aqt wrapped in \fBpyxs._internal.Event\fP class, unlike the received ones. .IP \(bu 2 Added \fBClient.walk()\fP method for walking XenStore tree \-\- similar to \fBos.walk()\fP .UNINDENT .SS Version 0.1 .sp Initial release, released on July 16th 2011 .INDENT 0.0 .IP \(bu 2 Added a complete implementation of XenStore protocol, including transactions and path watching, see \fBpyxs.Client\fP for details. .IP \(bu 2 Added generic validation helper \-\- \fI@spec\fP, which forces arguments to match the scheme from the wire protocol specification. .IP \(bu 2 Added two connection backends \-\- \fBXenBusConnection\fP for connecting from DomU through a block device and \fBUnixSocketConnection\fP, communicating with XenStore via a Unix domain socket. .UNINDENT .SH AUTHOR Sergei Lebedev, Fedor Gogolev .SH COPYRIGHT 2011-2020, Selectel .\" Generated by docutils manpage writer. .