#
# Copyright 1998 VMware, Inc.  All rights reserved. -- VMware Confidential
#

package VMware::VmPerl::VM;

use strict;

require DynaLoader;

use vars qw($VERSION @ISA);

BEGIN{$VERSION = '1.01';}

@ISA = qw(DynaLoader);

use VMware::VmPerl $VERSION;

# Preloaded methods go here.

sub new {
    return New();
}

sub get_last_error {
    my $vm = shift;
    my ($ret, $string) = $vm->GetLastError();
    if (wantarray) {
        return ($ret, $string);
    } else {
        return $ret;
    }
}

sub is_connected {
    my $vm = shift;
    return $vm->IsConnected();
}

sub connect {
    my $vm = shift;
    my ($cp, $cfg) = (undef, undef);

    $cp = shift if $#_ >= 0;
    $cfg = shift if $#_ >= 0;

    my $ret = $vm->Connect($cp, $cfg);

    if ($ret) {
       return $ret;
    } else {
       return undef;
    }
}

sub start {
    my $vm = shift;
    my $mode = shift;
    if (!defined($mode)) {
        $mode = VM_POWEROP_MODE_SOFT;
    }

    my $ret = $vm->Start($mode);
    if ($ret) {
        return $ret;
    } else {
        return undef;
    }
}

sub stop {
    my $vm = shift;
    my $mode = shift;
    if (!defined($mode)) {
        $mode = VM_POWEROP_MODE_SOFT;
    }
    my $ret = $vm->Stop($mode);
    if ($ret) {
        return $ret;
    } else {
        return undef;
    }
}

sub reset {
    my $vm = shift;
    my $mode = shift;
    if (!defined($mode)) {
        $mode = VM_POWEROP_MODE_SOFT;
    }
    my $ret = $vm->Reset($mode);
    if ($ret) {
        return $ret;
    } else {
        return undef;
    }
}

sub suspend {
    my $vm = shift;
    my $mode = shift;
    if (!defined($mode)) {
        $mode = VM_POWEROP_MODE_SOFT;
    }

    my $ret = $vm->SuspendToDisk($mode);
    if ($ret) {
        return $ret;
    } else {
        return undef;
    }
}

sub resume {
    my $vm = shift;
    my $mode = shift;
    if (!defined($mode)) {
        $mode = VM_POWEROP_MODE_SOFT;
    }

    my $state = $vm->get_execution_state();

    if (defined($state) && 
        $state != VM_EXECUTION_STATE_SUSPENDED) {
        $vm->SetError(VM_E_BADSTATE, $state);
        return undef;
    }

    return $vm->start();
}

