Citrix Blogs

Citrix XenServer: How to Access XenStore Information

A while ago, I wrote a Knowledge Base article (CTX136426) documenting the Windows Management Instrumentation (WMI) available in XenServer to transfer data between the hypervisor and an operating system within a VM such as a XenDesktop or XenApp VD. I still frequently get enquiries on our SDK forum that are basically looking to see if such an interface exists so I’m republishing my article here in the hope that google finds it easier to index!

Warning: This article is for the technical at heart!

The WMI interface in XenServer uses the underlying Xen hypervisor XenStore datastore. It is of particular use to developers looking to build products for the XenServer platform such as anti-virus or backup products for XenDesktop or management/monitoring solutions. However it could also be exploited by an experienced System Administrator to develop their own scripts and tools. WMI offers a mechanism to access information about a Windows Virtual Machine from within the guest Virtual Machine (VM), such as the name of the VM or its IP address.

I had a lot of help from a very helpful XenServer developer (Ben Chalmers) in their Windows tools team to write this article, he even wrote several code examples below to get others started.

The information is fairly technical but we’ve had a lot of requests for more technical blogs recently, such as feedback from the UK User Group. We do try to listen and accommodate all tastes 😉

The History of This Functionality

The XenStore_Client.exe is a small executable program that was (in previous versions of XenServer) distributed with the XenServer Tools and enabled users to access the value of parameters contained in XenStore. This program was removed from XenServer 6.1.0 as there was no knowledge of dependencies or other consumers. However, after the program was removed, Citrix noticed that there were users relying on this unsupported tool. XenStore_Client.exe was never officially supported or tested.

XenServer 6.1.0 introduced an alternative mechanism for extracting XenStore information by using Windows Management Instrumentation (WMI), which offers a far richer interface. This article provides information about using WMI for extracting XenStore information.

Developers wishing to use XenServer 6.2.0 and above and the Windows guest WMI interface as for communicating with XenStore and other hypervisor interfaces should read CTX136422 outlining its usage and providing code examples. The WMI interface can be used in XenServer 6.1.0 as an alternative to XenStore_Client.exe which was available in earlier versions of XenServer.

Summary

The XenStore_Client.exe is a small executable program that was (in previous versions of XenServer) distributed with the XenServer Tools and enabled users to access the value of parameters contained in XenStore. This program was removed from XenServer 6.1.0 as there was no knowledge of dependencies or other consumers. However, after the program was removed, Citrix noticed that there were users relying on this unsupported tool. XenStore_Client.exe was never officially supported or tested.

XenServer 6.1.0 introduces an alternative mechanism for extracting XenStore information by using Windows Management Instrumentation (WMI), which offers a far richer interface. This article provides information about using WMI for extracting XenStore information.

Background

This article is for (XenServer 6.1.0 and above) customers who use the Windows guest WMI interface as for communicating with XenStore and other hypervisor interfaces. The WMI interface can be used in XenServer 6.1.0 as an alternative to XenStore_Client.exe which was available in earlier versions of XenServer.
WMI offers a mechanism to access information about a Windows Virtual Machine from within the guest Virtual Machine (VM), such as the name of the VM or its IP address.

The Windows Guest WMI Interface

The Windows guest WMI interface is provided by the device driver xeniface.sys, which forms part of the XenServer Tools (Windows paravirtualized drivers). This interface is available to users who have been granted access to the root\wmi namespace (that is, the device driver namespace). By default, this is available only for administrators.

The WMI Interface provides a base singleton object (CitrixXenStoreBase) that can be used to generate individual session objects (CitrixXenStoreSession). These session objects represent individual applications (or functions of an application) and are the objects used to interact with XenStore; to read, write, set, and unset watches.

Sessions might also take advantage of the transaction semantics to ensure atomicity of XenStore operations. The lifetime of watches and transactions are limited by the lifetime of the session object which creates them. On driver load, an object CitrixXenStoreBase, is made available through WMI, which is a singleton object representing xenstore Properties: Uint64 XenTime: LocalTime as set by Windows for the VM, and then adjusted by the hypervisor’s clock.

WMI Objects

CitrixXenStoreBase

A singleton object representing XenStore:

