Tuesday, May 13, 2014

Surfacing

Where am I? Coming up for air!

I have reams of notes relating to things I've learned on the job that I started last year. They need to be edited and posted but I haven't been inclined to do that just yet.

I will say that I'm having a great time.  I'm back to writing Python code after drifting away from it for a few years. I have also returned to relational database technology after nearly 15 years of needlessly avoiding it. This time I'm working with MySQL instead of Oracle.

Lots of interesting things in the pipeline.  Web technologies, system performance and scalability, NoSQL, Amazon Web Services...  the list goes on.

Wednesday, December 18, 2013

Monday, August 12, 2013

SPICE: Improved UX On CentOS 5 KVM Guest

As you probably know, KVM is a great way to run virtual machines on a Linux host.  It may not be as refined as VMware Workstation, but it's very close.  And it's open source.

Not all of guest VM's need to provide a graphical desktop like Gnome.   But when they do, SPICE is one of the protocols you can use to access it.  Like RDP, PCoIP, and VNC, SPICE is a remote desktop access protocol.  I use the term "access" instead of "display" because all of these protocols provide more than just a display output channel.  They also provide input channels for serial devices such as keyboards and mice.

Electrical engineers: don't confuse the SPICE protocol with the SPICE circuit emulator.

When the guest is configured correctly, the serial channels provide seamless mouse traversal from the host to the guest, and allows cut-paste between the two.  Without these channels, you can't paste text into the guest from the host and you have to use keyboard escape sequences to release the mouse from the guest.

In short, it's fairly annoying if you have a need to switch quickly between the two environments.

When running newer Fedora, CentOS, and Red Hat guests on a newer host, SPICE input channels just work.  But if you need to run CentOS/RHEL 5.x, it doesn't.  Not "out of the box", anyway.  So here's how.

I'm working with CentOS 5.9.  After installing the base OS on the guest, follow these steps.
  1. Install the Feodra EPEL repo configuration.  (Note that the domain name may be different than what you see here.)

    rpm -i http://mirror.nexcess.net/epel/5/i386/epel-release-5-4.noarch.rpm
  2. Install the SPICE vdagent.

    yum install -y spice-vdagent

  3. Verify that the vdagent is enabled to start at boot time.

    chkconfig --list|grep spice