sub info {
    my $vm = shift;
    my @list = $vm->Info();
    my %hash;
    my ($k, $v);

    if ($#list <= 0) {
        return undef;
    }

    if (! ($#list % 2)) {
        print STDERR "VMware::VmPerl::VM::info: Warning: hash has odd number of elements\n";
    }

    keys(%hash) = $#list;
    while($#list > 0) {
        ($k, $v) = splice(@list, 0, 2);
        $hash{$k} = $v;
    }
    return \%hash;
}

sub disconnect {
    my $vm = shift;
    my $ret = $vm->Disconnect();

    return 1;
}

sub answer_question {
   my $vm = shift;
   my $ret = $vm->AnswerQuestion(@_);
   if ($ret) {
      return $ret;
   } else {
      return undef;
   }
}

sub connect_device {
   my $vm = shift;
   
   my $ret;
   $ret = $vm->DeviceConnect(@_);
   
   if ($ret) {
      return $ret;
   } else {
      return undef;
   }
}

sub disconnect_device {
   my $vm = shift;
   
   my $ret;
   $ret = $vm->DeviceDisconnect(@_);
   
   if ($ret) {
      return $ret;
   } else {
      return undef;
   }
}

sub device_is_connected {
    my $vm = shift;

    return $vm->DeviceIsConnected(@_);
}

sub tools_install_begin {
    my $vm = shift;

    my $ret = $vm->ToolsInstallBegin();

    if ($ret) {
        return $ret;
    } else {
        return undef;
    }
}

sub tools_install_end {
    my $vm = shift;

    my $ret = $vm->ToolsInstallEnd();

    if ($ret) {
        return $ret;
    } else {
        return undef;
    }
}

sub set_timeout {
    my $vm = shift;
    my $ret = $vm->SetTimeout(VM_TIMEOUT_ID_DEFAULT,@_);
}

sub get_execution_state {
   my $vm = shift;
   my $ret = $vm->GetExecutionState();
   return $ret;
}

sub get_pending_question {
   my $vm = shift;
   my $ret = $vm->GetExternalQuestion();
   if ($ret) {
      return $ret;
   } else {
      return undef;
   }
}

sub get_guest_info {
   my $vm = shift;
   return $vm->GetGuestInfo(@_);
}

sub set_guest_info {
   my $vm = shift;
   my $ret = $vm->SetGuestInfo(@_);

   if ($ret) {
      return $ret;
   } else {
      return undef;
   }
}

sub get_config {
   my $vm = shift;
   return $vm->GetConfig(@_);
}

sub set_config {
   my $vm = shift;
   my $ret = $vm->SetConfig(@_);

   if ($ret) {
      return $ret;
   } else {
      return undef;
   }
}

sub get_uptime {
   my $vm = shift;
   my $ret = $vm->GetUptime();

   return $ret;
}

sub get_heartbeat {
   my $vm = shift;
   my $ret = $vm->GetHeartbeat();

   return $ret;
}

sub get_id {
   my $vm = shift;
   my $ret = $vm->GetId();

   return $ret;
}

sub get_pid {
   my $vm = shift;
   my $ret = $vm->GetPid();

   return $ret;
}

sub get_capabilities {
   my $vm = shift;
   my $ret = $vm->GetCapabilities();

   return $ret;
}

sub get_remote_connections {
   my $vm = shift;
   my $ret = $vm->GetRemoteConnections();

   return $ret;
}

sub get_tools_last_active {
   my $vm = shift;
   my $ret = $vm->ToolsLastActive();

   return $ret;
}

sub get_product_info {
   my $vm = shift;

   my $ret = $vm->GetProductInfo(@_);
   
   return $ret;
}

sub get_config_file_name {
  my $vm = shift;
  
  my $ret = $vm->GetConfigFileName();
  if ($ret) {
    return $ret;
  }
  else {
    return undef;
  }
}

sub get_connected_users {
  my $vm = shift;

  my @values = $vm->Who();
  if (@values) {
    return @values;
  }
  else {
    return undef;
  }
}

sub get_resource {
   my $vm = shift;
   my $key = shift;

   my $ret = $vm->GetResource($key);
   return $ret;
}

sub set_resource {
   my $vm = shift;
   my $key = shift;
   my $value = shift;

   my $ret = $vm->SetResource($key, $value);
   if (!$ret) {
      return undef;
   } else {
      return $ret;
   }
}

sub add_redo {
   my $vm = shift;
   my $disk = shift;

   my $ret = $vm->AddRedo($disk);
   return $ret;
}

sub commit {
   my $vm = shift;
   my $disk = shift;
   my $level = shift;
   my $freeze = shift;
   my $wait = shift;

   my $ret = $vm->Commit($disk, $level, $freeze, $wait);
   return $ret;
}

sub get_runas_user {
   my $vm = shift;
   return $vm->GetRunAsUser();
}

sub set_runas_user {
   my $vm = shift;
   my $username = shift;
   my $password = shift;
   my $checkValid = 1;

   return $vm->SetRunAsUser($username, $password, $checkValid);
}

#############################################################
#
# INTERNAL TESTING ONLY.
# Reads legacy VM and Server variables
#
#############################################################

sub get_legacy {
   my $vm = shift;
   my $key = shift;
   my $ret = $vm->GetAsString($key);
   return $ret;
}

sub get_server_legacy {
   my $vm = shift;
   my $key = shift;
   my $ret = $vm->GetAsStringServerd($key);
   return $ret;
}


#Initialize the VM portion API library and return 1 if OK
VMware::VmPerl::VM::Init();

__END__

=head1 NAME 

VMware::VmPerl::VM - A perl module for controlling VMware virtual machines.

=head1 SYNOPSIS

  use VMware::VmPerl::VM;

  $connect_params = VMware::VmPerl::ConnectParams::new(undef, 0, undef, undef);
  $vm = VMware::VmPerl::VM::new();

  $err = $vm->connect($connectparams);
  if (!defined($err)) {
    ($errorNumber, $errorString) = $vm->get_last_error();
  }

  $ret = $vm->start();

  $ret = $vm->stop();
  $ret = $vm->stop(1);

  $ret = $vm->reset();

  $value = $vm->get_execution_state();

  $value = $vm->get_config("log.filename");

  $ret = $vm->connect_device("ide0:1");

  $ret = $vm->disconnect_device("ide0:1");

  $vm->disconnect();

=head1 DESCRIPTION

TBA

=head1 VMware::VmPerl::VM

=head2 $vm->get_execution_state()

Returns the virtual machine's current state. Can be one of the following values:

   VM_EXECUTION_STATE_ON
   VM_EXECUTION_STATE_OFF
   VM_EXECUTION_STATE_SUSPENDED
   VM_EXECUTION_STATE_STUCK
   VM_EXECUTION_STATE_UNKNOWN

=head2 $vm->get_pending_question()

Returns a C<VMware::VmPerl::Question> object if the virtual machine is currently in the C<VMEXECUTIONSTATE_STUCK> state. Otherwise, an error is thrown.

=head2 $vm->get_guest_info($key_name)

=head2 $vm->set_guest_info($key_name, $value)

Access a shared string variable identified by key_name. Shared variables allow scripts running outside of a virtual machine to exchange information with scripts running inside of the virtual machine. When a virtual machine process is created on the server, all shared variables are initially undefined. A shared variable is created the first time it is written. Shared variable key names are user-defined, and any number may be created. When a virtual machine process terminates, i.e, it is powered off and no remote consoles are connected, all shared variables are destroyed.

In a Linux guest operating system, use /etc/VMware-tools/VMware-guestd --cmd 'info-[get/set] guestinfo.key_name [valueToSet]' to read or write the shared variable key_name.

In a Windows guest operating system, the syntax is VMwareService.exe --cmd "info-[get/set] guestinfo.key_name [valueToSet]".

An perl script running outside the virtual machine can then read or write this variable through the C<VMware::VmPerl::VM> object's get_guest_info() and set_guest_info() method.

=head2 $vm->get_config($key_name)

Accesses the value of a configuration variable identified by key_name. The value read or written is always a string. When a virtual machine process is first started, configuration variables are read from the virtual machine's configuration file into memory. If a configuration variable is written through the Config() method, only its memory copy is updated and the new value is discarded when the virtual machine process terminates. An error is thrown if an undefined configuration variable is read.

=head2 $vm->set_config($key_name, $value)

Sets the value of a configuration variable identified by key_name to value.

=head2 $vm->get_product_info($infotype)

  Provides information about the product.

  $infotype  [in] one of the following strings:
                    "VM_PRODINFO_PRODUCT"
                    "VM_PRODINFO_PLATFORM"
                    "VM_PRODINFO_BUILD"
                    "VM_PRODINFO_VERSION_MAJOR"
                    "VM_PRODINFO_VERSION_MINOR"
                    "VM_PRODINFO_VERSION_REVISION"

=head2 $vm->get_id()

Returns the numerical id of the virtual machine which uniquely identifies the virtual machine among all virtual machines registered with a server.

=head2 $vm->get_pid()

Returns the process id of a running virtual machine process.

=head2 $vm->get_heartbeat()

Returns the current heart beat count generated by the VMware Tools service running in the guest operating system. The count is initialized to zero when the virtual machine is powered on. It is typically incremented at least once per second when the VMware Tools service is running under light load conditions. The count stays constant if the service is not running.

=head2 $vm->get_resource($key_name)

Accesses the value of a resource as identified by key_name. The value read or written is always a string. 

=head2 $vm->set_resource($key_name, $value)

Sets the value of resource as identified by key_name to value.

=head2 $vm->get_remote_connections()

Returns the number of remotely connected clients, which includes the number of remote console, API client and Web-based management interface connections made to the virtual machine in question.

=head2 $vm->get_capabilities()

Returns the access permissions that the current user has on the virtual machine in question.

=head2 $vm->get_uptime()

Returns the uptime of the virtual machine. Roughly corresponds to number of seconds elapsed since the last time the virtual machine is powered on.

=head2 $vm->get_tools_last_active()

Returns an integer indicating how long ago, expressed in seconds, the last heartbeat was detected from the VMware Tools service. This value is initialized to zero when the virtual machine powers on. It stays at zero until the first heartbeat is detected, after which it will always be non-zero until the virtual machine is power-cycled again.

When the guest operating system is lightly loaded, the service usually generates several heartbeats per second, causing the C<get_tools_last_active()>method to maintain a value of 1. If the guest operating system is heavily loaded, the value may occasionally reach several seconds. If the service stops running either because the guest operating system has experienced a failure, or is shutting down, the value will keep increasing.

A script can use the C<get_tools_last_active()> method to monitor when the VMware Tools service starts running, and once started, the health of the guest operating system. If the guest operating system has failed, the C<get_tools_last_active()> method indicates how long the guest has been down. The following table summarizes how the method values may be interpreted.

Value Meaning 

  0    The VMware Tools service hasn't started since power-on. 
  1    The service is running and healthy. 
  2-5  The service could be running, but the guest operating system may be heavily loaded or experiencing temporary problems. 
  > 5  The service stopped running, possibly because the guest operating system experienced a fatal failure, is restarting, or is shutting down. 

=head2 $vm->connect()

Establishes a connection with a virtual machine using the specified connectparams.

B<Syntax>

  $vm->connect($connectparams, $vm_name)

B<Parameters>

  $connectparams  [in] A VMware::VmPerl::ConnectParams object specifying the host and user information. 
  $vm_name        [in] A string specifying the virtual machine's configuration file name.  

B<Remarks>

No other methods may be called before a succesful call to Connect(). 

=head2 $vm->start()

Powers on a powered-off virtual machine, or resumes a suspended virtual machine. 

B<Syntax>

  $vm->start($mode) 

B<Parameters>

  $mode  [in] An enumeration specifying the operation's behavior. Can be one of the following:

     VM_POWEROP_MODE_HARD
        Immediately and unconditionally power on the virtual machine. 
   
     VM_POWEROP_MODE_SOFT
        Attempt to power on the virtual machine followed by executing the power-on script 
        in guest operating system. The operation fails if VMware Tools is not 
        running in the guest operating system or is out-of-date, in which case the virtual
        may be powered on but the script will not be run.
   
     VM_POWEROP_MODE_TRYSOFT
        Same meaning as VM_POWEROP_MODE_SOFT.

B<Remarks>

If the virtual machine is powered off, it is powered on. If it is suspended, this method resumes its execution. If the virtual machine is in another state, the method fails and throws an error. 

=head2 $vm->stop()

Shuts down and powers off a virtual machine.

B<Syntax>

  $vm->stop($mode)

B<Parameters>

  $mode  [in] An enumeration specifying the operation's behavior. Can be one of the following:

     VM_POWEROP_MODE_HARD
        Immediately and unconditionally power off or reset the virtual machine. 
   
     VM_POWEROP_MODE_SOFT
        Attempt to shutdown the virtual machine's guest operating system before powering 
        off or resetting the virtual machine. The operation fails if VMware Tools is not 
        running in the guest operating system. 
   
     VM_POWEROP_MODE_TRYSOFT
        First attempt a soft shutdown. If this fails, perform a hard power off or reset. 

B<Remarks>

This operation always fails if the virtual machine is not in the C<VMEXECUTIONSTATE_ON> state.

=head2 $vm->reset()

Shuts down, then reboots a virtual machine.

B<Syntax>

  $vm->reset($mode)

B<Parameters>

  $mode  [in] An enumeration specifying the operation's behavior. Refer to stop().

B<Remarks>

This operation always fails if the virtual machine is not in the C<VMEXECUTIONSTATE_ON> state.

=head2 $vm->suspend()

Suspends a virtual machine and saves its current state to disk.

B<Syntax>

  $vm->suspend($mode)

B<Parameters>

  $mode  [in] An enumeration specifying the operation's behavior. Can be one of the following:

     VM_POWEROP_MODE_HARD
        Immediately and unconditionally suspend the virtual machine. 
   
     VM_POWEROP_MODE_SOFT
        Attempt to run the suspend script in the guest operating system before suspending 
        the virtual machine's guest operating system. The operation fails if VMware Tools 
        is not running in the guest operating system or is out-of-date, in which case the
        guest operating system will remain powered on.
   
     VM_POWEROP_MODE_TRYSOFT
        First attempt a soft suspend. If this fails, perform a hard suspend. 

B<Remarks>

This operation always fails if the virtual machine is not in the C<VMEXECUTIONSTATE_ON> state.

=head2 $vm->answer_question()

Reply to a question. 

B<Syntax>

  $vm->answer_question($question, $choice) 

B<Parameters>

  $question [in] A VMware::VmPerl::Question object representing the question to answer. 
  $choice   [in] The zero-based index of the selected answer to the question. 

B<Remarks>

When a virtual machine is in the C<VM_EXECUTION_STATE_STUCK> state and requires user input in order to make forward progress, use this method to answer the current question or dismiss the current error message. First, get a C<VMware::VmPerl::Question> object from the C<VMware::VmPerl::VM> object's C<get_pending_question> method. The possible choices and their respective indices can be retrieved from the C<VMware::VmPerl::Question> object's C<choices> method. Then, use this method to answer the question. 

=head2 $vm->connect_device()

Sets a virtual device to the connected state.

B<Syntax>

  $vm->connect_device($dev_name)

B<Parameters>

  $devName  [in] A string identifying the virtual device to connect. 

B<Remarks>

The config() method may be used to set configuration parameters relevant to the specific device before calling C<connect()>. The following code example connects a virtual drive to a CD image file:

  $vm->set_config("ide1:0.type", "file");
  $vm->set_config("ide1:0.file", "/tmp/cdimages/foo.iso");
  $vm->connect_device("ide1:0");

=head2 $vm->disconnect_device()

Sets a virtual device to the disconnected state.

B<Syntax>

  $vm->disconnect_device($dev_name)

B<Parameters>

  $devName  [in] A string identifying the virtual device to disconnect. 

B<Remarks>

None.

=head2 $vm->get_last_error()

Obtain details about the last error that occurred.

B<Returns>

An array of ($error_num, $error_string).

=head1 AUTHORS

Jeff Hu, Vui-Chiap Lam, Bich Le

=head1 COPYRIGHT

    (c) 2002 VMware Incorporated.  All rights reserved.

=head1 VERSION

Version 1.01	   29 Mar 2002

C<% pod2html --header --title="VMware::VmPerl::VM" E<lt> VM.pm E<gt> VM.html>

=head1 SEE ALSO

perl(1).

=cut
