Electricmonk

Ferry Boender

Programmer, DevOpper, Open Source enthusiast.

Blog

Multiple VirtualBox VMs using one base image (copy-on-write)

Saturday, September 24th, 2011

As a developer and systems administrator, I use VirtualBox a lot for building binaries, testing upgrades, etc. It always struck me as a waste that I’d have to clone an entire HD image whenever I needed a fresh install of a machine. Why couldn’t I just use a single base image for each Virtual Machine, and have VirtualBox perform copy-on-write whenever it made changes? That way, only the changes to the base image would have to be stored separately for each clone, saving lots of disk space. Turns out it is possible to do just that! I had some problems with the steps in that article though, so here’s how I did it.

First, I created a new Virtual Machine and installed it like I always do. Once the VM was all set up, I shut it down, and cloned its harddisk:

$ VBoxManage clonehd ~/VirtualBox\ VMs/minimal.deb.local/minimal.deb.local.vdi ~/base.vdi

Next, I created a new Virtual Machine:

$ VBoxManage createvm --name "clone1" --ostype Debian_64 --register
Virtual machine 'clone1' is created and registered.
UUID: 1becc453-f4a9-44a8-a6c8-e43b80baf04d
Settings file: '/home/fboender/VirtualBox VMs/clone1/clone1.vbox'
$ VBoxManage modifyvm "clone1" --nic1 hostonly --hostonlyadapter1 "vboxnet0"
$ VBoxManage storagectl "clone1" --name "sata1" --add sata
$ VBoxManage storageattach "clone1" --storagectl "sata1" --port 0 --device 0 --type hdd --medium ~/base.vdi --mtype multiattach

The trick here lies in the --mtype multiattach option to the storageattach command. It tells VirtualBox that I’m going to attach this harddisk image to multiple different Virtual Machines. VirtualBox will then automatically do Copy-on-Write of all changes to a snapshot instead of to the base image. If I simply set the base.vdi harddisk image to immutable, as instructed by the article on Xaprb, I cannot attach it to multiple VirtualMachines. Using the --mtype multiattach also instructs VirtualBox to make persistant Copy-on-Writes. This means that, unlike the Xaprb article, your snapshot is not reset when starting the VirtualMachine. Thus you will not have to change the snapshots to autoreset=false.

You can start the VM now:

$ VBoxManage startvm "clone1"

If you want to create another VirtualMachine using the same base image, you can repeat the steps above, and replace every occurance of “clone1” with “clone2” or some other name. Then, when you attach the storage, you must not refer to the actual VDI file as it exists on disk, but you must simply refer to its name. So instead of specifying “--medium ~/base.vdi“, simply enter: “--medium base.vdi“. The full command thus becomes:

$ VBoxManage storageattach "clone2" --storagectl "sata1" --port 0 --device 0 --type hdd --medium base.vdi --mtype multiattach

We cannot refer directly to the image on disk, because it is already registered with VirtualBox. If you try to do this anyway, you will get an error such as:

VBoxManage: error: Cannot register the hard disk '/home/fboender/./base.vdi' {d3c861c1-6861-46c7-94a1-fd7a91987507} because a hard disk '/home/fboender/base.vdi' with UUID {d3c861c1-6861-46c7-94a1-fd7a91987507} already exists
VBoxManage: error: Details: code NS_ERROR_INVALID_ARG (0x80070057), component VirtualBox, interface IVirtualBox, callee nsISupports
Context: "OpenMedium(Bstr(pszFilenameOrUuid).raw(), enmDevType, AccessMode_ReadWrite, pMedium.asOutParam())" at line 209 of file VBoxManageDisk.cpp
VBoxManage: error: Invalid UUID or filename "./base.vdi"

If you create new VMs through the GUI, and attach the existing “base.vdi” harddisk during the Wizard, it will automatically attach that image in multiattach mode.

Like I said, all changes to the Virtual Machines are not written to the base.vdi image, but to a snapshot instead. The snapshots are very minimal in size:

$ ls -lh VirtualBox\ VMs/clone1/Snapshots/
total 26M
-rw------- 1 fboender fboender 26M 2011-09-24 10:30 {8f91d6ba-71bb-4618-8c82-5d8bd13fb045}.vdi

Only 26 Mb for a full-blown Debian install. Not bad.

MCPlayerEdit v0.20 released

Monday, September 12th, 2011

I’ve released a new version of my Minecraft Player/World Editor MCPlayerEdit v0.20. This release brings MCPlayerEdit up to date for the upcoming Minecraft Beta v1.8, The following features and modifications have been added:

  • Change player food (including god-mode)..
  • Switch between Creative and Survival.
  • Added Pine leaves, Birch leaves
  • Added (Double) Brick Slab, (Double) Stone Brick Slab, Stone With Silverfish, Stonebrick, Mossy Stonebrick (buggy), Cracked Stonebrick (buggy), Brick Stairs, Stone Brick Stairs
  • Added Huge Brown Mushroom (buggy), Huge Red Mushroom (buggy)
  • Added Iron Bars, Glass Pane, Vines, Fence Gate
  • Added Melon, Pumpkin Stem, Melon Stem, Melon Slice, Pumpkin Seeds, Melon Seeds, Raw Beef, Steak, Raw Chicken, Cooked Chicken, Rotten Flesh
  • Added Ender Pearl

