In two of my very first blog posts, “Installing CentOS 6.2 with VirtualBox” and “Installing Gnome on Centos With Virtualbox”, I installed CentOS 6.2 using VirtualBox and later used that to create a basebox for Vagrant.

In this post I want to go back to the very first step of installing CentOS and automate it. Luckily there is a tool called VeeWee that does this and more.

While searching I also found a nice post on building Vagrant boxes with VeeWee.

Let’s start by installing VeeWee:

$ mkdir <some_where>/veewee_test
$ cd <some_where>/veewee_test
$ gem install veewee
$ vagrant basebox templates

The last command lists available templates. A template is a set of prepared configuration files so you don’t need to start from scratch. I wanted CentOS-6.2-x86_64-minimal. For CentOS 6.3 I would use the 6.2 templates and adjust them.

Before starting I created <some_where>/veewee_test/iso and put my ISO image in it (VeeWee would otherwise download it automatically).

Then I ran:

$ vagrant basebox define 'my_cool_basebox' 'CentOS-6.2-x86_64-minimal'
$ vagrant basebox build 'my_cool_basebox'
$ vagrant basebox validate 'my_cool_basebox'
$ vagrant basebox export 'my_cool_basebox'
$ vagrant box add 'my_cool_basebox' 'my_cool_basebox.box'
$ vagrant init 'my_cool_basebox'
$ vagrant up 
$ vagrant ssh

Basically, that’s all you need. As always, things didn’t go as smoothly as expected. When running vagrant basebox validate my_cool_basebox, I got the following in the last validation step:

[validation output retained as-is]

 Scenario: Checking shared folders              # /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/veewee-0.2.3/lib/veewee/../../validation/vagrant.feature:47
.  When I ssh to "127.0.0.1" with the following credentials: # veewee-0.2.3/validation/features/steps/ssh_steps.rb:56
   | username | password | keyfile       |
   | vagrant | vagrant | vagrant-private.key |
  And I run "mount|grep veewee-validation"         # veewee-0.2.3/validation/features/steps/ssh_steps.rb:98
   done!
    
  Then I should see "veewee-validation" in the output    # veewee-0.2.3/validation/features/steps/ssh_steps.rb:167
   expected: /veewee-validation/
      got: nil (using =~) (RSpec::Expectations::ExpectationNotMetError)

Failing Scenarios:
cucumber /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/veewee-0.2.3/lib/veewee/../../validation/vagrant.feature:47 # Scenario: Checking shared folders

7 scenarios (1 failed, 6 passed)
21 steps (1 failed, 20 passed)
0m1.176s

Something went wrong. I continued the steps after validation just to see what would happen and got another error when doing vagrant up:

$ vagrant up
[default] Importing base box 'my_cool_basebox'...
[default] No guest additions were detected on the base box for this VM! Guest
additions are required for forwarded ports, shared folders, host only
networking, and more. If SSH fails on this machine, please install
the guest additions and repackage the box to continue.

This is not an error message; everything may continue to work properly,
in which case you may ignore this message.
[default] Matching MAC address for NAT networking...
[default] Clearing any previously set forwarded ports...
[default] Fixed port collision for 22 => 2222. Now on port 2200.
[default] Forwarding ports...
[default] -- 22 => 2200 (adapter 1)
[default] Creating shared folders metadata...
[default] Clearing any previously set network interfaces...
[default] Booting VM...
[default] Waiting for VM to boot. This can take a few minutes.
[default] VM booted and ready for use!
[default] Mounting shared folders...
[default] -- v-root: /vagrant
The following SSH command responded with a non-zero exit status.
Vagrant assumes that this means the command failed!

mount -t vboxsf -o uid=`id -u vagrant`,gid=`id -g vagrant` v-root /vagrant

Logging into the box worked:

$ vagrant ssh
Last login: Tue Jul 24 21:21:33 2012 from 10.0.2.2
[vagrant@localhost ~]$

So it basically worked, but shared folders failed. The build output indicated a problem installing the guest additions:

Building the VirtualBox Guest Additions kernel modules
The headers for the current running kernel were not found. If the following
module compilation fails then this could be the reason.
The missing package can be probably installed with
yum install kernel-devel-2.6.32-220.el6.x86_64