Properties Description
Uint64 XenTime The Local Time set by windows for the VM, and then adjusted by the hypervisor’s clock.
Methods Description
AddSession
(String Id)
Add a CitrixXenStoreSession object to the WMI namespace. The returned value (SessionId) is a unique value which can be used to identify the session which has been created (in case multiple sessions have the same string identifier).Returns SessionId.

CitrixXenStoreSession

Each instance represents a single session of communication with XenStore:

Properties Description
String ID A string to identify the use of the session and to determine if any sessions which have been left open can be closed
Uint32 SessionID An integer, unique amongst all sessions. This integer is the same as the integer value returned when AddSession creates the session.
Methods Description
StartTransaction Until the transaction is ended, all activities on this session occur within a transaction (hence activities will not affect XenStore until the transaction is committed).
CommitTransaction Attempt to commit the current session’s transaction. If this fails, the transaction has not succeeded, and may need to be retried.
EndTransaction Cancel the current transaction without committing
GetValue (String Pathname) Returns string value. Returns the value stored at the path Pathname in XenStore
GetChildren
(String Pathname)
Returns children { UInt32 NoOfChildNodes, String[NoOfChildNodes]ChildNodes}: For a given node (at PathName), this returns an object containing the number of child nodes, and an array of strings, where each string is the full pathname of a child node.
RemoveValue
(String Pathname):
Removes an entry from XenStore (and, if they exist, all descendent entries)
SetValue(String Pathname, String value) Set the value at a given pathname to Value
Log(String): Outputs a log message to the hypervisor
SetWatch(String Pathname) Watch a specified XenStore entry for changes.
Note
: Multiple changes of the same XenStore entry, which occur soon after one another, can be merged into one WMI event. The event is received after all the changes referred to by the merged event occur.
RemoveWatch (String Pathname) Remove the watch, set previously with SetWatch.
EndSession() Terminate this session. Remove the session object from the WMI namespace. All watches and transactions associated with the session will be ended

Events

CitrixXenStoreWatchEvent

Event is raised when a particular XenStore entry changes. Multiple close changes of a XenStore event might be merged into one CitrixXenStoreWatchEvent. You can register your interest in receiving such an event by calling CitrixXenStoreSession.SetWatch(pathname)

Properties Description
String EventId The pathname of the XenStore value which has changed

CitrixXenStoreUnsuspendedEvent

Event is raised whenever a VM resumes from suspended state.
Power Shell Example:
The following example uses PowerShell to show how you can script the XenStore WMI interface:

# Locate the base object
$base = gwmi -n root\wmi -cl CitrixXenStoreBase
# Create a session
$sid = $base.AddSession("MyNewSession")
$session = gwmi -n root\wmi -q "select * from CitrixXenStoreSession where SessionId=$($sid.SessionId)"
# Write a value
$session.SetValue("data/TempValue","This is a string")
# Read a value
$session.GetValue("data/TempValue").value
# Read the current VM's name
$session.GetValue("name").value
# Remove a value
$session.RemoveValue("data/TempValue")
#Examine Children
$session.GetChildren("data").children
# Set Watch
$watch = Register-WMiEvent -n root\wmi -q "select * from CitrixXenStoreWatchEvent where EventId='data/TempValue'" -action {write $session.getvalue("data/TempValue") }
$session.setvalue("data/TempValue","HELLO")
$session.setvalue("data/TempValue","WORLD")
$watch.action.output 

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

Visual Basic Example:

rem testwmi.vbs
rem a sanity check for the xeniface wmi interface
rem can be called using cscript.exe
rem will set %ERRORLEVEL% to 0 on success and 1 on failure
rem will also output the text 'SUCCESS' or an error message
rem
rem This code was designed to showcase functionality and
rem should not be regarded as production quality.

Set objWMIService = GetObject("winmgmts:\\.\root\wmi")
Set base = objWmiService.InstancesOf("CitrixXenStoreBase")
Dim answer
Dim answer2
Dim objItem

rem Locate the base object

if (base.Count)  1 then
   wscript.echo("Too many base objects found")
   wscript.quit(1)
end if
for each itementry in base
   rem is there a more trivial way of getting the only item from a collection in vbscript?
   set objItem = itementry
next

rem Add two sessions

objitem.AddSession "VBSTestSession", answer
objitem.AddSession "AnotherVBSTestSession", answer2

