It is some time that I’m interested in virtualization: I think it is a nice way to keep my machine healty and clean, and in the same time it allows me to experiment and do “distruptive” things.
I love the possibility to take snapshots and recover a previous state in a moment!
Probably some of you have noticed that “photoatomiclab.net” is not always online(there is a reason for this you’ll discover in a moment), right? I know it is boring and frustrating when a resource is not available when you need it, and for this I’m really sorry.
So… I’ve started thinking on how to improve the thing. First of all: my favorite virtualization environment is VirtualBox (too bad Oracle have bought it, I hope it will not ruine all this good work) I like it because is free, is fast (in my opinion far better than VMWare) and it is supported by an opensource community… and having the source code in your hands you can do great things.
Anyway… my site is not always available: that’s because it is hosted on a virtual machine on my real machine! ANd this because I always like to know the internals and from time to time I had some crazy ideas: like streaming the town fest in the square in front of my windows using my HD camera ( LOL, usually I did this on xmas night) or connect some netduino robots and drive it from a web interface… this requires me to have a host where I really can do everything. and these host services are not cheap, unfortunately
But hey! VirtualBox really saves the day! So I have this virtualmachine “Bear” that runs my site… the one you are reading now. And it is hosted on my real machine… and my machine is housed in my bedroom… and at night I like to sleep
It is natural that I shut id down at night… and therefore the site becomes unavailable….
Again, my pc is setup to start up at about 14.00 CET every day (that’s because it have to record my favorite tv series…. but this is another story) and since I’m forgetful, I usually don’t remember to turn the VM on, so I’ve tough to improve the situation… I’ve started searching for a tool that allows me to automatically starts my VM up when the pc starts.
I’ve found VirtualBox headless mode… nice! but… I have not found a way to use it… expecially because for the shutd down part… I want my VM freezes its state when the pc is shutted down.. I don’t want to loose the last change on the site, nor to wait minutes for the virtualized machine shut down…
I’ve serched for days but nothing appears to be a strong solution…. there are some services that tries to emulate this but at the end they open a shell and invokes the command line version ov VBOX and “do things”
this have the bad behavior (in the major part of the occasions) to open console windows for some seconds, or to leave consoles opened…. and if you close the console .. the VM dies
this is ugly and completely unprofessional.
But fortunately VirtualBox is opensource! and there are SDKs!!
so I’ve started up VisualStudio2010 and I’ve started writing my own virtual machine server
(the one that is running this site now… if you are reading it!) and I’ve learned a lot of things, I hope to remember them all and I’m going to write these down now.
Background:
My pc is a quad core with HT (8 hardware thread) with 16 GB, so I don’t have problem in letting a VM running al day, I don’t feel it except for the startup and shutdown phase that is disk intensive (even with a raid5, unfortunately, I’ll tray later with a solid state raid)
anyway to do this project I want to explore the following things
Ingredients:
COM interoperability at 64 Bits
Windows Services (I’ve never wrote a serious one before)
.NET Framework 4
LINQ (I love linq) and LINQ to XML
TPL (Task Parallel library)
Target:
- (step1) I want a windows service that is able to starts some of the VM I’ve set up in the VirtualBox console automatically and automatically suspend them when I shut down my pc.
- (step2) I want a gadget for the windows 7 sidebar that allows me to monitor the VM and modify startup/shutdown behavior.
Now I’ve completed the Step 1. there is an XML file that describes which VM have to be started and what to do if the service or the pc is shouted down.
Preparation:
I’ve never wrote before an application that targets the 64 bit version of the .NET framework explicitly, there are a lot of interesting things if you want to do this.
- in the config manager create the x64 platform
- in the projects that have to use the 64 bit COM object exposed by the virtualbox SDK (but this is true for any 64 bit com) in project properties –> build set the target platform to 64 bit
- if you want to do TestDrivenDevelopment or in any case if you need to perform automatic test, your test project have to be set to “Any CPU” in the target platform, otherwise you could not debug them.
- in the Local.Testsettings solution item in the Host menu, select “run test in 64 bit process on 64 bit machines”
that should be enough as setup
Then every time you add a reference to the COM object to one of your project remember to change the property of the just added reference to
- Copy Local –> True
- Embed interop type –> FALSE
- Isolated –> False
Good! you are ready to code!
humm…. no not really!
for a reason that sounds VERY strange to me, and I suppose it is due to the way the source code of VBox is made and its portability to other platform, you could not invoke the SDK’s COM function if your executable is in a folder different from where the virtualbox program is installed. to tell the true I’ve not investigated well this aspect. but my solution was to deploy my compiled files in the same directory of VBOX… I know… it’s not very beauty but consider that at the end my server is just another “frontend” for virtualbox, and all the vbox frontend are in the same dir… where also mine is deployed… so… not too bad.
Ok, now you are really ready and you can start code your server!
Nice things to know: VBOX APIs are quite easy to use, the
documentation is not bad at all! but there are some things to note:
1) I’ve not found in the docs why my exe need to stay in the same folder of the other files in order to run correctly… as I’ve said I’ve not investigated but it appears to be a “by design” of the VBOX sdk, maybe there are workarounds… I don’t know at the moment
2) once you have found the way to start/restore your VM you’ll notice that even if it is started (the VBOX graphic console is a great tool and hels a lot for this…) it doesn’t reply at all to any message you can send to it… that’s because even if it runs in another thread,if the main thread is stucked in a busy wait (or spin lock) ti doesn’t have enough processing power to work –> solution.. once the machine are started, put the main “server” thread to sleep, this will free the cpu and let the vm to run ( I suppose that it is required just to dispatch messages to the COM infrastructure, in fact each VM spawn it’s own process…)
3)there are about zero documentation on how to create your own frame buffer for the VM console, you need this to make your VM headless… fortunately it is not so hard to guess how it should work… you can look at the sourcecode of the actual headless frontend and guess from there!
So at the end you’ll have your beauty server.. and it works! (I run it in a test console for a while… testing the freeze the ACPI shut down the restore…. everything! and that’s why my site went up and down dozen of times in the last weeks.. I suppose google hates me
, I should have a very bad rank…)
Anyway… at the end you have your server, and you want to turn it in a windows service!
it should be easy… right?
as I’ve never wrote a service before… I’ve discovered a lot of things
1)that’s not enough that you create a service project using the template, you also have to add the installation part to make it work (at least this is what I’ve found on internet, I’ve not verified if it works without the installer)
The highlighted items are the one for the installation… to generate them double click on the VirtualBoxService.cs item (in the example above) and from the grey screen that will appear right click on the background and select “add installer”
Make sure that the rest of parameters are correctly configured you don’t need to write code unless you need something special. Mine works without adding any custom code to the ProjectInstaller items.
OK! compile everything and now you are almost done! as we have configured the output dir to place the compiled files in the Vbox installation path, you only need to register the service….
But … now other problems arises.
I’ve opened a normal visual studio console and used the
INSTALLUTIL myservice.exe
command… and I’ve recived a BadImage exception, I was sure it was something related to the 64 bits… in fact visual studio have several console available
some are 32 bits some are 64
You should use Visual Studio x64 Win64 Command Prompt (2010), the last one in the pic above.
but… if you now run again
INSTALLUTIL myservice.exe
you’ll probably receive a ACCESS DENIED error.
to work around this you need to start the console in admin mode (right click on the link –> “run as administrator”)
this time the command will work and the service will be registered… you’ll see it in the services console.
now you can run and stop it as many time you want….
except that this is VirtualBox and I’m afraid that for the sake of the portability they have obtained the so called “cucumbersome” design.
again probably for the same reason of the path problem above (the one that requires that the exe is in the same dir of the other vbox files in order to work) if you run the service from the service panel, it will simply not find any of the virtualmachines you have defined.
And I’m going to explain you why: basically when you run a service, you can setup the user that will be used to run it. if you don’t set up any particular user it will use Local System.
But is Local System a real user? I don’t know.. I suppose is something special in fact its home dir is something like
C:\Windows\system32\config\systemprofile
On Windows 7. that’s its home dir.
The VBOX Api uses the home dir of the user that run the api to "guess” where the irtualbox configuration file is
Usually VBOX places it
C:\Users\UserName\.VirtualBox\VirtualBox.xml
there. The problem is that if you run the service as local user vbox will search the VirtualBox.xml file in
C:\Windows\system32\config\systemprofile\.VirtualBox\VirtualBox.xml
And will find nothing at all!
You should then think that you just need to change the logon user in the service, and setup the name of the user that have created the machines…. uh?
No! too easy
there is a “by design” (new name for bug, much more cool) that avoids the vbox api to retrive the correct home of the user, and keeps returning the “systemprofile” path
The incriminated function is GetVBoxUserHomeDirectory in the COM class.
but if you look at the source code you can find also a workaround!
Give it a look!
int GetVBoxUserHomeDirectory(char *aDir, size_t aDirLen)
{
AssertReturn(aDir, VERR_INVALID_POINTER);
AssertReturn(aDirLen > 0, VERR_BUFFER_OVERFLOW);
/* start with null */
*aDir = 0;
char szTmp[RTPATH_MAX];
int vrc = RTEnvGetEx(RTENV_DEFAULT, "VBOX_USER_HOME", szTmp, sizeof(szTmp), NULL);
if (RT_SUCCESS(vrc) || vrc == VERR_ENV_VAR_NOT_FOUND)
{
if (RT_SUCCESS(vrc))
{
/* get the full path name */
vrc = RTPathAbs(szTmp, aDir, aDirLen);
}
else
{
/* compose the config directory (full path) */
/** @todo r=bird: RTPathUserHome doesn't necessarily return a full (abs) path
* like the comment above seems to indicate. */
vrc = RTPathUserHome(aDir, aDirLen);
if (RT_SUCCESS(vrc))
vrc = RTPathAppend(aDir, aDirLen, VBOX_USER_HOME_SUFFIX);
}
/* ensure the home directory exists */
if (RT_SUCCESS(vrc))
if (!RTDirExists(aDir))
vrc = RTDirCreateFullPath(aDir, 0777);
}
return vrc;
}
see at line 8: it first try to search for an environment variable called VBOX_USER_HOME! the fact is that on windows the use of environments variables is something not so up to date… people tries to avoid these, but anyway they exists and since it is so common on other OS, to make everybody happy VBOX can use it… even if the windows installer doesn’t create this (and the doc is not so clear about this)
anyway! just define a global system variable lake that
VBOX_USER_NAME=C:\Users\UserName\.VirtualBox
and BOOM! your service will find the VMs!
Aaaah! I’m so happy now
I can run virtualmachines automagically and make it suspendand restore when I shut down/power up my pc
I think I’ll put the project on codeplex or maybe on this site when it will be a little more refined. for now it looks pretty stable but I want to test it for a couple of days before releasing the first alpha.
Anyway if someone is intereste din the project, please contact me or leave a comment on the blog
Tags: c#, VirtualMachines