HOWTO: Monitor Virtual Server Events
I think Virtual Server Events and Asynchronous Tasks are two of the least utilized features of the Virtual Server Administration API.
Contrary to the often-asked task of "find the VM, turn it off, manipulate its VHD, then turn it back on", which shows the synchronous, task-driven side of the VS Admin model, Events and Asynchronous Tasks show off a nice event-based, asynchronous model suitable for passive monitoring and response. What good is this?
Well... that's the motivation behind this blog entry's sample code, which illustrates a simple "Virtual Server Monitor Agent" which does a few basic things:
- By default, it simply monitors all Virtual Server events and reports them to the console window. Assuming you named the JScript code VSMonitor.js, just launch it from the commandline with:
START CSCRIPT VSMonitor.js - Thereafter, whenever you start a Virtual Machine, a new child monitor script will pop up and monitor just that Virtual Machine
- If that Virtual Machine has a Virtual DVD drive, they will also be monitored for media insertion/ejection and type (ISO or drive letter path)
- When you turn off a Virtual machine, its associated child monitor script will also terminate (but it will first popup a message telling you this, in case you missed it).
- It also notices when you fail to startup a Virtual Machine due to Out-of-Memory and report that via a popup
The sample basically illustrates how to:
- Sync on Virtual Server wide events
- Act on a Virtual Server wide event
- Sync on Virtual Machine specific events
- Act on a Virtual Machine specific event
- Sync on Virtual DVD specific events
- Report on Virtual DVD events
And it should provide enough information for you to play around, note when events happen, and note available data for the event... and implement other interesting ideas supported by the API. I don't have any in mind, but if you do... feel free to share... because then I may update this sample to do something more interesting. :-)
Enjoy.
//David
var strVMName = "sample VM Name";
var CRLF = "\r\n";
var NO_WAIT = false;
var VISIBLE = 1;
var ERROR_VM_NOT_FOUND = -2146828283;
var ERROR_VM_OUT_OF_MEMORY = 3238134821;
var fSignaled = false;
var fPopup = true;
var cPeriod = 10000;
var VM_STATE_STRING = {
0 : "Invalid",
1 : "Off",
2 : "Saved",
3 : "Turning on",
4 : "Restoring",
5 : "Running",
6 : "Paused",
7 : "Saving",
8 : "Turning off",
9 : "Merging drives",
10 : "Deleting VM"
};
var VM_STATE_OFF = 1;
var VM_STATE_RUNNING = 5;
var objVS = null;
var objVM = null;
var objDVD = null;
var objShell = null;
var enumObjs;
var enumObj;
if ( WScript.Arguments.Length > 0 )
{
strVMName = WScript.Arguments.Item( 0 );
}
try
{
objShell = new ActiveXObject( "WScript.Shell" );
objVS = new ActiveXObject( "VirtualServer.Application" );
try
{
//
// Try to locate the specified VM and listen for its events
// If fail to locate VM, just listen for VS-wide events
//
objVM = objVS.FindVirtualMachine( strVMName );
WScript.ConnectObject( objVM, "VirtualMachineEvent_" );
//
// If the VM has any DVD drives, listen for their changes, too
//
enumObjs = new Enumerator( objVM.DVDROMDrives );
for ( ; !enumObjs.atEnd(); enumObjs.moveNext() )
{
objDVD = enumObjs.item();
WScript.ConnectObject( objDVD, "VirtualDVDEvent_" );
}
}
catch ( e )
{
if ( e.number == ERROR_VM_NOT_FOUND )
{
LogEcho( "Failed to find VM " + strVMName + "." );
}
else
{
LogEcho( formatErrorString( e ) );
}
objVM = null;
WScript.ConnectObject( objVS, "VirtualServerEvent_" );
}
LogEcho( "Waiting for Events from: " + CRLF +
( objVM != null ? "- VM " + strVMName + CRLF : "- VS Wide" ) +
( objDVD != null ? "- DVD Drive(s)" + CRLF : "" ) +
"" );
//
// Poll every cPeriod time period to determine if should exit
//
while ( !fSignaled )
{
WScript.Sleep( cPeriod );
}
}
catch ( e )
{
LogEcho(
formatErrorString( e ) + CRLF +
( objShell == null ?
"Failed to create WScript.Shell - check:" + CRLF +
"- %windir%\System32\WSHOM.OCX is ACLed for user" + CRLF +
"- Scripts are allowed by Personal Security products" + CRLF :
"" ) +
( objVS == null ?
"Failed to create Virtual Server COM object - check:" + CRLF +
"- Virtual Server is installed" + CRLF +
"- User has Control/Execute Access in VS Security" + CRLF :
"" )
);
LogEcho( "Waiting a few seconds for you to read this..." );
WScript.Sleep( cPeriod );
}
function LogEcho( str )
{
WScript.Echo( str );
}
function LogPopup( str )
{
if ( fPopup )
{
objShell.Popup( str );
}
else
{
LogEcho( str );
}
}
function formatErrorString( objError )
{
return "(" + Int32ToHRESULT( objError.number ) + ")" + ": " +
objError.description;
}
function Int32ToHRESULT( num )
{
if ( num < 0 )
{
return "0x" + new Number( 0x100000000 + num ).toString( 16 );
}
else
{
return "0x" + num.toString( 16 );
}
}
//
// Virtual Server Events
//
function VirtualServerEvent_OnEventLogged( e )
{
LogEcho( "VirtualServer_OnEventLogged: (Event ID) " + e );
if ( e == ERROR_VM_OUT_OF_MEMORY )
{
LogPopup( "Cannot start VM due to out of memory" );
}
}
function VirtualServerEvent_OnHeartbeatStopped( e )
{
LogEcho( "VirtualServer_OnHeartbeatStopped: (VMName) " + e );
}
function VirtualServerEvent_OnServiceEvent( e )
{
LogEcho( "VirtualServer_OnServiceEvent: (Event ID) " + e );
}
function VirtualServerEvent_OnVMStateChange( e, s )
{
var retVal;
LogEcho( "VirtualServer_OnVMStateChange: VM " + e + " " +
"changed to state " + s + "(" + VM_STATE_STRING[ s ] + ")" );
switch ( s )
{
case VM_STATE_RUNNING:
LogEcho( "Running " + WScript.ScriptFullName +
" to monitor VM " + e );
retVal = objShell.Run(
"CSCRIPT.EXE" + " " +
"\"" + WScript.ScriptFullName + "\"" + " " +
"\"" + e + "\"",
VISIBLE,
NO_WAIT );
break;
}
}
function VirtualMachineEvent_OnConfigurationChanged( e, s )
{
LogEcho( "VirtualMachine_OnConfigurationChanged: " + strVMName + " " +
"config " + e + " = " + "\"" + s + "\"" );
}
function VirtualMachineEvent_OnHeartbeatStopped()
{
LogEcho( "VirtualMachine_OnHeartbeatStopped: " + strVMName );
}
function VirtualMachineEvent_OnRequestShutdown()
{
LogEcho( "VirtualMachine_OnRequestShutdown: " + strVMName );
//
// return true/false to reboot
//
return false;
}
function VirtualMachineEvent_OnReset()
{
LogEcho( "VirtualMachine_OnReset: " + strVMName );
}
function VirtualMachineEvent_OnStateChange( e )
{
LogEcho( "VirtualMachine_OnStateChange: " + strVMName + " " +
"changed to state " + e + "(" + VM_STATE_STRING[ e ] + ")" );
switch ( e )
{
case VM_STATE_OFF:
LogPopup( "Signaled to stop monitoring VM " + strVMName );
fSignaled = true;
break;
}
}
function VirtualMachineEvent_OnTripleFault()
{
LogEcho( "VirtualMachine_OnTripleFault: " + strVMName );
}
function VirtualDVDEvent_OnMediaInsert( e )
{
LogEcho( "VirtualDVDEvent_OnMediaInsert: " + strVMName + " " +
"DVD is bound to " + e );
}
function VirtualDVDEvent_OnMediaEject( e )
{
LogEcho( "VirtualDVDEvent_OnMediaEject: " + strVMName + " " +
"DVD is not bound to " + e );
}
Comments
- Anonymous
June 30, 2006
Where should I load this script within the VM or under VM-> Configuration-> Scripts (just enable the script within the Virtual Server. - Anonymous
June 30, 2006
ZEKE - this is a stand-alone script, so just launch it from the commandline on the Host. You can't run it in the Guest, and running under VM->Configuration->Scripts doesn't make sense because those are the events.
//David - Anonymous
June 30, 2006
Ok I ran the script like this, I have it loaded on my desktop as VSMonitor.js then I open the cmd prompt and go under c:Documents and Settings"usrname"> Start CSCRIPT VSMonitor.js
then a seprate cmd window pops up and goes away quickly, so I restarted the vm's and closed the Virtual Server and I have noticed no changes for monitoring.
I am running VS on top of windows xp
My VM's are installed on my external harddrive - Anonymous
July 01, 2006
The comment has been removed - Anonymous
July 03, 2006
Will this script work for VS2005 r2, because I tell you it is completely not showing anything for me, I did change the name at the top of your script to the name of my Virtural Manchine. - Anonymous
July 03, 2006
zeke - it definitely works on VS2005R2 - that is what I developed against.
I think you are running other software on your machine that is preventings scripts from working. I just updated the script to help troubleshoot that - try the new version.
//David - Anonymous
July 03, 2006
No! I am running some other scripts of yours that are working fine with my VM some how it seems that this is the only script that does not work, do I have to change anything within the script to get it to work with mine? - Anonymous
July 03, 2006
Zeke - nothing should need to change. The script runs as-is by default - NO MODIFICATIONS NECESSARY. I would not change strVMName since you lose the VM monitoring feature when you do that...
Just to be certain - this script cannot be modified to run for remote Virtual Servers. You can only monitor events for the server you run the script on. It's a limitation of these "pseudo-events" from WScript that is used.
Since you have the source code, I suggest that you try to debug your machine to determine when and why the script is exiting. I have not seen a machine with Virtual Server 2005 (or R2) that fail to run this properly, with both XPSP2 and WS03SP1 as Host, so I cannot debug without an example of the failure.
//David - Anonymous
July 05, 2006
The comment has been removed