#! /usr/bin/perl -w
# $Header: /usr/groups/linux/xen/RCS/xe2xf.pl,v 1.1 2008/04/06 20:25:43 pb22 Exp $
=head1 NAME

xe2xf.pl - generate a Xen Fedora config filr from XenE data

=head1 SYNOPSIS

xe2xf.pl machine

=head1 OPTIONS

=over 4

=item B<--trace>

trace what it is doing.

=item B<--help>

generate help info.

=item B<--mc>

XenE machine to use for data (default: I<godmanchester>)

=item B<--dir>

full directory to use (default: I</usr/groups/linux/ownfiles/$mc/samp/>)

=item B<--vm>

do a vm lookup on regexp B<machine> to get the UUID. "--vm ." will list all machines.

=item B<--vif>

do a vif lookup to get the network info.

=item B<--vdb>

do a vdb lookup to get the VDI info.

=item B<--vdi>

do a vdi lookup to get the LVM.

=back

=head1 DESCRIPTION

With no flags, generates a Xen Fedora config file from XenE info in B<ownfiles>

slogin-serv3:~: ~/pl/xe-info.pl -vif cups-serv2
0 00:16:3E:E8:09:D2 vtrunk100-eth2
1 00:16:3E:E8:09:D2 vlan457
slogin-serv3:~: ~/pl/xe-info.pl -vbd cups-serv2 | xargs -n 2 ~/pl/xe-info.pl -vdi 
xvdb /dev/VG_XenStorage-279ab38c-32ec-865e-3e69-84adeadd7193/LV-a9428dc2-f06e-4bb3-9c9b-da7221ad5c0b
xvda /dev/VG_XenStorage-279ab38c-32ec-865e-3e69-84adeadd7193/LV-e00bac25-d68e-4b84-8ea7-a07ad01a3892
xvdc /dev/VG_XenStorage-1f6ea335-5999-3d8a-60aa-2b54386be80d/LV-f11bcdb9-946e-45ba-bb46-b8e467f1a6ac
slogin-serv3:~: 

=cut

use Getopt::Long;
use Pod::Usage;

$mc = "downham";

%opts = (
	"trace"		=> \$trace,
	"help"		=> \$help,
	"mc:s"		=> \$mc,
	"dir:s"		=> \$dir,
	"vm"		=> \$opt_vm,
	"vif"		=> \$opt_vif,
	"vbd"		=> \$opt_vbd,
	"vdi"		=> \$opt_vdi,
);

GetOptions (%opts) || pod2usage();
pod2usage(-verbose => 2) if $help;

%brmap = (
	"vtrunk100-eth2"	=> "xenbr0",
);

$dir = sprintf "/usr/groups/linux/ownfiles/%s/samp", $mc unless $dir;

print STDERR "$0: using $dir ($opt_vm)\n" if $trace;

if ($opt_vm) {
	die("$0: vm expectes one argument\n") unless $#ARGV == 0;
	print STDERR "$0: do vm($ARGV[0])\n" if $trace;
	print join("\n", &read_vm_list($ARGV[0])), "\n";
} elsif ($opt_vif) {
	die("$0: vif expectes one argument\n") unless $#ARGV == 0;
	print STDERR "$0: do vif($ARGV[0])\n" if $trace;
	print &read_vif_list($ARGV[0]), "\n";
} elsif ($opt_vdi) {
	die("$0: vdi expectes two arguments\n") unless $#ARGV == 1;
	print STDERR "$0: do vdi($ARGV[0], $ARGV[1])\n" if $trace;
	print &read_vdi_list($ARGV[0], $ARGV[1]), "\n";
} elsif ($opt_vbd) {
	die("$0: vbd expectes one argument\n") unless $#ARGV == 0;
	print STDERR "$0: do vbd($ARGV[0])\n" if $trace;
	print &read_vbd_list($ARGV[0]), "\n";
} elsif ($#ARGV == 0) {
	my ($name) = $ARGV[0];
	print "name = \"$name\"\n";
	@vmdata = &read_vm_list($name);
	foreach $vmdata (@vmdata) {
		my ($uuid, $name, $max, $min, $cmax, $cmin) = split(/ /, $vmdata);
		print "memory = $min\n";
		print "maxmem = $max\n" unless $min == $max;
		print "vcpus=$cmin\n" if $cmin > 1;
		print "# max_vcpus=$cmax\n" if $cmax > 1;
	}
	@vdb = &read_vbd_list($name);
	my (@res) = ();
	foreach $vdb (@vdb) {
		my ($key, $val) = split(/ /, $vdb);
		push @res, &read_vdi_list($key, $val);
	}
	print "disk = [ ", @res, " ]\n";
	print "vif = [ ", &read_vif_list($name), "]\n";
	print "vnc=1\n";
	print "bootloader=\"/usr/bin/pygrub\"\n";
} else {
	pod2usage();
}