Building the main Guest Additions module[FAILED]
(Look at /var/log/vboxadd-install.log to find out what went wrong)
Doing non-kernel setup of the Guest Additions[ OK ]
Installing the Window System drivers[FAILED]
(Could not find the X.Org or XFree86 Window System.)
dd: writing to `/tmp/clean': No space left on device
15493137+0 records in
15493136+0 records out
7932485632 bytes (7.9 GB) copied, 56.7727 s, 140 MB/s

In postinstall.sh I found the entry that tried to install the exact package name, but it failed with:

No package kernel-devel-2.6.32-220.el6.x86_64 available.

I logged into the Vagrant box and tried to install manually; the package was not found. Checking an old blog post showed I had used yum install kernel-devel previously, which worked now:

$ yum info kernel-devel
Loaded plugins: fastestmirror, presto
Loading mirror speeds from cached hostfile
 * base: ftp.belnet.be
 * extras: ftp.belnet.be
 * updates: mirror.nucleus.be
Available Packages
Name    : kernel-devel
Arch    : x86_64
Version   : 2.6.32
Release   : 279.2.1.el6
Size    : 7.6 M
Repo    : updates
Summary   : Development package for building kernel modules to match the kernel
URL     : http://www.kernel.org/
License   : GPLv2
Description : This package provides kernel headers and makefiles sufficient to build modules
      : against the kernel package.

I edited postinstall.sh to install kernel-devel instead of the full version string and ran vagrant basebox build 'my_cool_basebox' again, but got this error:

[error traceback retained]

$ vagrant basebox build 'my_cool_basebox'
Shutting down vm my_cool_basebox

Verifying the isofile CentOS-6.2-x86_64-minimal.iso is ok.
Removing step [1] snapshot as it is no more valid
/Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/virtualbox-0.9.2/lib/virtualbox/com/implementer/ffi.rb:106:in `call_and_check': Error in API call to save_settings: 2159738882 (VirtualBox::Exceptions::InvalidVMStateException)
	from /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/virtualbox-0.9.2/lib/virtualbox/com/implementer/ffi.rb:80:in `call_vtbl_function'
	from /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/virtualbox-0.9.2/lib/virtualbox/com/implementer/ffi.rb:61:in `call_function'
	from /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/virtualbox-0.9.2/lib/virtualbox/com/abstract_interface.rb:145:in `call_function'
	from /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/virtualbox-0.9.2/lib/virtualbox/com/abstract_interface.rb:62:in `save_settings'
	from /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/virtualbox-0.9.2/lib/virtualbox/vm.rb:422:in `with_open_session'
	from /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/virtualbox-0.9.2/lib/virtualbox/snapshot.rb:180:in `destroy'
	from /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/veewee-0.2.3/lib/veewee/session.rb:836:in `transaction'
	from /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/veewee-0.2.3/lib/veewee/session.rb:833:in `each'
	from /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/veewee-0.2.3/lib/veewee/session.rb:833:in `transaction'
	from /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/veewee-0.2.3/lib/veewee/session.rb:267:in `build'
	from /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/veewee-0.2.3/lib/veewee/command/basebox_build.rb:28:in `execute'
	from /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/veewee-0.2.3/lib/veewee/command/basebox.rb:36:in `execute'
	from /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/vagrant-1.0.3/lib/vagrant/cli.rb:42:in `execute'
	from /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/vagrant-1.0.3/lib/vagrant/environment.rb:167:in `cli'
	from /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/vagrant-1.0.3/bin/vagrant:43
	from /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/bin/vagrant:19:in `load'
	from /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/bin/vagrant:19
	from /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/bin/ruby_noexec_wrapper:14
muntwissm15146:veewee_test twiss1$ vagrant destroy
[default] VM not created. Moving on...

I had to manually delete the VM and related files using the VirtualBox GUI and then tried vagrant basebox build 'my_cool_basebox' again.

During the build I peeked at the console and saw:

---> Package kernel-devel.x86_64 0:2.6.32-279.2.1.el6 will be installed

So kernel-devel was being installed, but later the guest additions build failed with the familiar message:

Uncompressing VirtualBox 4.1.12 Guest Additions for Linux.........
VirtualBox Guest Additions installer
Removing existing VirtualBox DKMS kernel modules[ OK ]
Removing existing VirtualBox non-DKMS kernel modules[ OK ]
Building the VirtualBox Guest Additions kernel modules
The headers for the current running kernel were not found. If the following
module compilation fails then this could be the reason.
The missing package can be probably installed with
yum install kernel-devel-2.6.32-220.el6.x86_64

Building the main Guest Additions module[FAILED]
(Look at /var/log/vboxadd-install.log to find out what went wrong)
Doing non-kernel setup of the Guest Additions[ OK ]
Installing the Window System drivers[FAILED]
(Could not find the X.Org or XFree86 Window System.)
dd: writing to `/tmp/clean': No space left on device
15470233+0 records in
15470232+0 records out
7920758784 bytes (7.9 GB) copied, 47.686 s, 166 MB/s

