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 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. |
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.
Powershell - Code 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 - Code 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.
Warning! This Web site might contain links to Web sites controlled by parties other than Citrix. Citrix is not responsible for and does not endorse or accept any responsibility for the contents or use of these third party Web sites. Citrix is providing these links to you only as a convenience, and the inclusion of any link does not imply endorsement by Citrix of the linked Web site. It is your responsibility to take precautions to ensure that whatever you select for your use is free of viruses or other items of a destructive nature
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.