rem locate the first session

query = "select * from CitrixXenStoreSession where SessionId = '" & answer & "'"
Set sessions = objWMIService.ExecQuery(query)
if (sessions.count)  1 then
   wscript.echo("Too many session-1 sessions found")
   wscript.quit(1)
end if
for each itementry in sessions
   rem is there a more trivial way of getting the only item from a collection in vbscript?
   set session = itementry
next

rem locate te second session

query = "select * from CitrixXenStoreSession where SessionId = '" & answer2 & "'"
Set sessions2 = objWMIService.ExecQuery(query)
if (sessions2.count)  1 then
   wscript.echo("Too many session-2 sessions found")
   wscript.quit(1)
end if
dim session2
for each ses in sessions2
   Set session2=ses
next

rem ensure we located the expected session

if session.Id  "VBSTestSession" then
   wscript.echo("incorrect session found")
   wscript.quit(1)
end if

rem blank a set of xenstore entries

session.removevalue "data/wmitestrun"

rem and put a known set of values there

session.SetValue "data/wmitestrun/test1", "Testing"
session.SetValue "data/wmitestrun/test2", "123 Testing"
session.SetValue "data/wmitestrun/test3", "456 Testing"
session.SetValue "data/wmitestrun/test4", "789 Testing"

rem read back a value from xenstore, and check that it is right

session.getvalue "data/wmitestrun/test1", res
if res  "Testing" then
   wscript.echo("failed writing or reading to data/wmitestrun/test1")
   wscript.echo("read = " & res)
   wscript.quit(1)
end if 

rem read back a different value from xenstore, and check that it is right

session.getvalue "data/wmitestrun/test2", res
if res  "123 Testing" then
   wscript.echo("failed writing or reading to data/wmitestrun/test2")
   wscript.echo("read = " & res)
   wscript.quit(1)
end if 

rem transactions
rem test that aborted transactions don't do anything

session.starttransaction()
session.SetValue "data/wmitestrun/test1", "WEIRD"
session.getvalue "data/wmitestrun/test1", res
if res  "WEIRD" then
   wscript.echo("failed writing or reading within transaction to data/wmitestrun/test1")
   wscript.echo("read = " & res)
   wscript.quit(1)
end if
session.aborttransaction()

session.getvalue "data/wmitestrun/test1", res
if res  "Testing" then
   wscript.echo("failed reading to data/wmitestrun/test1 after aborted transaction ")
   wscript.echo("read = " & res)
   wscript.quit(1)
end if

rem test that 2 overlapping transactions honour commits and aborts, and raise errors when needed

session.starttransaction()
session2.starttransaction()
session.SetValue "data/wmitestrun/test1", "WEIRD"
session2.SetValue "data/wmitestrun/test1", "Fish"
session.getvalue "data/wmitestrun/test1", res
session2.getvalue "data/wmitestrun/test1", res2
if res  "WEIRD" then
   wscript.echo("failed writing or reading within transaction to data/wmitestrun/test1 session 1")
   wscript.echo("read = " & res)
   wscript.quit(1)
end if
if res2  "Fish" then
   wscript.echo("failed writing or reading within transaction to data/wmitestrun/test1 session 2")
   wscript.echo("read = " & res)
   wscript.quit(1)
end if 

on error resume next
session.committransaction()
Err.clear()
if Err.Number  0 then
   wscript.echo("Could not commit first transaction")
   wscript.quit(1)
end if
session2.committransaction()
if Err.Number = 0 then
   wscript.echo("Both transactions comitted")
   wscript.quit(1)
end if
session2.aborttransaction()
session2.getvalue "data/wmitestrun/test1", res2
if res2  "WEIRD" then
   wscript.echo("failed commiting the correct transaction")
   wscript.echo("read = " & res)
   wscript.quit(1)
end if 

rem events
rem set up an event sink

dim refsink
set refsink = CreateObject("WBemScripting.SWbemSink")
wscript.ConnectObject refsink, "EVENTSINK_"
stq = "Select * from CitrixXenStoreWatchEvent"
objwmiservice.ExecNotificationQueryAsync refsink, stq

evtcount = 0

rem watch a xenstore entry

