Author Archives: btm

multipath broken on ubuntu intrepid

After getting open-iscsi going on Ubuntu Intrepid, the next horse was multipath. I did this before on debian etch, but this time it turned into quite an adventure.

First, multipath is simply broken in Intrepid and this doesn’t seem to be taken to be very important. udev’s arguments for /lib/udev/scsi_id changed somewhere around udev 114. Debian patched udev in udev=125-4, see bug 493075.

So I opened an ubuntu bug against udev, LP 306723. Ubuntu doesn’t want to go down this path (1, 2). So off to look at multipath-tools.

Package: multipath-tools
Maintainer: Ubuntu Core Developers

Last night I tried sending a message to the list, but it was moderated: “Post by non-member to a members-only list”. Today I jumped on #ubuntu-devel, but nobody took responsibility for the package or for that matter responded. So I joined the list, but once again was moderated because: “Post by non-developer to moderated list.” Well, maybe eventually my messages will get passed to the list, but I didn’t want to wait for someone else to say “not my problem”.

So I patched multipath-tools myself, and uploaded it as a PPA. It works for me. Getting a PPA setup was an ordeal of it’s own.

So until someone at Canonical cares about multipath being broken, use my package. It looks fixed in the multipath head, but it’s been sixteen months since the last release of multipath so I’m not crossing my fingers waiting for an upstream sync to fix the problem.

Setting up an Ubuntu launchpad PPA

Ubuntu Personal Package Archives (PPAs) let you upload source packages to be built. There’s help on PPAs which lists these requirements:

  1. learn Ubuntu packaging
  2. install dput – sudo apt-get install dput
  3. have imported your PGP key to your Launchpad account.
  4. become an Ubuntero (i.e. you must sign the Ubuntu Community Code of Conduct)

Becoming an Ubuntero lists:

  1. Log into your Launchpad account and click your name in the top-right corner of the page.
  2. Click Codes of Conduct in the Actions menu in the left-hand column of the screen.
  3. Following the on-screen instructions to download the most recent Code of Conduct, then sign it using gpg.
    Note: You must import your pgp signature before signing the Code of Conduct.

First, get a GPG key into launchpad. If you don’t have a gpg key, read this. Go to: https://launchpad.net/people/+me/+editpgpkeys

For whatever reason ‘gpg –list-keys’ doesn’t output column headers of any kind and making it more verbose with a ‘-v’ argument doesn’t do much useful.

$gpg --list-keys -v
gpg: using PGP trust model
/home/bryanm/.gnupg/pubring.gpg
-------------------------------
pub   1024D/874DF056 2008-04-09
uid                  Bryan McLellan 
sub   2048g/857DA9D9 2008-04-09

The GNU Privacy Handbook discusses what the fields are for. The hexadecimal number after the / is the key-id. You’ll want to upload the pub key to the keyserver like so:

$ gpg --keyserver keyserver.ubuntu.com --send-key 874DF056
gpg: sending key 874DF056 to hkp server keyserver.ubuntu.com

Then get the key fingerprint and put it in launchpad at https://launchpad.net/people/+me/+editpgpkeys:

$ gpg --fingerprint 857DA9D9
pub   1024D/874DF056 2008-04-09
      Key fingerprint = 5056 0995 E4F5 5338 70A6  A0FD FD58 20E3 874D F056
uid                  Bryan McLellan 
sub   2048g/857DA9D9 2008-04-09

If launchpad can match the fingerprint to a key in the ubuntu keyserver, it will email you an encrypted message. With a helpful, albeit late, link to a GPG howto. Since I use Gmail and Firefox, I use FireGPG to decrypt the message. Highlight the encrypted portion of the message then choose Tools -> FireGPG -> Decrypt. (Or, if you want a few moments you’ll get a “Decrypt this message” option near the bottom of the message next to reply/forward). Inside the decrypted message you’ll get a link to follow to confirm the key.

Once you have a key set up, follow this link to the Ubuntu Code of Conduct. You can also get there from https://launchpad.net/people/+me/, then scrolling down to the bottom where it says “Ubunteroo: No”. There’s a button after the ‘no’ that you can click on.