I looked at /var/log/vboxadd-install.log inside the box:

/tmp/vbox.0/Makefile.include.header:97: *** Error: unable to find the sources of your current Linux kernel. Specify KERN_DIR=<directory> and run Make again. Stop.
Creating user for the Guest Additions.
Creating udev rule for the Guest Additions kernel module.

Then I checked versions:

$ yum list | grep kernel-devel
kernel-devel.x86_64      2.6.32-279.2.1.el6    updates
$ uname -r
2.6.32-220.el6.x86_64

The kernel version (uname -r) and the installed kernel-devel version didn’t match. I removed everything again:

$ vagrant destroy
$ vagrant box remove 'my_cool_basebox'
$ vagrant basebox destroy 'my_cool_basebox'

I reverted my changes in postinstall.sh and made one change in ks.cfg as described on this page: add /usr/bin/yum -y install kernel.

This time the build showed:

---> Package openssl-devel.x86_64 0:1.0.0-20.el6_2.5 will be installed

And installing the Guest Additions mostly succeeded:

Uncompressing VirtualBox 4.1.12 Guest Additions for Linux.........
VirtualBox Guest Additions installer
Removing existing VirtualBox DKMS kernel modules[ OK ]
Removing existing VirtualBox non-DKMS kernel modules[ OK ]
Building the VirtualBox Guest Additions kernel modules
Building the main Guest Additions module[ OK ]
Building the shared folder support module[ OK ]
Building the OpenGL support module[FAILED]
(Look at /var/log/vboxadd-install.log to find out what went wrong)
Doing non-kernel setup of the Guest Additions[ OK ]
Installing the Window System drivers[FAILED]
(Could not find the X.Org or XFree86 Window System.)

Validating the box took longer and returned many errors:

[validation output retained as-is]

$ vagrant basebox validate my_cool_basebox
Feature: vagrant box validation
 As a valid vagrant box
 I need to comply to a set of rules

 Scenario: Checking login                  # /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/veewee-0.2.3/lib/veewee/../../validation/vagrant.feature:5
.  When I ssh to "127.0.0.1" with the following credentials: # veewee-0.2.3/validation/features/steps/ssh_steps.rb:56
   | username | password |
   | vagrant | vagrant |
  And I run "whoami"                    # veewee-0.2.3/validation/features/steps/ssh_steps.rb:98
   undefined method `open_channel' for nil:NilClass (NoMethodError)
  Then I should see "vagrant" in the output         # veewee-0.2.3/validation/features/steps/ssh_steps.rb:167

 Scenario: Checking sudo                   # /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/veewee-0.2.3/lib/veewee/../../validation/vagrant.feature:12
.  When I ssh to "127.0.0.1" with the following credentials: # veewee-0.2.3/validation/features/steps/ssh_steps.rb:56
   | username | password |
   | vagrant | vagrant |
  And I run "sudo whoami"                  # veewee-0.2.3/validation/features/steps/ssh_steps.rb:98
   undefined method `open_channel' for nil:NilClass (NoMethodError)
  Then I should see "root" in the output          # veewee-0.2.3/validation/features/steps/ssh_steps.rb:167

 Scenario: Checking ruby                             # /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/veewee-0.2.3/lib/veewee/../../validation/vagrant.feature:19