allevents=0
session.setwatch "data/wmitestrun/test1"
session.setvalue "data/wmitestrun/test1","MAGIC"
session.removevalue "data/wmitestrun/test1"
session.setvalue "data/wmitestrun/test1","GOLD"
wscript.sleep(5000)
session.removewatch "data/wmitestrun/test1"

rem check we received an event. Also, since events can be coalesced, check
rem that when we receive our final event, the value we read from test1 is the
rem final value we set it to

rem (note the actual work of counting and checking events is done in the
rem EVENTSINK_OnObjectready sub below)
)
if evtcount <= 4 and allevents  1 then)
   wscript.echo("Failed to catch all the expected events")
   wscript.quit(1)
end if

session.removevalue "data/wmitestrun/test1"

rem check that we can read the list of children an entry has

strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

Set colOperatingSystems = objWMIService.ExecQuery _
("Select * from Win32_OperatingSystem") 

for each os in colOperatingSystems
   rem is there a more trivial way of getting the only item from a collection in vbscript?
   set myos = os
next

wscript.echo(myos.Version)

if Mid(myos.Version, 1 , 3)  "6.0" then
   dim children
   session.getchildren "data/wmitestrun", children

   if children.noofchildnodes  3 then
     wscript.echo("Failed to find all the expected child nodes")
     wscript.quit(1)
   end if
end if

session.getfirstchild "data/wmitestrun", res
session.getnextsibling res, res

rem end both sessions that we created.

session2.EndSession()
session.EndSession()

Wscript.echo("Success")

Sub EVENTSINK_OnObjectReady(re, rc)
   evtcount = evtcount + 1
   session.getvalue "data/wmitestrun/test1", res
   if res = "GOLD" then
     allevents = 1
   else
     allevents = 0
   end if
end sub

rem Copyright (c) Citrix Systems, Inc.
rem All rights reserved.
rem
rem Redistribution and use in source and binary forms, with or without
rem modification, are permitted provided that the following conditions
rem are met:
rem
rem 1) Redistributions of source code must retain the above copyright
rem notice, this list of conditions and the following disclaimer.
rem
rem 2) Redistributions in binary form must reproduce the above
rem copyright notice, this list of conditions and the following
rem disclaimer in the documentation and/or other materials
rem provided with the distribution.
rem
rem THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
rem "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
rem LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
rem FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
rem COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
rem INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
rem (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
rem SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
rem HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
rem STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
rem ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
rem OF THE POSSIBILITY OF SUCH DAMAGE.
rem

More Information
The following command line tools which are shipped with Windows are particularly useful for exploring WMI:
• Wbemtext.exe provides a graphical user interface (GUI)
• Wmic.exe is a command line tool which can be used for accessing WMI

There are a number of external WMI explorers available.
• Windows Management Instrumentation
• Wikipedia: Windows Management Instrumentation.

Disclaimer

The sample code is provided to you AS IS with no representations, warranties or conditions of any kind. You may use, modify and distribute it at your own risk. CITRIX DISCLAIMS ALL WARRANTIES WHATSOEVER, EXPRESS, IMPLIED, WRITTEN, ORAL OR STATUTORY, INCLUDING WITHOUT LIMITATION WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NONINFRINGEMENT. Without limiting the generality of the foregoing, you acknowledge and agree that (a) the sample code may exhibit errors, design flaws or other problems, possibly resulting in loss of data or damage to property; (b) it may not be possible to make the sample code fully functional; and (c) Citrix may, without notice or liability to you, cease to make available the current version and/or any future versions of the sample code. In no event should the code be used to support of ultra-hazardous activities, including but not limited to life support or blasting activities. NEITHER CITRIX NOR ITS AFFILIATES OR AGENTS WILL BE LIABLE, UNDER BREACH OF CONTRACT OR ANY OTHER THEORY OF LIABILITY, FOR ANY DAMAGES WHATSOEVER ARISING FROM USE OF THE SAMPLE CODE, INCLUDING WITHOUT LIMITATION DIRECT, SPECIAL, INCIDENTAL, PUNITIVE, CONSEQUENTIAL OR OTHER DAMAGES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. Although the copyright in the code belongs to Citrix, any distribution of the code should include only your own standard copyright attribution, and not that of Citrix. You agree to indemnify and defend Citrix against any and all claims arising from your use, modification or distribution of the code.

Exit mobile version