Read it. This entire post is triggered because of issues I’m having with multipath and udev and getting to the point where I’m going to have to fix it myself. It’s good to be reminded to calm down.

When you choose the ‘Sign It’ option you’ll download the text and sign the file, then upload the signed message. The directions in launchpad at this point are pretty clear. When finished, your user account in launchpad should now list you as an Ubunteroo.

Now go to: https://launchpad.net/people/+me/+activate-ppa
. Read and accept the terms of service to activate your PPA.

open-iscsi on ubuntu intrepid

Some time ago I started playing with iscsi on a Dell MD3000i on debian etch. I found etch was too far behind the times, and moved to lenny. The problem is needing to replace a Netgear / Infrant NAS in production that was having memory leak problems at the time. I resolved those by not running munin-node on it, and forgot about it for a while.

Recently I started having a ton of NFS problems with the beast. Apparently someone discovered they got better NFS performance with a single server thread than the default eight, and Netgear decided that it would be a good reason to make that the default. Time to pick back up on getting rid of that gear for anything meaningful. Would be a really nice place to mirror ubuntu archives I think.

Running back through the normal commands lead to an error though:

# iscsiadm -m discovery –type sendtargets –portal x.x.x.x -P 1
# iscsiadm -m node -l
# iscsiadm -m session
iscsiadm: Could not get host for sid 1.
iscsiadm: could not get host_no for session 6.
iscsiadm: could not find session info for session1
iscsiadm: Can not get list of active sessions (6)

Turns out it’s a bug, LP #289470. This appears to allow a single session but you can’t view it’s status. Upgrading to a newer version fixes both the session status and the ability to mount multiple sessions again.

I wanted to grab the new package out of jaunty in a sane way. Adding jaunty to the sources.list alone would make apt want to upgrade all of the packages. Downloading the deb from the website and installing it by hand with dpkg wouldn’t handle any possible dependencies.

/etc/apt/preferences:
Package: *
Pin: release a=jaunty
Pin-Priority: 450

Package: *
Pin: release a=intrepid-updates
Pin-Priority: 900

Package: *
Pin: release a=intrepid-proposed
Pin-Priority: 400

Then I ran:

# apt-get install -t jaunty open-iscsi

Which failed with a few errors:

# snip
Setting up open-iscsi (2.0.870.1-0ubuntu1) ...
Installing new version of config file /etc/init.d/open-iscsi ...
Installing new version of config file /etc/iscsi/iscsid.conf ...
update-rc.d: /etc/init.d/remove: file does not exist
 * Starting iSCSI initiator service iscsid  [fail]
 * Setting up iSCSI targets
       iscsiadm: No records found!
       [ OK ]
invoke-rc.d: initscript open-iscsi, action "start" failed.
dpkg: error processing open-iscsi (--configure):
 subprocess post-installation script returned error exit status 1
Errors were encountered while processing:
 open-iscsi
E: Sub-process /usr/bin/dpkg returned an error code (1)

There’s a couple bugs in there. One is a failure to correctly run ‘update-rc.d -f open-iscsi remove’, LP #306678, the other is that the init script doesn’t work so hot in 2.0.865-1ubuntu4, LP #181188 (init script), LP #306693 (upgrade).

After this, the inital commands worked as expected.

Edit to add that automatic login works with:

iscsiadm -m node -T TARGET --op update -n node.startup -v automatic

db_recover for slapd on ubuntu intrepid

First find out what version of bdb (Berkely DB) slapd is using:
apt-cache show slapd
[snip]
Depends: libc6 (>= 2.4), libdb4.2, libgcrypt11 (>= 1.4.0), libgnutls26 (>= 2.4.0-0), libldap-2.4-2 (= 2.4.11-0ubuntu6), libltdl7 (>= 2.2.4), libperl5.10 (>= 5.10.0), libsasl2-2, libslp1, libtasn1-3 (>= 0.3.4), libwrap0 (>= 7.6-4~), unixodbc (>= 2.2.11-1), zlib1g (>= 1:1.1.4), coreutils (>= 4.5.1-1), psmisc, perl (>> 5.8.0) | libmime-base64-perl, adduser
[snip]

