2009-05-27

HOWTO: Install VMware Tools on Ubuntu using my script

I've previously written about my DKMS script and want to show this in action.

First of all, do this on the console, as the net driver probably will terminate your ssh connection.


My virtual demo host has very low priority, and this makes this demo a bit long...



video



I made this screen capture, using CamStudio

Regex matching email address and some benchmarking

Today I was trying to help a colleague with a regular expression (regex) for matching the most common email formats (Not quite RFC 2822, as most of the exceptions there is almost never seen).

My colleague came up with this expression:

^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$

This seems to work well, except for rare addresses having + in the local part.

My suggestion was this:

^[\w\.+-]+@(?:[a-z0-9-]{2,}\.)+[a-z0-9]{2,4}$

I wondered if mine was more efficient, and used Benchmark to try to figure this out.

My script looks like this:

#!/usr/bin/perl -w

use strict;
use Benchmark qw(:all);;

my $email = $ARGV[0]; # Supply the email address to benchmark as an argument

my $count = 1000000;

my $results = timethese($count, {'Optimized' => sub { $email =~ /^[\w\.+-]+@(?:[a-z0-9\-]{2,}\.)+[a-z0-9]{2,4}$/},
'Original' => sub { $email =~ /^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$/}
});

cmpthese($results);

I first tried the most common format (I think), localpart@domain:
$ ./mailre.pl ballek@supperaadet.not
Benchmark: timing 1000000 iterations of Optimized, Original...
Optimized: 2 wallclock secs ( 1.50 usr + 0.01 sys = 1.51 CPU) @ 662251.66/s (n=1000000)
Original: 3 wallclock secs ( 2.88 usr + 0.03 sys = 2.91 CPU) @ 343642.61/s (n=1000000)
Rate Original Optimized
Original 343643/s -- -48%
Optimized 662252/s 93% --

Then the heavily used firstname.lastname@domain:

$ ./mailre.pl balle.klorin@supperaadet.not
Benchmark: timing 1000000 iterations of Optimized, Original...
Optimized: 1 wallclock secs ( 1.36 usr + 0.00 sys = 1.36 CPU) @ 735294.12/s (n=1000000)
Original: 4 wallclock secs ( 2.85 usr + 0.01 sys = 2.86 CPU) @ 349650.35/s (n=1000000)
Rate Original Optimized
Original 349650/s -- -52%
Optimized 735294/s 110% --

At last, a format used by some MTA for local aliasing (Exim and Postfix usually uses - and qmail uses +):

$ ./mailre.pl balle.klorin-list@supperaadet.not
Benchmark: timing 1000000 iterations of Optimized, Original...
Optimized: 0 wallclock secs ( 1.44 usr + 0.00 sys = 1.44 CPU) @ 694444.44/s (n=1000000)
Original: 2 wallclock secs ( 2.97 usr + 0.00 sys = 2.97 CPU) @ 336700.34/s (n=1000000)
Rate Original Optimized
Original 336700/s -- -52%
Optimized 694444/s 106% --

I was not surprised that my version was faster. The real world impact of writing slow regex might not be that big (1 million test took about 3 seconds for the unoptimized version), and for this problem, matching email addresses, the product will not become noticeably slower. On the other hand, if you write something that parses millions of lines on a frequent basis, you should try to optimize your regex.

2009-05-19

Windows: Set processor affinity

From time to time, one might want to start a process on one or more dedicated CPU/cores.

The task manager has this ability in the process view, but this only changes runtime, and you have to do this every time you start that process.

The quick solution, is to use START. From Windows 2003 Server and Windows Vista, this command has the /AFFINITY option, that will give you a persistent way of dictating the CPU affinity.

The help from START /? says this:

AFFINITY The new application will have the specified processor
affinity mask, expressed as a hexadecimal number.


The question is, how to apply this?

Well, the cores have the following hex numbers:

  1. x01

  2. x02

  3. x04

  4. x08

  5. x10

  6. x20

  7. x40

  8. x80



