#!/usr/bin/perl
# External STONITH module for VMWare ESXi 5 Server Guests
#
# Copyright (c) 2012 OpenServices e.U. - Michael Fladischer <Michael.Fladischer@openservices.at>
# Copyright (c) 2004 SUSE LINUX AG - Andrew Beekhof <abeekhof@suse.de>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it would be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# Further, this software is distributed without any warranty that it is
# free of the rightful claim of any third person regarding infringement
# or the like.  Any license provided herein, whether implied or
# otherwise, applies only to this software file.  Patent licenses, if
# any, provided herein do not apply to combinations of this program with
# other software, or any other product whatsoever.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
#
use strict;
use warnings;

sub supply_default
{
    my $name = $_[0];
    my $value = $_[1];

    if ( ! defined $ENV{$name} ) {
	$ENV{$name} = $value;
    }
}

sub vmware_command
{
    my $action = $_[0];
    my $target = $_[1] || "";
    my @lines;

    my $device = $ENV{'device_host'}; 

    if ( $device =~ /localhost/ ) {
	@lines = readpipe "vim-cmd $action $target";

    } else {
	@lines = readpipe "ssh $device \"vim-cmd \\\"$action\\\" $target\"";
    }

    return @lines;
}

sub is_host_active
{
    my $target = target_for_host($_[0]);
    my @lines = vmware_command("vmsvc/power.getstate", $target);
    foreach my $line (@lines) {
	if ( $line =~ /^Powered on$/ ) {
	    return 1;
	}
    }
    return 0;
}

sub supported_hosts
{
    my $line;
    my @lines;
    my $host;

    if ( defined $ENV{'host_map'} ) { 
	@lines = split(/;/, $ENV{'host_map'});
	foreach my $line (@lines){
	    my @config = split(/=/, $line);
	    $host = $config[0];
	    if ( is_host_active($host) == 1 ) {
		print "$host\n";
	    }
	}
	
    } else {
	@lines = vmware_command("vmsvc/getallvms");
	foreach my $line (@lines){
	    my @elements = split(/\s+/, $line);
            next if $elements[0] !~ /^\d+$/;
	    $host = $elements[1];
	    if ( is_host_active($host) == 1 ) {
		print "$host\n";
	    }
	}
    }
}

sub target_for_host
{
    my $line;
    my @lines;
    my $host = $_[0];

    if ( defined $ENV{'host_map'} ) { 
	@lines = split(/;/, $ENV{'host_map'});
	foreach my $line (@lines){
	    if ( $line =~ /^$host=/ ) {
		my @config = split(/=/, $line);
		return $config[1];
	    }
	}
	
    } else {
	@lines = vmware_command("vmsvc/getallvms");
	
	foreach my $line (@lines){
            my @elements = split(/\s+/, $line);
            chomp($elements[1]);
	    if ( $elements[1] =~ /^$host$/ ) {
                chomp($elements[0]);
		return $elements[0];
	    }
	}
    }
}

my $host;
my $command = $ARGV[0];
if ( defined $ARGV[1] ) {
    $host = $ARGV[1];
}

supply_default("device_host", "localhost");

if ( $command =~ /^gethosts$/ ) {
    supported_hosts;

} elsif ( $command =~ /^getconfignames$/ ) {
    print "device_host\n";

} elsif ( $command =~ /^getinfo-devid$/ ) {
    print "VMware Server STONITH device\n";
} elsif ( $command =~ /^getinfo-devname$/ ) {
    print "VMware Server STONITH device\n";
} elsif ( $command =~ /^getinfo-devdescr$/ ) {
    print "VMware Server STONITH device\n";
} elsif ( $command =~ /^getinfo-devurl$/ ) {
    print "http://www.vmware.com/";

} elsif ( $command =~ /^on$/ ) {
    print vmware_command("vmsvc/power.on", target_for_host($host));

} elsif ( $command =~ /^off$/ ) {
    print vmware_command("vmsvc/power.off", target_for_host($host));

} elsif ( $command =~ /^reset$/ ) {
    print vmware_command("vmsvc/power.reset", target_for_host($host));

} elsif ( $command =~ /^status$/ ) {
    my $rc = 7;
    my $device = $ENV{'device_host'}; 
    if ( $device =~ /localhost/ ) {
	$rc = 0;
	# TODO: Check for the vmware process
	print "Local version: always running\n";

    } else {
	print "Remote version: running ping\n";
	my @lines = readpipe "ping -c1 $device";
	print @lines;

	foreach my $line ( @lines ) {
	    if ( $line =~ /0% packet loss/ ) {
		$rc = 0;
		last;
	    }
	}
    }
    exit($rc);

} elsif ( $command =~ /^getinfo-xml$/ ) {
    print <<END;
<parameters>
<parameter name="host_map" unique="0" required="0">
<content type="string" />
<shortdesc lang="en">
Host Map
</shortdesc>
<longdesc lang="en">
A mapping of hostnames to config paths supported by this device.
Eg. host1=/config/path/1;host2=/config/path/2;host3=/config/path/3;
</longdesc>
</parameter>
<parameter name="device_host" unique="0" required="0">
<content type="string" />
<shortdesc lang="en">
Device Host
</shortdesc>
<longdesc lang="en">
The machine _hosting_ the virtual machines
</longdesc>
</parameter>
</parameters>
END

} else {
    print "Command $command: not supported\n";
    exit(3); # Not implemented
}

exit(0);