Then install the appropriate version of dbX.Y-util:
apt-get install db4.2-util
The utilities like db_recover and db_verify are actually named db4.2_verify and db4.2_recover. You can see a list with:
dpkg -L db4.2-util

rubygems server on Ubuntu Intrepid 8.10

Serving gem’s locally isn’t too hard these days.

sudo apt-get install rubygems

Populate /etc/init.d/gem-server with:

#!/bin/sh

### BEGIN INIT INFO
# Provides:          gem-server
# Required-Start:    $network $local_fs $remote_fs
# Required-Stop:     $network $local_fs $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: start local gem server
### END INIT INFO

PATH=/sbin:/bin:/usr/sbin:/usr/bin

DAEMON="/usr/bin/gem"
OPTIONS="server --daemon"

# clear conflicting settings from the environment
unset TMPDIR

# See if the daemon is there
test -x $DAEMON || exit 0

. /lib/lsb/init-functions

case "$1" in
	start)
    PID=$(ps ax -o pid,command | grep "gem server" | grep daemon | awk '{print $1}')
    if test -n "$PID" ; then
		  log_daemon_msg "Ruby Gem server already running : PID $PID" "gem-server"
    else
		  log_daemon_msg "Starting the Ruby Gem server" "gem-server"
		  $DAEMON $OPTIONS
    fi

		log_end_msg $?
		;;

	stop)
    PID=$(ps ax -o pid,command | grep "gem server" | grep daemon | awk '{print $1}')
    if test -n "$PID" ; then
	  	log_daemon_msg "Stopping the Ruby Gem server" "gem-server"
      kill $PID
    else
	  	log_daemon_msg "Ruby Gem server not running" "gem-server"
    fi

		log_end_msg $?
		;;

	restart|force-reload)
		$0 stop && sleep 2 && $0 start
		;;

	*)
		echo "Usage: /etc/init.d/gem-server {start|stop|restart|force-reload}"
		exit 1
		;;
esac

Then use the initscript to start it. If you want to serve gem’s out of a directory other than the default /var/lib/gems/1.8, then add “-d DIRECTORY” to the OPTIONS variable in the init script. Then install locally sourced gem’s with:

sudo gem install --source http://hostname:8808 gem_package

perl: warning: Setting locale failed.

I’ve seen this perl error for a while and ignored it but it was stopping postgres from starting. This is on Ubuntu Intrepid 8.10, specifically a JeOS install made by vm-builder, which is the key.

$ sudo /etc/init.d/postgresql-8.3 start
 * Starting PostgreSQL 8.3 database server
 * perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
	LANGUAGE = (unset),
	LC_ALL = (unset),
	LANG = "en_US.UTF-8"
    are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
The PostgreSQL server failed to start. Please check the log output:
FATAL:  invalid value for parameter "lc_messages": "en_US.UTF-8"

The solution:

sudo apt-get install language-pack-en

Configuring ssl requests with SubjectAltName with openssl

Subject Alternative Names are a X509 Version 3 (RFC 2459) extension to allow an SSL certificate to specify multiple names that the certificate should match. SubjectAltName can contain email addresses, IP addresses, regular DNS host names, etc. There’s a clean enough list of browser compatibility here.

Changing /etc/ssl/openssl.cnf isn’t too hard. Although most the documentation is hard to grasp, especially if you’re only trying to make requests. From this, I developed these changes to a standard config provided by debian/ubuntu. Edit openssl.cnf and uncomment “x509_extensions = v3_ca” in the [ req ] section.

Annoyingly, nobody appears to have figured out how to get openssl to ask you for this value.

I thought I was clever putting ‘subjectAltName=email:move’ in the v3_req section, which would put the email address you type in the subjectAltName field. I’d put in “foo@example.org, DNS:www1.example.org, DNS:www2.example.org” in the email field when ‘openssl req’ asked for it. Visually it worked, but the browsers didn’t like it. This appears to be functionality to deal with part 4.1.2.6 of the RFC, moving email address into subjectAltName.

I thought about writing a script that would copy openssl.cnf, ask me for the value of SubjectAltName, run sed against it, then start openssl. It would appear seamless, but of course be a hack.

A better answer lies here, you can configure openssl to use environment variables. At the top of openssl.cnf under where it set’s HOME=”…” I added