You can get the new version Here.

PyWebkitGTK: ‘module’ object has no attribute ‘WebView’

Thursday, September 8th, 2011

If you’re working with PyWebkitGTK, and you get the following error:

Traceback (most recent call last):
  File "./webkit.py", line 7, in 
    import webkit
  File "/home/todsah/webkit.py", line 18, in 
    class BrowserPage(webkit.WebView):
AttributeError: 'module' object has no attribute 'WebView'

… make sure you haven’t named your script ‘webkit.py‘, and there is no other script with the same name in that directory. Also delete any webkit.pyc pic files. Do’h!

gCountDown v1.0: Systray countdown timer for Linux

Wednesday, September 7th, 2011

I’ve released v1.0 of the gCountDown program.

gCountDown is a very simple alarm countdown timer. It sits in your system tray where you can click it to set an alarm. Once the time runs out, you will be alerted.

This release adds the ability to play a sound when an alarm goes off pops up a menu on right-clicking the icon so you can quit the application and has some minor bugfixes. A Debian/Ubuntu package is now also available.

Stop Pingback/Trackback Spam on WordPress

Wednesday, September 7th, 2011

I guess the spammers finally found my blog, cause I’ve been getting a lot of pignback/trackback spam. I tried some anti-spam plugins, but none really worked, so I disabled pingbacks altogether. Here’s how:

First, log into wordpress as an admin. Go to Settings → Discussion, and uncheck the Allow link notifications from other blogs (pingbacks and trackbacks.) box.

That’s not all though, cause that just works for new articles. Old ones will still allow ping/trackbacks. As far as I could tell, WordPress doesn’t have a feature to disable those for older posts, so we’ll have to fiddle around in the database directly.

Connect to your MySQL server using the WordPress username and password. If you no longer remember those, you can find them in the wp-config.php file.

$ mysql -u USERNAME -p -h localhost
Password: PASSWORD
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1684228
Server version: 5.0.51a-24+lenny5 (Debian)

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql>

At the MySQL prompt, we must now switch to our WordPress database. Again, if you don’t remember the name, you can find it in the wp-config.php file. In my case, it is em_wordpress

mysql> USE em_wordpress;
Database changed

Finally, we update all posts and disable ping backs on them:

mysql> UPDATE wp_posts SET ping_status = 'closed';
Query OK, 1084 rows affected (0.10 sec)
Rows matched: 1084  Changed: 1084  Warnings: 0

There we go. No more ping- and trackback spam on old posts.

Creating simple Debian packages

Tuesday, September 6th, 2011

Here’s a quick way to create your own Debian package. This is merely a simple package which will not be included in the official Debian repositories, so we can ignore most of the Debian packaging guidelines.

First off, we need to create a directory which shall hold the contents of the package. In this case, a simple Python script called ‘myscript‘.

mkdir myscript

Next, we need to create the control file. This file contains some meta-data for the Debian package such as the name, description, etc. It lives in a special directory called ‘DEBIAN‘ in the root of the package.

mkdir myscript/DEBIAN
vi myscript/DEBIAN/control

We put the following contents in the control file

Package: myscript
Version: 0.1
Section: utils
Priority: optional
Architecture: all
Essential: no
Depends: python
Maintainer: Your Name 
Description: The short description of the script
 A longer description of the descript, possible
 spanning multiple lines.

Most of these fields are rather self-explanatory. You can find a list of valid Sections on the “List of Sections” page. Make sure to use the last part of the URL, not the actual title of the section. For scripts, the Architecture will almost always be ‘all‘. The Depends field tells the package installation software which other packages should be installed for this package to work correctly. Multiple packages can be specified by separating them with commas. See Chapter 7 of the Debian Policy Manual for details. The Description field is a single line containing a simple description of the package. The extended description can be placed under it, and may span multiple lines. Prefix each line with a single space.

Now we add the actual contents of the package to the myscript directory. We shall be installing the script in /usr/bin, so we create that directory and place our script in it.

mkdir -p myscript/usr/bin
cp ~/dev/myscript myscript/usr/bin/

Here’s the final directory layout of the myscript directory:

myscript
myscript/usr
myscript/usr/bin
myscript/usr/bin/myscript
myscript/DEBIAN
myscript/DEBIAN/control

The final step: actually creating the package!

fakeroot dpkg-deb --build myscript

fakeroot is a special tool that runs another program (in this case dpkg-deb) and fakes all filesystem ownerships as being 'root:root'. This is needed because the files in this Debian package need to be owned by root. The dpkg-deb --build command takes care of creating the package.