My host is running Fedora 17.  If you're using virt-manager to access your desktops, then you don't really need the SPICE client (it's built in to virt-manager).  But if you just want to connect with the 'spicec' command, then yum install spice-client

If you're accessing the desktop from the network, you need to make sure that SPICE is configured to listen on the right network interface.  By default, it only listens on 127.0.0.1.  In a production environment, your choice will depend on security requirements.  In a lab environment, I usually set this to 0.0.0.0 so I can get to the desktop from anywhere.

Things should start working at this point.  When I first got everything configured, it didn't.  I'm not sure what fixed it (logout?  screen save?) but it's OK now.  The mouse cursor is a little clunky compared to the experience on newer guests, but cut/paste is OK and I don't have to use a magic key combo to release the mouse.



Monday, August 5, 2013

Making ISO Files and Burning CD's

Need to create an ISO image of some directory contents and burn it to a CD or DVD? Here's how I do it on Fedora/RHEL/CentOS.

In (overly) simplistic script form, the making of an ISO9660 image goes like this.

#!/bin/bash
contents="path/to/files"
isodir="path/to/empty/dir"
isoimage="my-image.iso"

mkdir $isodir
cp -a $contents $isodir

mkisofs -R -J -T \
    -V "VOLUME_ID" \
    -A "Description of the contents" \
    -publisher "The Company, Inc" \
    -p "Another Company, Inc" \
    -o $isoimage $isodir

The Rock Ridge protocol (-R) and Joliet fileystem (-J) options specify extensions to the ISO9660 standard that help with OS compatibility. Rock Ridge adds POSIX file capabilites for Unix-compatible systems, and Joliet improves Windows compatibility.

The -T option adds a translation table to each directory, which further enhances compatibility on both Windows and Linux systems.

The remaining options are fairly obvious.  The volume ID (-V) can be up to 32 characters.  You might want to avoid whitespace for easier use on Unix systems, but it's not a requirement.

The other strings for application ID (-A), publisher, preparer (-p), are descriptive strings that can be up to 128 characters.

If you don't specify an output file or device (-o), the output will be written to stdout.

If you choose to write to a file, you can use cdrecord (a symlink to wodim on newer versions of Linux) to burn a CD.  You'll need to know the name of the device file for the optical writer on your system.  It's usually /dev/cdrom, /dev/dvdwriter, or something similar.

The command I use to burn CD's and DVD's is
cdrecord dev=/dev/cdrom my-image.iso.

Thursday, July 25, 2013

Email with Mutt

It's been a long time since I used a plain-text mail reader from the command line in Linux.  I was surprised to see that mutt on Linux worked so easily -- with a secure Microsoft Exchange Server, even!

After installing the 'mutt' package with yum, I simply ran mutt.  Then I connected to my company Exchange server.

  • Press 'c' to connect
  • Enter IMAP server.  For example, imaps://exchange.company-intranet.com
  • Accept the certificate if you think it is valid
  • Enter your user name and password
That's it.  You should see a count of mail headers as they are downloaded.  Once that operation completes, you can read, compose, and delete messages at will.  Press '?' for help on key bindings.

Wednesday, June 19, 2013

Accessing services on KVM guests behind a NAT

I have a small web service running on a Fedora 17 VM. The VM lives on the default virtual network provided by libvirt, which allows outbound connections to the external world. But because the IPv4 space for that network (192.168.122.0/24) is private, the host's iptables rules will NAT all packets on their way out.

That means "no way in" for external connections. The virtual network addresses are unseen (unroutable) to the outside world.

Luckily, libvirtd provides hooks so that you can insert custom operations at key points in the start-up/shut-down phases of a guest.   The following procedure shows how to create a hook to modify iptables when a guest is starting (or stopping).
  1. On the host, create a new file called /etc/libvirt/hooks/qemu containing this sample script. (There's a link to a more comprehensive script if you need it. I also wrote a Python replacement below.)
  2. Replace the placeholder variables in the sample script with the guest name, addresses, and ports that are to be forwarded.
  3. Restart the libvirt service.
  4. Verify new DNAT rules with iptables -nvL -t nat.
Make sure that your guest doesn't have any iptables rules that will interfere.  For instance, you'll need to open up TCP port 80 if you want your web service to be accessible.

As an exercise, I rewrote the sample script in Python, adding some logging and removing some redundancy along the way.

#!/usr/bin/env python
#!/usr/bin/env python
import argparse
import logging
import subprocess
import sys

guestAddr = { 'f17-base':'192.168.122.200' }
hostPort = { '80':'8000', '22':'222' }
logFile = '/var/log/qemu-hook.log'
logLevel = logging.DEBUG

logging.basicConfig(filename=logFile, level=logLevel, format='%(asctime)s : %(message)s')

parser = argparse.ArgumentParser()
for arg in [ 'guest', 'op', 'subop', 'extra' ]:
    parser.add_argument(arg)
args = parser.parse_args()

logging.debug('qemu hook: guest %s, op %s' % (args.guest, args.op))
if args.guest not in guestAddr:
    logging.debug('Nothing to do for guest %s' % args.guest)
    sys.exit()

if args.op == 'start':
    natOp = '-A'
    filterOp = '-I'
    opStr = 'Adding'
elif args.op == 'stopped':
    natOp = filerOp = '-D'
    opStr = 'Removing'
else:
    logging.debug('Nothing to do for op %s' % args.op)
    sys.exit()

for gport in hostPort.keys():
    # build the nat command
    natcmd = ['iptables', '-t', 'nat', natOp, 'PREROUTING']
    gAddrPort = "{}:{}".format(guestAddr[args.guest], gport)
    natcmd += ['-p', 'tcp', '--dport', hostPort[gport], '-j', 'DNAT', '--to', gAddrPort]  
    logging.info('%s nat rules for %s' % (opStr, gAddrPort))
    subprocess.call(natcmd)
    # build the filter command
    filtercmd = ['iptables', filterOp, 'FORWARD']
    filtercmd += ['-d', '{}/32'.format(guestAddr[args.guest]), '-p', 'tcp']
    filtercmd += ['-m', 'state', '--state', 'NEW']
    filtercmd += ['-m', 'tcp', '--dport', gport, '-j', 'ACCEPT']
    logging.info('%s forwarding rules for %s' % (opStr, gport))
    subprocess.call(filtercmd)

logging.info('iptables update complete')
sys.exit()

Note that, depending on the version of libvirtd you are running, the hook may not process "reconnect" operations -- i.e., when libvirtd is restarted.  You need 0.9.13 or later for that.  If you have an earlier version, you may have an issue with duplicate rules.

I left those operations out of the Python script because my Fedora 17 system is running 0.9.11.

Cheers!

Fixed DHCP addresses in libvirt

The libvirt DHCP service can deal out fixed IP addresses.  Yes, you could simply configure the guest OS with a static IP, but that's beside the point.  A DHCP service should be able to handle fixed addresses and, earlier in the game, I didn't think libvirt was capable of it.  But it is!

Just add a host element to the default network XML file using virsh net-edit default.

<network>
  <name>default</name>
  <uuid>5c0448c7-4240-4325-9a80-eb9f575c962e</uuid>
  <forward mode='nat'/>
  <bridge name='virbr0' stp='on' delay='0' />
  <mac address='52:54:00:BE:58:83'/>
  <ip address='192.168.122.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.122.128' end='192.168.122.254' />
      <host mac='52:54:00:c9:06:c5' name='router122' ip='192.168.122.200' />
    </dhcp>
  </ip>
</network>

Of course, this same principle applies to other virtual networks.  The reason I doubted it at first is that virt-manager 0.9.5 doesn't expose this level of customization in its GUI.

Everything you need to know about network configuration can be found at libvirt networking.