SAN="email:noc@example.com"

And in [ v3_req ] I added:

subjectAltName=${ENV::SAN}

So if you run openssl like this:

SAN="DNS:www.1example.org, DNS:www2.example.org" \
  openssl req -new -key www.example.org.key -out www.example.org.csr

It will fill in subjectAltName with the contents of the SAN variable, otherwise will fill it with the contents specified at the top of the file. There’s no way to use conditionals (I assume).If you just leave it blank, or leave it out altogether, you get these errors:

Unable to load config info from /usr/lib/ssl/openssl.cnf

and respectively,

Error Loading request extension section v3_req
27687:error:2206D06C:X509 V3 routines:X509V3_PARSE_LIST:invalid null name:v3_utl.c:327:
27687:error:22097069:X509 V3 routines:DO_EXT_NCONF:invalid extension string:v3_conf.c:139:name=subjectAltName,section=
27687:error:22098080:X509 V3 routines:X509V3_EXT_nconf:error in extension:v3_conf.c:93:name=subjectAltName, value=

Adding hosts to virt-manager in Ubuntu Intrepid

I have a nice ssh-key system setup for connecting to KVM hosts, and through permission settings on:

/var/run/libvirt/libvirt-sock
/var/run/libvirt/libvirt-sock-ro

I managed access to the guests. Recently upgrading to intrepid brought along a new version of virt-manager, that whenever you add a QEMU+SSH libvirt instance in, it forcibly adds ‘root@’ to the URI where before the username was left out. If you add a URI like ‘bryanm@host’ it becomes ‘root@bryanm@host’.

Use gconf-editor, under apps -> virt-manager -> connections add new URI’s by hand rather than using the virt-manager interface as a workaround.

edit: launchpad bug #294965, Red Hat bug #470416.

Request-tracker: Could not load a valid user

A while back I moved my rt instance, mostly debianized it, and stabilized on RT 3.6.7 (decompressed on top of the 3.6.5 deb). I recently found that external emails were no longer creating new accounts.

It’s possible that I fixed the problem along the way and that my email account I was testing from was sending my ‘RealName’ and we were matching on that.

[Thu Nov  6 01:54:45 2008] [error]: RT could not load a valid user, and RT's configuration does not allow
for the creation of a new user for your email. (/usr/share/request-tracker3.6/lib/RT/Interface/Email.pm:243)
[Thu Nov  6 01:54:45 2008] [error]: Could not record email: Could not load a valid user (/usr/share/request-tracker3.6/html/REST/1.0/NoAuth/mail-gateway:75)
[Thu Nov  6 02:09:46 2008] [crit]: User creation failed in mailgateway: Name in use (/usr/share/request-tracker3.6/lib/RT/Interface/Email.pm:243)
[Thu Nov  6 02:09:46 2008] [crit]: User  'test@example.org' could not be loaded in the mail gateway (/usr/share/request-tracker3.6/lib/RT/Interface/Email.pm:243)
[Thu Nov  6 02:09:47 2008] [err]: Couldn't load  from the users database. (/usr/share/request-tracker3.6/lib/RT/CurrentUser.pm:147)
[Thu Nov  6 02:09:47 2008] [err]: Couldn't load  from the users database. (/usr/share/request-tracker3.6/lib/RT/CurrentUser.pm:147)
[Thu Nov  6 02:09:47 2008] [error]: Couldn't create ticket from message with commands, fallback to standard mailgate.

Error: No permission to create tickets in the queue 'lposupport' (/usr/share/perl5/RT/Interface/Email/Filter/TakeAction.pm:504)
[Thu Nov  6 02:09:47 2008] [crit]: Couldn't create ticket from message with commands, fallback to standard mailgate.

Error: No permission to create tickets in the queue 'lposupport' (/usr/share/request-tracker3.6/lib/RT/Interface/Email.pm:243)
[Thu Nov  6 02:09:47 2008] [error]: RT could not load a valid user, and RT's configuration does not allow
for the creation of a new user for this email (test@example.org).

You might need to grant 'Everyone' the right 'CreateTicket' for the
queue lposupport. (/usr/share/request-tracker3.6/lib/RT/Interface/Email.pm:243)