The myscript.deb Debian package can now be installed on your system using dpkg:

dpkg -i ./myscript.deb

Users of a GUI can usually right-click .deb files in their file managers and choose to install them from there. There are no special things to consider for de-installation of the package, unless the binary in your package creates files in non-temporary storage or users’ homedirs.

Please note again that this is not an official Debian package, and is missing many things required in well-made Debian packages ready for inclusion in the official Debian repositories.

Update::

If you want to include configuration files in the package, just add a etc/ directory in your package:

myscript
myscript/etc
myscript/etc/myscript
myscript/etc/myscript/myscript.conf

Normally when upgrading a package that contains a configuration file, Debian asks:

Configuration file `/etc/myscript/myscript.conf'
 ==> Modified (by you or by a script) since installation.
 ==> Package distributor has shipped an updated version.
   What would you like to do about it ?  Your options are:
    Y or I  : install the package maintainer's version
    N or O  : keep your currently-installed version
      D     : show the differences between the versions
      Z     : start a shell to examine the situation
 The default action is to keep your current version.
*** tvtgrab.conf (Y/I/N/O/D/Z) [default=N] ? 

To get the same thing for your package, you’ll have to let dpkg know which files are configuration files. You can do so by including a conffiles in the DEBIAN directory:

cat myscript/DEBIAN/conffiles
/etc/myscript/myscript.conf

Debian will now recognize your configuration files.

gCountDown: Systray countdown timer for Linux

Friday, August 26th, 2011

I needed an easy way to set timers on my desktop PC. All I really want is to set a countdown in hours, minutes and seconds, and have it alert me when that time has elapsed. I couldn’t find anything simple with some exceptions that wouldn’t compile (anymore) due to missing libs (which weren’t available in Xubuntu). So I whipped up my own.

You can download it from its home page, and here’s a screenshot of the thing:

Additionally, I was quite amazed at how easy it is to write GUI applications using just GTK in combination with Glade. Writing this tool took me only about an hour, with no previous knowledge. All it really required was creating a GTK Status Icon with an active signal handler. The handler pops up an interface put together in Glade by loading the gcountdown.glade file using gtk.glade.XML(). Connecting signals to the widgets is also super easy with signal_autoconnect().

Take a look at the source code. It’s only a measly 136 lines.

Redirect stdout and stderr to a logger in Python

Sunday, August 14th, 2011

I’m writing a daemon and needed a method of redirecting anything that gets sent to the standard out and standard error file descriptors (stdout and stderr) to a logging facility. I googled around a bit, but couldn’t find a satisfactory solution, so I came up with this.

import logging
import sys

class StreamToLogger(object):
   """
   Fake file-like stream object that redirects writes to a logger instance.
   """
   def __init__(self, logger, log_level=logging.INFO):
      self.logger = logger
      self.log_level = log_level
      self.linebuf = ''

   def write(self, buf):
      for line in buf.rstrip().splitlines():
         self.logger.log(self.log_level, line.rstrip())

logging.basicConfig(
   level=logging.DEBUG,
   format='%(asctime)s:%(levelname)s:%(name)s:%(message)s',
   filename="out.log",
   filemode='a'
)

stdout_logger = logging.getLogger('STDOUT')
sl = StreamToLogger(stdout_logger, logging.INFO)
sys.stdout = sl

stderr_logger = logging.getLogger('STDERR')
sl = StreamToLogger(stderr_logger, logging.ERROR)
sys.stderr = sl

print "Test to standard out"
raise Exception('Test to standard error')

We define a custom file-like object called StreamToLogger object which sends anything written to it to a logger instead. We then create two instances of that object and replace sys.stdout and sys.stderr with our fake file-like instances.

The output logfile looks like this:

2011-08-14 14:46:20,573:INFO:STDOUT:Test to standard out
2011-08-14 14:46:20,573:ERROR:STDERR:Traceback (most recent call last):
2011-08-14 14:46:20,574:ERROR:STDERR:  File "redirect.py", line 33, in 
2011-08-14 14:46:20,574:ERROR:STDERR:raise Exception('Test to standard error')
2011-08-14 14:46:20,574:ERROR:STDERR:Exception
2011-08-14 14:46:20,574:ERROR:STDERR::
2011-08-14 14:46:20,574:ERROR:STDERR:Test to standard error

(Finite-) State Machines in practice

Saturday, August 13th, 2011

(The lastest version of this article is always available in from this location).

1. Introduction

A (Finite-) State Machine is a method of determining output by reading input and switching the state of the machine (computer program). Depending on the type of State Machine (more on this later), the state of the machine is changed by looking at the current state, sometimes in combination with looking at the input.

(more…)

ePub versions of Writings now available

Monday, August 8th, 2011

I’ve generated ePub versions (for reading in ebook readers) of most of the Writings to the page.

The text of all posts on this blog, unless specificly mentioned otherwise, are licensed under this license.