sub read_vm_list {
	my ($want) = @_;
	my (@want) = ();
	my (@match) = ();
	my ($last);
	my ($file) = "$dir/xe-vm-list#params=all";
	my (@res) = ();
	open(VMS, $file) || die("$0: failed to open $file: $!\n");
	while (<VMS>) {
		# uuid ( RO)           : 10b7952b-c0f2-c804-b59b-70914b4a65c5
		# name-label ( RW): slogin-serv3
		# power-state ( RO): running
		# memory-dynamic-max ( RW): 536870912
		# memory-dynamic-min ( RW): 536870912
		# memory-static-max ( RW): 536870912
		# memory-static-min ( RW): 16777216
		# VCPUs-max ( RW): 4
		# VCPUs-at-startup ( RW): 2
		if (/^\s*uuid\s+.*:\s*(\S+)/) { $uuid = $1; next; }
		if (/^\s*name-label\s+.*:\s*(\S+)/) { $name = $1; next; }
		if (/^\s*memory-dynamic-max\s+.*:\s*(\S+)/) { $memmax = $1 / (1024*1024); next; }
		if (/^\s*memory-dynamic-min\s+.*:\s*(\S+)/) { $memmin = $1 / (1024*1024); next; }
		if (/^\s*VCPUs-max\s+.*:\s*(\S+)/) { $cpumax = $1; next; }
		if (/^\s*VCPUs-at-startup\s+.*:\s*(\S+)/) { $cpumin = $1; next; }
		if (/^\s*$/) {
			$data = "$uuid $name $memmax $memmin $cpumax $cpumin";
			push @want, $data if $name eq $want;
			push @match, $data if $name =~ /$want/oi;
			$name = "";
			next;
		}
	}
	close(VMS) || die("$0: failed to close $file: $!\n");
	return @want if $#want >= 0;
	return @match;
}

sub read_vif_list {
	my ($want) = @_;
	my ($file) = "$dir/xe-vm-vif-list";
	my ($networkuuid);
	my (@res) = ();
	open(VMS, $file) || die("$0: failed to open $file: $!\n");
	while (<VMS>) {
		# uuid ( RO)                  : 98d4d6cb-7457-9507-a503-e2c1da853d0b
		#          vm-name-label ( RO): bescot
		#                 device ( RO): 0
		#                    MAC ( RO): 00:16:3e:e8:01:80
		#           network-uuid ( RO): 257d946d-ea83-96e0-c621-d58e6ceff0cf
		#     network-name-label ( RO): vtrunk100-eth2
		if (/^\s*network-name-label\s+.*:\s*(\S+)/) { $networknamelabel = $1; next; }
		if (/^\s*network-uuid\s+.*:\s*(\S+)/) { $networkuuid = $1; next; }
		if (/^\s*vm-name-label\s+.*:\s*(\S+)/) { $vmnamelabel = $1; next; }
		if (/^\s*MAC\s+.*:\s+(\S+)/) { $mac = $1; next; }
		if (/^\s*device\s+.*:\s*(\S+)/) { $device = $1; next; }
		if ($mac) {
			$networknamelabel = $brmap{$networknamelabel} if $brmap{$networknamelabel};
			$res[$device] = "'mac=$mac, bridge=$networknamelabel', " if $vmnamelabel eq $want;
			$mac = 0;
		}
	}
	close(VMS) || die("$0: failed to close $file: $!\n");
	return @res;
}

sub read_vbd_list {
	my ($want) = @_;
	my ($file) = "$dir/xe-vbd-list";
	my (@res) = ();
	open(VMS, $file) || die("$0: failed to open $file: $!\n");
	while (<VMS>) {
		# uuid ( RO)             : 4385ca20-2646-4fae-3cab-3031ebeb6055
		#           vm-uuid ( RO): c6b46f58-61ce-841b-4f58-40575b07d7f5
		#     vm-name-label ( RO): cups-serv2
		#          vdi-uuid ( RO): f11bcdb9-946e-45ba-bb46-b8e467f1a6ac
		#             empty ( RO): false
		#            device ( RO): xvdc
		if (/^\s*vm-name-label\s+.*:\s*(\S+)/) { $vmnamelabel = $1; next; }
		if (/^\s*vm-uuid\s+.*:\s*(\S+)/) { $vmuuid = $1; next; }
		if (/^\s*vdi-uuid\s+.*:\s*(\S+)/) { $vdiuuid = $1; next; }
		if (/^\s*empty\s+.*:\s+(\S+)/) { $empty = $1; next; }
		if (/^\s*device\s+.*:\s*(\S+)/) { $device = $1; next; }
		if ($vdiuuid) {
			push @res, "$device $vdiuuid" if $vmnamelabel eq $want && $empty eq "false";
			$vdiuuid = 0;
		}
	}
	close(VMS) || die("$0: failed to close $file: $!\n");
	return @res;
}

sub read_vdi_list {
	my ($prefix, $want) = @_;
	my ($file) = "$dir/xe-vdi-list";
	my ($namelabel);
	my (@res) = ();
	open(VMS, $file) || die("$0: failed to open $file: $!\n");
	while (<VMS>) {
		# uuid ( RO)                : e00bac25-d68e-4b84-8ea7-a07ad01a3892
		#           name-label ( RW): cups-serv2
		#     name-description ( RW): CUPS server
		#              sr-uuid ( RO): 279ab38c-32ec-865e-3e69-84adeadd7193
		#         virtual-size ( RO): 2147483648
		#             sharable ( RO): false
		#            read-only ( RO): false
		if (/^\s*uuid\s+.*:\s*(\S+)/) { $uuid = $1; next; }
		if (/^\s*name-label\s+.*:\s*(\S+)/) { $namelabel = $1; next; }
		if (/^\s*name-description\s+.*:\s*(\S+)/) { $vmuuid = $1; next; }
		if (/^\s*sr-uuid\s+.*:\s*(\S+)/) { $sruid = $1; next; }
		if (/^\s*virtual-size\s+.*:\s+(\S+)/) { $empty = $1; next; }
		if (/^\s*sharable\s+.*:\s*(\S+)/) { $device = $1; next; }
		if (/^\s*read-only\s+.*:\s*(\S+)/) { $readonly = $1; $rw = ($readonly eq "false") ? "rw" : "ro"; next; }
		if ($sruid) {
			push @res, "'phy:VG_XenStorage-$sruid/LV-$uuid,$prefix,$rw'," if $uuid eq $want;
			$sruid = 0;
		}
	}
	close(VMS) || die("$0: failed to close $file: $!\n");
	return @res;
}