I had to reconfigure my configs during the move. Of course I checked the queue permissions, then expected that $AutoCreateNonExternalUsers was not set to 1. Neither was the solution. I installed the latest versions of RT and ExternalAuth from source. Still not working. The trick? I found a recommended change to the LDAP attr_match_list, reducing it to just Name and EmailAddress. This makes sense from the newer logs I saw in debugging.

Upgrading also led me to a new error about d_filter not being set. I used the following, taken from this thread:

'd_filter' => '(userAccountControl:1.2.840.113556.1.4.803:=2)',

And the logs:

[Thu Nov  6 05:02:00 2008] [debug]: Going to create user with address 'test@example.org' (/opt/rt3/bin/../lib/RT/Interface/Email/Auth/MailFrom.pm:94)
[Thu Nov  6 05:02:00 2008] [debug]: RT::User::CanonicalizeUserInfo called by RT::User /opt/rt3/bin/../lib/RT/User_Overlay.pm 128 with: Comments: Autocreated
on ticket submission, Disabled: 0, EmailAddress: test@example.org, Name: info@imob.org, Password: , Privileged: 0, RealName: Bryan McLellan (/usr/share/perl5/RT
/User_Vendor.pm:400)
[Thu Nov  6 05:02:00 2008] [debug]: Attempting to get user info using this external service: My_LDAP (/usr/share/perl5/RT/User_Vendor.pm:408)
[Thu Nov  6 05:02:00 2008] [debug]: Attempting to use this canonicalization key: Name (/usr/share/perl5/RT/User_Vendor.pm:417)
[Thu Nov  6 05:02:01 2008] [debug]: LDAP Search ===  Base: dc=corp,dc=example,dc=org == Filter: (&(objectclass=user)(sAMAccountName=test@example.org)) == Attrs
: l,cn,st,mail,sAMAccountName,co,streetAddress,postalCode,telephoneNumber,sAMAccountName,physicalDeliveryOfficeName,sAMAccountName (/usr/share/perl5/RT/User_
Vendor.pm:538)
[Thu Nov  6 05:02:01 2008] [info]: RT::User::LookupExternalUserInfo : Returning:  EmailAddress: , Name: , RealName:  (/usr/share/perl5/RT/User_Vendor.pm:703)
[Thu Nov  6 05:02:01 2008] [debug]: RT::User::LookupExternalUserInfo No user was found this time (/usr/share/perl5/RT/User_Vendor.pm:706)
[Thu Nov  6 05:02:01 2008] [debug]: Attempting to use this canonicalization key: EmailAddress (/usr/share/perl5/RT/User_Vendor.pm:417)
[Thu Nov  6 05:02:02 2008] [debug]: LDAP Search ===  Base: dc=corp,dc=example,dc=org == Filter: (&(objectclass=user)(mail=test@example.org)) == Attrs: l,cn,st,mail,sAMAccountName,co,streetAddress,postalCode,telephoneNumber,sAMAccountName,physicalDeliveryOfficeName,sAMAccountName (/usr/share/perl5/RT/User_Vendor.pm:538)
[Thu Nov  6 05:02:02 2008] [info]: RT::User::LookupExternalUserInfo : Returning:  EmailAddress: , Name: , RealName:  (/usr/share/perl5/RT/User_Vendor.pm:703)
[Thu Nov  6 05:02:02 2008] [debug]: RT::User::LookupExternalUserInfo No user was found this time (/usr/share/perl5/RT/User_Vendor.pm:706)
[Thu Nov  6 05:02:02 2008] [debug]: Attempting to use this canonicalization key: RealName (/usr/share/perl5/RT/User_Vendor.pm:417)
[Thu Nov  6 05:02:03 2008] [debug]: LDAP Search ===  Base: dc=corp,dc=example,dc=org == Filter: (&(objectclass=user)(cn=Bryan McLellan)) == Attrs: l,cn,st,mail,sAMAccountName,co,streetAddress,postalCode,telephoneNumber,sAMAccountName,physicalDeliveryOfficeName,sAMAccountName (/usr/share/perl5/RT/User_Vendor.pm:538)
[Thu Nov  6 05:02:03 2008] [info]: RT::User::LookupExternalUserInfo : Returning:  Address1: , City: , Country: , EmailAddress: bryanm@widemile.com, ExternalAuthId: bryanm, Gecos: bryanm, Name: bryanm, Organization: , RealName: Bryan Mclellan, State: , WorkPhone: 206-985-7171 x117, Zip:  (/usr/share/perl5/RT/User_Vendor.pm:703)
[Thu Nov  6 05:02:03 2008] [info]: RT::User::CanonicalizeUserInfo returning Address1: , City: , Comments: Autocreated on ticket submission, Country: , Disabled: 0, EmailAddress: bryanm@widemile.com, ExternalAuthId: bryanm, Gecos: bryanm, Name: bryanm, Organization: , Password: , Privileged: 0, RealName: Bryan Mclellan, State: , WorkPhone: 206-985-7171 x117, Zip:  (/usr/share/perl5/RT/User_Vendor.pm:444)
[Thu Nov  6 05:02:03 2008] [crit]: User creation failed in mailgateway: Name in use (/opt/rt3/bin/../lib/RT/Interface/Email.pm:244)
[Thu Nov  6 05:02:04 2008] [warning]: Couldn't load user 'test@example.org'.giving up (/opt/rt3/bin/../lib/RT/Interface/Email.pm:806)
[Thu Nov  6 05:02:04 2008] [crit]: User  'info@imob.org' could not be loaded in the mail gateway (/opt/rt3/bin/../lib/RT/Interface/Email.pm:244)
[Thu Nov  6 05:02:04 2008] [error]: RT could not load a valid user, and RT's configuration does not allow
for the creation of a new user for this email (test@example.org).