.undefined method `open_channel' for nil:NilClass (NoMethodError)  When I ssh to "127.0.0.1" with the following credentials:           # veewee-0.2.3/validation/features/steps/ssh_steps.rb:56
   | username | password |
   | vagrant | vagrant |
  And I run ". /etc/profile ;ruby --version 2> /dev/null 1> /dev/null; echo $?" # veewee-0.2.3/validation/features/steps/ssh_steps.rb:98
   undefined method `open_channel' for nil:NilClass (NoMethodError)
  Then I should see "0" in the output                      # veewee-0.2.3/validation/features/steps/ssh_steps.rb:167

 Scenario: Checking gem                             # /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/veewee-0.2.3/lib/veewee/../../validation/vagrant.feature:26
.  When I ssh to "127.0.0.1" with the following credentials:           # veewee-0.2.3/validation/features/steps/ssh_steps.rb:56
   | username | password |
   | vagrant | vagrant |
  And I run ". /etc/profile; gem --version 2> /dev/null 1> /dev/null ; echo $?" # veewee-0.2.3/validation/features/steps/ssh_steps.rb:98
   undefined method `open_channel' for nil:NilClass (NoMethodError)
  Then I should see "0" in the output                      # veewee-0.2.3/validation/features/steps/ssh_steps.rb:167

 Scenario: Checking chef                                # /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/veewee-0.2.3/lib/veewee/../../validation/vagrant.feature:33
.  When I ssh to "127.0.0.1" with the following credentials:              # veewee-0.2.3/validation/features/steps/ssh_steps.rb:56
   | username | password |
   | vagrant | vagrant |
  And I run ". /etc/profile ;chef-client --version 2> /dev/null 1>/dev/null; echo $?" # veewee-0.2.3/validation/features/steps/ssh_steps.rb:98
   undefined method `open_channel' for nil:NilClass (NoMethodError)
  Then I should see "0" in the output                         # veewee-0.2.3/validation/features/steps/ssh_steps.rb:167

 Scenario: Checking puppet                             # /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/veewee-0.2.3/lib/veewee/../../validation/vagrant.feature:40
.  When I ssh to "127.0.0.1" with the following credentials:            # veewee-0.2.3/validation/features/steps/ssh_steps.rb:56
   | username | password |
   | vagrant | vagrant |
  And I run ". /etc/profile ; puppet --version 2> /dev/null 1>/dev/null; echo $?" # veewee-0.2.3/validation/features/steps/ssh_steps.rb:98
   undefined method `open_channel' for nil:NilClass (NoMethodError)
  Then I should see "0" in the output                       # veewee-0.2.3/validation/features/steps/ssh_steps.rb:167

 Scenario: Checking shared folders              # /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/veewee-0.2.3/lib/veewee/../../validation/vagrant.feature:47
.  When I ssh to "127.0.0.1" with the following credentials: # veewee-0.2.3/validation/features/steps/ssh_steps.rb:56
   | username | password | keyfile       |
   | vagrant | vagrant | vagrant-private.key |
  And I run "mount|grep veewee-validation"         # veewee-0.2.3/validation/features/steps/ssh_steps.rb:98
   undefined method `open_channel' for nil:NilClass (NoMethodError)
  Then I should see "veewee-validation" in the output    # veewee-0.2.3/validation/features/steps/ssh_steps.rb:167

Failing Scenarios:
cucumber /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/veewee-0.2.3/lib/veewee/../../validation/vagrant.feature:5 # Scenario: Checking login
cucumber /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/veewee-0.2.3/lib/veewee/../../validation/vagrant.feature:12 # Scenario: Checking sudo
cucumber /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/veewee-0.2.3/lib/veewee/../../validation/vagrant.feature:19 # Scenario: Checking ruby
cucumber /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/veewee-0.2.3/lib/veewee/../../validation/vagrant.feature:26 # Scenario: Checking gem
cucumber /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/veewee-0.2.3/lib/veewee/../../validation/vagrant.feature:33 # Scenario: Checking chef
cucumber /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/veewee-0.2.3/lib/veewee/../../validation/vagrant.feature:40 # Scenario: Checking puppet
cucumber /Users/twiss1/.rvm/gems/ruby-1.8.7-p358/gems/veewee-0.2.3/lib/veewee/../../validation/vagrant.feature:47 # Scenario: Checking shared folders

7 scenarios (7 failed)
21 steps (7 failed, 7 skipped, 7 passed)
9m20.915s

Interestingly, the VM console in the GUI was black and unresponsive. After resetting the VM via the VirtualBox GUI, validation succeeded:

7 scenarios (7 passed)
21 steps (21 passed)
0m1.015s

I exported the box. After vagrant up the same shared folder error appeared:

$ vagrant init 'my_cool_basebox'
`Vagrantfile` already exists in this directory. Remove it before
running `vagrant init`.
muntwissm15146:veewee_test twiss1$ vagrant up
[default] Importing base box 'my_cool_basebox'...
[default] No guest additions were detected on the base box for this VM! Guest
additions are required for forwarded ports, shared folders, host only
networking, and more. If SSH fails on this machine, please install
the guest additions and repackage the box to continue.

This is not an error message; everything may continue to work properly,
in which case you may ignore this message.
[default] Matching MAC address for NAT networking...
[default] Clearing any previously set forwarded ports...
[default] Forwarding ports...
[default] -- 22 => 2222 (adapter 1)
[default] Creating shared folders metadata...
[default] Clearing any previously set network interfaces...
[default] Booting VM...
[default] Waiting for VM to boot. This can take a few minutes.
[default] VM booted and ready for use!
[default] Mounting shared folders...
[default] -- v-root: /vagrant
The following SSH command responded with a non-zero exit status.
Vagrant assumes that this means the command failed!

mount -t vboxsf -o uid=`id -u vagrant`,gid=`id -g vagrant` v-root /vagrant

This didn’t make sense. I checked the earlier export step:

$ vagrant basebox export 'my_cool_basebox'
Vagrant requires the box to be shutdown, before it can export
Sudo also needs to work for user vagrant
Performing a clean shutdown now.
Executing command: sudo /sbin/halt -h -p
........
Machine my_cool_basebox is powered off cleanly
box my_cool_basebox.box already exists

Aha— it didn’t export a new box because the file already existed. I removed everything and checked the directory:

$ vagrant halt
$ vagrant destroy
$ vagrant box remove my_cool_basebox
$ vagrant basebox destroy my_cool_basebox
$ ls -al

Output:

total 1006480
drwxr-xr-x  8 twiss1 461641192    272 Jul 25 10:07 .
drwxr-xr-x 10 twiss1 461641192    340 Jul 24 17:27 ..
-rw-r--r--@ 1 twiss1 461641192    6148 Jul 24 17:30 .DS_Store
-rw-r--r--  1 twiss1 461641192     14 Jul 24 17:28 .rvmrc
-rw-r--r--  1 twiss1 461641192    3990 Jul 24 21:26 Vagrantfile
drwxr-xr-x  3 twiss1 461641192    102 Jul 24 18:05 definitions
drwxr-xr-x  4 twiss1 461641192    136 Jul 24 17:30 iso
-rw-r--r--  1 twiss1 461641192 515301376 Jul 24 21:24 my_cool_basebox.box

So I had been working with an old box file the whole time. To fix that:

$ rm my_cool_basebox.box
$ vagrant basebox build 'my_cool_basebox'

Validation again produced many errors and the VirtualBox GUI console was black. Resetting the VM again fixed it, and after that everything went smoothly: validation, export, and starting the box.

$ vagrant box add 'my_cool_basebox' 'my_cool_basebox.box'
[vagrant] Downloading with Vagrant::Downloaders::File...
[vagrant] Copying box to temporary location...
[vagrant] Extracting box...
[vagrant] Verifying box...
[vagrant] Cleaning up downloaded box...
muntwissm15146:veewee_test twiss1$ vagrant up
[default] Importing base box 'my_cool_basebox'...
[default] Matching MAC address for NAT networking...
[default] Clearing any previously set forwarded ports...
[default] Forwarding ports...
[default] -- 22 => 2222 (adapter 1)
[default] Creating shared folders metadata...
[default] Clearing any previously set network interfaces...
[default] Booting VM...
[default] Waiting for VM to boot. This can take a few minutes.
[default] VM booted and ready for use!
[default] Mounting shared folders...
[default] -- v-root: /vagrant

Logging in:

$ vagrant ssh
Last login: Wed Jul 25 09:07:03 2012 from 10.0.2.2

Finally!

But I still have some open questions:

  1. How do I remove or delete everything completely if I want to start the whole procedure again?
  2. Why is the VirtualBox console sometimes black and validation then fails?

Done for today!