To start a process on CPU 1 and 2, you will have to use the hex number 3 (1+2), for 1, 2, 3 and 4 the hex number f (1+2+4+8).

Like this:

START /AFFINITY f mycommand.exe


To easily calculate these hex numbers, I use a Perl one-liner like this:

$ perl -e 'map{$hex += 2**($_-1)} @ARGV; printf "%x\n", $hex;' 1 3 5 7
55

2009-05-13

Powershell: Toggle network connection status on virtual machines in VMware (take 2)

There been some time since I wrote the script and it is now in production.

Some changes have been made, both for functionality and security reasons.

When I added the script as an scheduled task, running as a logged in user, all was fine, but when it run as a non-interactive user, it failed to log in to the Virtual Centre (VC). Therefore we made a local user, added this an administrator for the virtual machine in VC and changed the script to use a specified username and password.

While trying to debug this when running as a scheduled task, we needed some kind of logging, and a simple and well known way to do this is by email. The new version has a possibility to send status emails (configurable).

I want to be sure that only one adapter is enabled at the time, so a small check to prevent enabling both cards is built in (the $prev check). An other thing I do, was to sort the adapters so that the script first disables the active card and then enables the inactive. This way, the virtual host is without connection on both cards for a very short time, but that is more secure than it was, there both cards would be enabled at the same time (usually every second time it toggled)

The code:
# Toggle connection state on NICs on a virtual machine
#
# Usage:
# powershell -noprofile -c -nologo -noninteractive "& 'C:\path to\script\toggle.ps1'"
#
# Copyright (c) 2009 Rune Nordbøe Skillingstad <rune.skillingstad@ntnu.no>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 dated June, 1991.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
# USA.

# Configure
# Seems like there is a problem authenticating without user/password
# when running this script uninteractive as a schedule.
$VIServer = "localhost"
$VIUser = "toggle-user"
$VIPassword = "secret"
$ComputerName = "myvirtualhost"

# Set sendmail = 1 for status emails
$sendmail = 0
$mailfrom = "Virtual Center <virtualcentre@mydomain.tld>"
$mailto = "user@mydomain.tld"
$smtpServer = "10.140.80.100"

# Add this to a schedule:
# You might want to change Execution Rights to Unrestricted (as I haven't
# signed this remote, RemoteSigned will not work)

# Magic ignoring warnings
$wpref = $WarningPreference
$WarningPreference ="SilentlyContinue"
Add-PSsnapin VMware.VimAutomation.Core
$server = Connect-VIServer -Server $VIServer -Protocol https -User $VIUser -Password $VIPassword
# Reset warings
$WarningPreference = $wpref

$body = $VIUser + " is toggling connection status on network adapters on " + $ComputerName + "`n"

if($server) {
$adapters = Get-NetworkAdapter $ComputerName

$prev = ""
# Sort so connected is disabled first
foreach($adapter in $adapters | Sort-Object @{Expression={$_.ConnectionState.Connected};Descending=$true;}) {
if(!$adapter -or $adapter.NetworkName -eq "") {
$body += "Ignoring unnamed adapter`n"
continue
}
if($prev -eq $adapter.ConnectionState.Connected) {
$body += "Detecting same status for " + $adapter.NetworkName + " as previous adapter.. ignoring`n"
} else {
if(!$adapter.ConnectionState.Connected) {
$body += "Enabling " + $adapter.NetworkName + "`n"
$ignore = Set-NetworkAdapter $adapter -Connected:$true -Confirm:$false
} else {
$body += "Disabling " + $adapter.NetworkName + "`n"
$ignore = Set-NetworkAdapter $adapter -Connected:$false -Confirm:$false
}
}
$prev = $adapter.ConnectionState.Connected
}
} else {
$body = $body + "Problems connecting to VI server"
}

if($sendmail -eq 1) {
$msg = new-object Net.Mail.MailMessage
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
$msg.From = $mailfrom
$msg.To.Add($mailto)
$msg.Subject = “VMware Network Toggler”
$msg.Body = $body
$smtp.Send($msg)
}