You might need to grant 'Everyone' the right 'CreateTicket' for the
queue lposupport. (/opt/rt3/bin/../lib/RT/Interface/Email.pm:244)

How I dealt with KVM host identification

Recently I started researching how a KVM guest could tell who it’s host is. I dug into the KVM code and found in r77 there’s new functionality to pass -uuid on the command line on the host and access it from the qemu monitor. KVM-78 should have bios modifications such that ‘dmidecode’ will return this uuid if passed as well. As noted in that last link, libvirt doesn’t support that yet. Although it’s a trivial change I can’t really wait for all this stuff, nor do I want to take the time to package it.

The existing vmport code in qemu, best I can tell, is used mostly for some vmmouse stuff. I can’t find anywhere than anyone actually uses it. I don’t want to write code to start poking around memory holes, so I threw out the idea of prodding around there.

In the end, I used my infrastructure, again. kvm/libvirt hosts report their guests to iclassify based on hostname:

#!/usr/bin/ruby -w
# This is an iclassify script for updating a libvirt (KVM) host with the list of guests
# Until KVM guests can access their UUID, this will rely on hostname being unique
# 2008-10-28 -- Bryan McLellan 

def update_guests
  local_guests = Array.new
  server_guests = Array.new

  # Get the list of current guest hostnames
  %x[virsh list --all 2>/dev/null].each { |line|

    # ignore header lines, match lines that start with a number ID, grab hostname from second column
    if row = line.match(/^\s+\d+\s+(\S+)/)
      local_guests << row[1]
    end
  }

  unless local_guests.empty?
	  # update the array, and try to give it a break if it's the same
	  server_guests = attrib?("guest-hostname")
	  replace_attrib("guest-hostname", local_guests) unless server_guests == local_guests
  end

end 

if tag?("kvm")
  update_guests
end

Then I could modify my ruby script that displays virt server status, originally written when I was using just vmware servers, to also show kvm/libvirt hosts:

client = IClassify::Client.new(config[:server], config[:user], config[:passwd])

vmwarehosts = client.search('(tag:vmware-server OR tag:kvm) AND NOT tag:workstation', [])

