Using the XenServer API Event.from() to replace the legacy Event.next() API
If a host is generating a very high number of events, the internal queue used by the event.next() API can fail. In the event that this happens a user will need to unregister and register for events. For this reason we recommend the newer API event.from which is architected to avoid the internal queue limitation.
event.from allows the user to request all the events from a particular event via a token. This allows a user to poll for events at an interval of their choosing. event.from takes a timeout value after which the API will return even if no events have occurred, otherwise the API will return one or more events when detects further events have occurred, along with the array/list of events a new token is returned containing information about the last event returned to the user. This new token can be used by the user to limit the returned events to those that have occurred since the last call to event.from. If a user want to access all stored previous events e.g. the first time calling event.from the user should use an empty string as the token.
NOTE: Within the Python bindings, as from is a reserved word, in python the function must be accessed via event_from i.e. session.xapi.event_from
A Python Code Example Demonstrating the recommend usage of event.from
#!/usr/bin/env python # Copyright (c) Citrix Systems, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1) Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # 2) Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials # provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # OF THE POSSIBILITY OF SUCH DAMAGE. # Simple python example to demonstrate the event system. Logs into the server, # registers for all events and prints them to the screen. # call via python event_from.py http://myhost.uk.xensource.com user_name user_password import XenAPI, sys, time # if no events occur the call to event_from will return after this interval # if events do occur the call will return sooner EVENT_FROM_TIMEOUT = 30.0 # if the token parameter is set to an empty string, the return from event_from will contain all # events that have occurred, you probably want to use this the first time you use event_from token_from ='' # Register for events on all classes event_types = ["*"] # A C-sharp example can be found in open sourced XenCenter in XenAPI.XenObjectDownloader.cs # XenCenter is fully open source, and is available at https://github.com/xenserver/xenadmin under a BSD-style license. def main(session): try: global event_types global token_from global EVENT_FROM_TIMEOUT while True: # event_from will return a new token # the user does not need to manipulate this token # The token contains information about the last event return, # if this token is passed into a subsequent call to event_from_ret the user # will receive only events later than events returned by the first call event_from_ret = session.xenapi.event_from(event_types, token_from, EVENT_FROM_TIMEOUT) ret_token = event_from_ret['token'] events = event_from_ret['events'] token_from = ret_token # print number of events print "Number of events: " + repr(len(events)) # print events # Print the events out in a nice format: fmt = "%8s %20s %5s %s" hdr = fmt % ("id", "class", "type", "name of object (if available)") print "-" * (len(hdr)) print hdr print "-" * (len(hdr)) for event in events: # print event name = "(unknown object name)" if "snapshot" in event.keys(): snapshot = event['snapshot'] if "name_label" in snapshot.keys(): name = snapshot['name_label'] print fmt % (event['id'], event['class'], event['operation'], name) # only poll every 5 minutes = 300 seconds print "Sleeping for 5 minutes" time.sleep(300) finally: session.xenapi.session.logout() if __name__ == "__main__": if len(sys.argv) <> 4: print "Usage:" print sys.argv, "
" sys.exit(1) url = sys.argv username = sys.argv password = sys.argv # First acquire a valid session by logging in: session = XenAPI.Session(url) session.xenapi.login_with_password(username, password) main(session)
Legacy usage of event.next
When using the legacy function event.next, for legacy usage, the user needs to handle the API failure thus:
except XenAPI.Failure, e: if e.details <> [ "EVENTS_LOST" ]: raise print "** Caught EVENTS_LOST error: some events may be lost" # Check for the "EVENTS_LOST" error (happens if the event queue fills up on the # server and some events have been lost). The only thing we can do is to # unregister and then re-register again for future events. # NB: A program which is waiting for a particular condition to become true would # need to explicitly poll the state to make sure the condition hasn't become # true in the gap. # session.xenapi.event.unregister(["*"]) # session.xenapi.event.register(["*"])