#!/usr/bin/perl

use lib "/etc/kvm/api";
#push(@INC, "/etc/kvm/api");

use strict;
use Getopt::Std;
use POSIX qw(floor);

use KVMapi;

my $command = shift;
my $vm_name = shift;
my $maxwait = 60;

my $isEnabled = (-d "/sys/devices/system/kvm");

if ($command eq "shutdown" || $command eq "stop")
{
	unless ($isEnabled)
	{
		printf("KVMctrl: host is not kvm enabled...\n");
		exit(1);
	}

	my $kvm = KVMapi->new($vm_name);
	unless ($kvm->isRunning())
	{
		printf("KVMctrl: machine $vm_name is not running...\n");
		exit(1);
	}
	$kvm->sendShutdown();	
	printf("KVMctrl: shutdown request sent to $vm_name...\n");
}
elsif ($command eq "reset")
{
	unless ($isEnabled)
	{
		printf("KVMctrl: host is not kvm enabled...\n");
		exit(1);
	}

	my $kvm = KVMapi->new($vm_name);
	unless ($kvm->isRunning())
	{
		printf("KVMctrl: machine $vm_name is not running...\n");
		exit(1);
	}
	$kvm->sendReset();
	printf("KVMctrl: hardware reset sent to $vm_name...\n");
}
elsif ($command eq "destroy")
{
	unless ($isEnabled)
	{
		printf("KVMctrl: host is not kvm enabled...\n");
		exit(1);
	}

	my $kvm = KVMapi->new($vm_name);
	unless ($kvm->isRunning())
	{
		printf("KVMctrl: machine $vm_name is not running...\n");
		exit(1);
	}
	$kvm->destroy();
	my %options = $kvm->getOptions();
	my $pidfile = $options{"pidfile"};
	if (-f $pidfile)
	{
		`kill \$( cat $pidfile ) 2>/dev/null`;
		unlink($pidfile);
	}

	printf("KVMctrl: machine $vm_name destroyed...\n");
}
elsif ($command eq "isrunning")
{
	unless ($isEnabled)
	{
		printf("KVMctrl: host is not kvm enabled...\n");
		exit(1);
	}
	my $kvm = KVMapi->new($vm_name);
	if ($kvm->isRunning())
	{
		exit(0);
	}
	exit(1);
}
elsif ($command eq "reboot")
{
	my $cnt = 0;
	my $kvm = KVMapi->new($vm_name);
	if ($kvm->isRunning())
	{
		printf("KVMctrl: sending shutdown command and waiting for completition (maxwait is $maxwait seconds)\n");
		system("/usr/sbin/kvmctrl shutdown $vm_name");
		while ($cnt < $maxwait)
		{
			sleep(1);
			$kvm = KVMapi->new($vm_name);
			$cnt++;
			next if ($kvm->isRunning());
	
			printf("KVMctrl: machine stopped...\n");
			$cnt = 0;
			last;
		}
	}
	if ($cnt == 0)
	{
		printf("KVMctrl: starting machine...\n");
		system("/usr/sbin/kvmctrl start $vm_name");
	}
	else
	{
		printf("KVMctrl: forcing a reset of machine...\n");
		system("/usr/sbin/kvmctrl reset $vm_name");
	}
	sleep(1);
	my $rval = system("/usr/sbin/kvmctrl isrunning $vm_name");
	if ($rval != 0)
	{
		printf("KVMctrl: for some reason the vm didn't boot... retrying once...\n");
		system("/usr/sbin/kvmctrl start $vm_name");
	}
}
elsif ($command eq "console")
{
	unless ($isEnabled)
	{
		printf("KVMctrl: host is not kvm enabled...\n");
		exit(1);
	}

	my $kvm = KVMapi->new($vm_name);
	unless ($kvm->isRunning())
	{
		printf("KVMctrl: machine $vm_name is not running...\n");
		exit(1);
	}

	my %options = $kvm->getOptions();
	system("nc localhost " . $options{"console_port"});
#	printf("automatic console attachment not yet implemented... need to execute the following...");
#	$kvm->attachConsole();
}
elsif ($command eq "types")
{
	printf("vga:  std,cirrus,vmware,none\n");
	printf("disk: virtio,ide,scsi\n");
	printf("vif:  virtio,rtl1389,e1000\n");
}
elsif ($command eq "start")
{
	unless ($isEnabled)
	{
		printf("KVMctrl: host is not kvm enabled...\n");
		exit(1);
	}

	my $kvm = KVMapi->new($vm_name);
	if ($kvm->isRunning())
	{
		printf("KVMctrl: machine $vm_name is already running...\n");
		exit(1);
	}
	my $rval = system("/sbin/start-stop-daemon -q -b -S --exec /usr/sbin/kvmwrap -- $vm_name");
	if ($rval ne 0)
	{
		printf("kvm %s couldn't be started, code: %s\n", $vm_name, $rval);
		exit(1);
	}	

	my %options = $kvm->getOptions();
	if ($options{"vnc_password"} ne "")
	{
		printf("kvm %s started, waiting for vnc setup...\n", $vm_name);
		sleep(1);
	
		$kvm->sendVncPassword($options{"vnc_password"});
		printf("done...\n", $vm_name);
	}
	else
	{
		printf("kvm %s started...\n", $vm_name);
	}
}
elsif ($command eq "list")
{
	opendir(DIR, "/etc/kvm");
	my @files = readdir(DIR);
	closedir(DIR);

	my $syntax = "%-25s%3s%6s%6s%7s%2s%-15s\n";
	printf($syntax, "Name", "ID", " Mem", " VCPUs", " PID", "", "State");
	my $usedRam;
	my $neededRam;
	foreach my $file (@files)
	{
		next unless ($file =~ /\.kvm$/);
		my $name = $file;
		$name =~ s/\.kvm//g;
#		printf ("file: '%s'\n", $name);
		my $kvm = KVMapi->new($name);
		my %options = $kvm->getOptions();
		$neededRam += $options{"mem"};
		if ($kvm->isRunning())
		{
			$usedRam += $options{"mem"};
		}

		printf($syntax,
			$name, 
			$options{"id"}, 
			$options{"mem"}, 
			$options{"cpus"}, 
			$options{"pid"},
			"", $options{"state"});
	}	

	my $cpus=`grep -w processor /proc/cpuinfo | wc -l`;
	chomp($cpus);
	
	my $memory=`grep -w MemTotal /proc/meminfo | awk '{ print \$2 }'`;
	chomp($memory);
	$memory = floor($memory / 1024);
	$memory -= $neededRam;

	my $state = "kvm disabled";
	if ($isEnabled)
	{
		$state = "kvm enabled";
	}
	printf($syntax, "domain-0", "", $memory, $cpus, "", "", $state);
}
else
{
	printf("Usage: kvmctrl <subcommand> [args]\n");
	printf("\n");
	printf("Control, list, and manipulte KVM guest instances.\n");
	printf("\n");
	printf("Common 'kvmctrl' commands:\n");
	printf("\n");

	printf(" console                Attach to <Domain>'s kvm console.\n");
	printf(" list			List information about all/some domains.\n");
	printf(" help			Display this message.");
	printf(" start                  Create a domain based on <Domain>.\n");
	printf(" shutdown	        Issue a system shutdown command on <Domain>.\n");
	printf(" reset                  Reset a domain immediately.\n");
	printf(" reboot			Issues a shutdown, waits for completition and recreates <Domain>.\n");
	printf(" destroy                Terminate a domain immediately.\n");
	printf("\n");
	printf("<Domain> must be the Domain Name.\n");
}