vmwarehosts.sort_by { |node| node.description }.each do |node|

  puts node.description
  puts "\tmemory free/total: " + node.attrib?('memoryfree').gsub!(/[^0-9.]/,"") + "/" + node.attrib?('memorysize') \
    + "\tswap free/total: " + node.attrib?('swapfree').gsub!(/[^0-9.]/,"") + "/" + node.attrib?('swapsize')
  print "\tguests: "

  # remember that node.description and friends aren't always clean
  guests = client.search("vmwarehost:#{node.attrib?('hostname')}", [])
  guests.sort_by { |node| node.description }.each do |guest|
    print "#{guest.attrib?('hostname')} "

  end
  if node.attrib?("guest-hostname")
    node.attrib?("guest-hostname").each { |guest| print "#{guest} " }
  end
  puts "\n"
end

And I guess that works for me for now. Later it’ll be nice to use the host and guests’s real UUID as the iclassify uuid. That’s a project for another day.

Mounting KVM qcow2 qemu disk images

qcow2 images are not flat files, see qemu-img(1). KVM ships with qemu-nbd, which lets you use the NBD protocol to share the disk image on the network.

First, for partition nbd partition support you need to be running kernel 2.6.26 (commit, changelog) or greater. For ubuntu users, that means it’s time to upgrade to intrepid ibex. Load the nbd module with:

sudo modprobe nbd max_part=8

If you leave off the max_part attribute, partitions are not supported and you’ll be able to access the disk, but not have device nodes for any of the partitions. Running

sudo qemu-nbd root.qcow2

will bind to all interfaces (0.0.0.0) and share the disk on the default port (1024). It’s important to note that the nbd kernel module produces /dev/nbd0 while the nbd-client man page recommends /dev/nb0 in it’s examples. The error message isn’t so clear, see lp:290076.

# nbd-client localhost 1024 /dev/nb0
Error: Can not open NBD: No such file or directory

This can all be reduced in steps using the ‘–connect’ option of qemu-nbd, like this:

sudo qemu-nbd --connect=/dev/nbd0 root.qcow2

At which point you can view the disk partitions:

sudo fdisk /dev/nbd0

or mount a disk, such as

mount /dev/nbd0p1 /mnt

KVM: Who’s your daddy?

I guess I never blogged about the VMWare solution to this. I wanted a node to detect if it was a VMWare guest, and if it was, to register the name of it’s host as an iClassify attribute. Originally the solution to know what VMWare server host a guest was on was to put it in it’s hostname when you created the node, like ‘vm03-somecrap’. That just sucked. With the information in iclassify, it was easy to write a ruby script to give me a list of hosts and their guests. And that worked alright. I’d run a script on the host against each guest something like:

#!/bin/bash
VMWARECMD=/usr/bin/vmware-cmd

# vmware config files returned by 'vmware-cmd -l' often have spaces, by default bash for treats spaces as a field seperator
IFS=$'\n'

if [ "$1" == "" ]; then
  echo $0: requires vmware host hostname as an argument
  exit 1
fi

for config in `$VMWARECMD -l` ; do
  $VMWARECMD "$config" setguestinfo host $1
done

Which one could then read on the guest if the vmware-guest tools where installed with:

/usr/sbin/vmware-guestd --cmd 'info-get guestinfo.host'

Finding the syntax for vmware-guestd took forever. I don’t know why I didn’t blog that.

I want to do something similar for KVM. I use libvirt, so the first step was looking at the configuration file options for libvirt and the command line options for qemu to see if anything nice matched up. I played a bit with the serial pipe option, which you can use even though it’s not listed on the libvirt page because I saw it in the source, but I couldn’t get it to do much. I had thought about having a daemon return hostname or such to the FIFO whenever queried with a \n or something.

I figured I could find something to pass to the kernel cmdline in an append option, but I really don’t want to have to template the libvirt template files just to stuff a hostname in there.

I really want something I can pass to SMBIOS that I can pull with dmidecode on the guest. I started digging into the LinuxBIOS/coreboot code that comes with the ubuntu kvm source package and in bios/rombios32.c, I found a function called uuid_probe that sets the uuid variable. I just posted to the coreboot mailing list asking about it. #qemu on irc.freenode.net just got me this when I asked about it:

15:29 < aliguori> in linux bios?  it's stuff that shouldn't be there

Googling for 0x564d5868 revealed it’s indicative of the VMWare backdoor stuff. This lead me to what appears to be some emulation of this called VMPort in QEMU. I have no idea yet what it does, if it ever worked, and thus if I can interact with it yet.

Running multiple nrpe binaries on debian/ubuntu

Silly init scripts. I have two nrpe binaries running on the nagios server, one for it to check the normal things like CPU, disk, etc, and one for an external nagios server to connect and make sure that nagios is running. For basic security reasons, these use different nrpe config files with a seperate set of plugins.

But the init script has to be modified so they don’t kill each other. I made a link from ‘/usr/sbin/nrpe-ext’ to ‘/usr/sbin/nrpe’ then copied ‘/etc/init.d/nagios-nrpe-server’ to ‘/etc/init.d/nagios-nrpe-server-ext’

Make the following modification to both so they don’t kill each other:

52c52
< 	start-stop-daemon --stop --quiet --oknodo --exec $DAEMON
---
> 	start-stop-daemon --stop --quiet --oknodo --name $NAME
57c57
< 	start-stop-daemon --stop --signal HUP --quiet --exec $DAEMON
---
> 	start-stop-daemon --stop --signal HUP --quiet --name $NAME

Then make these changes to nagios-nrpe-server-ext so it starts a unique process:

5c5
< # Provides:          nagios-nrpe-server
---
> # Provides:          nagios-nrpe-server-ext
17,20c17,20
< DAEMON=/usr/sbin/nrpe
< NAME=nagios-nrpe
< DESC=nagios-nrpe
< CONFIG=/etc/nagios/nrpe.cfg
---
> DAEMON=/usr/sbin/nrpe-ext
> NAME=nrpe-ext
> DESC=nagios-nrpe-ext
> CONFIG=/etc/nagios/nrpe-ext.cfg

And update nagios-nrpe-server so it works with our new invocation of start-stop-daemon:

18c18
< NAME=nagios-nrpe
---
> NAME=nrpe

KVM Virtio network performance

I’ve switched my production infrastructure from VMWare server to KVM and libvirt recently. I’ve been working on moving from ubuntu-vm-builder to python-vm-builder (now just vm-builder). Nick Barcet made a tree while we were talking about the lack of a bridging option that adds a ‘–net-virtio’ option. So I started using virtio on a new libvirt guest for networking.

On the guest, lspci will show this device when using virtio:

00:03.0 Ethernet controller: Qumranet, Inc. Unknown device 1000

From the host, in simple tests (‘ping -c100 guestname’) aren’t all that different and are pretty statistically useless.

with virtio:

100 packets transmitted, 100 received, 0% packet loss, time 99012ms
rtt min/avg/max/mdev = 0.113/0.387/0.821/0.065 ms

without virtio:

100 packets transmitted, 100 received, 0% packet loss, time 99007ms
rtt min/avg/max/mdev = 0.143/0.200/0.307/0.032 ms

Running iperf with the server on the guest and the client on the host produces:

with virtio:

------------------------------------------------------------
Client connecting to virtio, TCP port 5001
TCP window size: 16.0 KByte (default)
------------------------------------------------------------
[  3] local 10.0.1.172 port 54168 connected with 10.0.1.33 port 5001
[  3]  0.0-10.0 sec  1.34 GBytes  1.15 Gbits/sec

without virtio:

------------------------------------------------------------
Client connecting to novirtio, TCP port 5001
TCP window size: 16.0 KByte (default)
------------------------------------------------------------
[  3] local 10.0.1.172 port 34414 connected with 10.0.1.13 port 5001
[  3]  0.0-10.0 sec    375 MBytes    315 Mbits/sec

So that’s better. Both guests are Ubuntu 8.04.1 running 2.6.24-19-server SMP x86_64 with 1 vcpu and 768MB of RAM. Host has 8GB of RAM, same kernel and distro, with 8 CPUs (Xeon’s with HT and all that crap).

Access is denied when saving files from Office 2007 on Vista to a redirected documents folder

Client is Office 2007 on Vista, saving to ‘Document’s which is redirected folder on a Server 2003 R2 file share. Whenever saving files you get “access is denied” and it creates a 0KB file, but you can copy the file there in explorer no problem. As a side note, offline files and folders is also enabled.

It’s related to SMB2, which is Vista + Server 2008 tricks. See KB 296264 about ensure that opportunistic locks are enabled in the registery on the server.