blob: 24e4559bb1b4e86b9e800efb27b9d7990ad4006a [file] [log] [blame]
#!/usr/bin/perl -w
###############################################################################
# $Id$
###############################################################################
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
###############################################################################
=head1 NAME
VCL::Module::Provisioning::VMware::vmware_cmd;
=head1 SYNOPSIS
my $vmhost_datastructure = $self->get_vmhost_datastructure();
my $vmware_cmd = VCL::Module::Provisioning::VMware::vmware_cmd->new({data_structure => $vmhost_datastructure});
my @registered_vms = $vmware_cmd->get_registered_vms();
=head1 DESCRIPTION
This module provides support for VMs to be controlled using VMware Server 1.x's
vmware-cmd command via SSH.
=cut
###############################################################################
package VCL::Module::Provisioning::VMware::vmware_cmd;
# Specify the lib path using FindBin
use FindBin;
use lib "$FindBin::Bin/../../../..";
# Configure inheritance
use base qw(VCL::Module::Provisioning::VMware::VMware);
# Specify the version of this module
our $VERSION = '2.5';
# Specify the version of Perl to use
use 5.008000;
use strict;
use warnings;
use diagnostics;
use VCL::utils;
###############################################################################
=head1 PRIVATE OBJECT METHODS
=cut
#//////////////////////////////////////////////////////////////////////////////
=head2 initialize
Parameters : none
Returns : boolean
Description : Initializes the vmware_cmd object by by checking if vmware-cmd is
available on the VM host.
=cut
sub initialize {
my $self = shift;
if (ref($self) !~ /VCL::Module/i) {
notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
return;
}
my $args = shift;
# Check to make sure the VM host OS object is available
if (!defined $args->{vmhost_os}) {
notify($ERRORS{'WARNING'}, 0, "required 'vmhost_os' argument was not passed");
return;
}
elsif (ref $args->{vmhost_os} !~ /VCL::Module::OS/) {
notify($ERRORS{'CRITICAL'}, 0, "'vmhost_os' argument passed is not a reference to a VCL::Module::OS object, type: " . ref($args->{vmhost_os}));
return;
}
# Store a reference to the VM host OS object in this object
$self->{vmhost_os} = $args->{vmhost_os};
# Check if vmware-cmd is available on the VM host
my $command = 'vmware-cmd';
my ($exit_status, $output) = $self->vmhost_os->execute($command);
if (!defined($output)) {
notify($ERRORS{'WARNING'}, 0, "failed to run SSH command to determine if vmware-cmd is available on the VM host");
return;
}
elsif (grep(/not found/i, @$output)) {
notify($ERRORS{'DEBUG'}, 0, "vmware-cmd is not available on the VM host, output:\n" . join("\n", @$output));
return;
}
else {
notify($ERRORS{'DEBUG'}, 0, "vmware-cmd is available on VM host");
}
notify($ERRORS{'DEBUG'}, 0, ref($self) . " object initialized");
return 1;
}
#//////////////////////////////////////////////////////////////////////////////
=head2 _run_vmware_cmd
Parameters : $vmware_cmd_arguments
Returns : array ($exit_status, $output)
Description : Runs vmware-cmd on the VMware host.
=cut
sub _run_vmware_cmd {
my $self = shift;
if (ref($self) !~ /VCL::Module/i) {
notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
return;
}
my $vmware_cmd_arguments = shift;
if (!$vmware_cmd_arguments) {
notify($ERRORS{'WARNING'}, 0, "vmware-cmd arguments were not specified");
return;
}
my $vmhost_computer_name = $self->vmhost_os->data->get_computer_short_name();
my $command = "vmware-cmd $vmware_cmd_arguments";
my ($exit_status, $output) = $self->vmhost_os->execute($command);
if (!defined($output)) {
notify($ERRORS{'WARNING'}, 0, "failed to run vmware-cmd on VM host $vmhost_computer_name: '$command'");
}
else {
#notify($ERRORS{'DEBUG'}, 0, "executed vmware-cmd on VM host $vmhost_computer_name: '$command'");
return ($exit_status, $output);
}
}
###############################################################################
=head1 API OBJECT METHODS
=cut
#//////////////////////////////////////////////////////////////////////////////
=head2 get_registered_vms
Parameters : none
Returns : array
Description : Returns an array containing the vmx file paths of the VMs running
on the VM host.
=cut
sub get_registered_vms {
my $self = shift;
if (ref($self) !~ /VCL::Module/i) {
notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
return;
}
# Run 'vmware-cmd -l'
my $vmware_cmd_arguments = "-l";
my ($exit_status, $output) = $self->_run_vmware_cmd($vmware_cmd_arguments);
return if !$output;
my @vmx_file_paths = grep(/^\//, @$output);
notify($ERRORS{'DEBUG'}, 0, "registered VMs found: " . scalar(@vmx_file_paths) . "\n" . join("\n", sort @vmx_file_paths));
return @vmx_file_paths;
}
#//////////////////////////////////////////////////////////////////////////////
=head2 get_vm_power_state
Parameters : $vmx_file_path
Returns : string
Description : Returns a string containing the power state of the VM indicated
by the vmx file path argument. The string returned may be one of
the following values:
on
off
suspended
=cut
sub get_vm_power_state {
my $self = shift;
if (ref($self) !~ /VCL::Module/i) {
notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
return;
}
# Get the vmx file path argument
my $vmx_file_path = shift;
if (!$vmx_file_path) {
notify($ERRORS{'WARNING'}, 0, "vmx file path argument was not supplied");
return;
}
my $vmx_file_name = $self->_get_file_name($vmx_file_path);
# Run 'vmware-cmd <cfg> getstate'
my $vmware_cmd_arguments = "\"$vmx_file_path\" getstate";
my ($exit_status, $output) = $self->_run_vmware_cmd($vmware_cmd_arguments);
return if !$output;
# The output should look like this:
# getstate() = off
my $vm_power_state;
if (grep(/=\s*on/i, @$output)) {
$vm_power_state = 'on';
}
elsif (grep(/=\s*off/i, @$output)) {
$vm_power_state = 'off';
}
elsif (grep(/=\s*suspended/i, @$output)) {
$vm_power_state = 'suspended';
}
else {
notify($ERRORS{'WARNING'}, 0, "unexpected output returned while attempting to determine power state of '$vmx_file_path', vmware-cmd arguments: '$vmware_cmd_arguments' output:\n" . join("\n", @$output));
return;
}
notify($ERRORS{'DEBUG'}, 0, "power state of VM '$vmx_file_name': $vm_power_state");
return $vm_power_state;
}
#//////////////////////////////////////////////////////////////////////////////
=head2 vm_power_on
Parameters : $vmx_file_path
Returns : boolean
Description : Powers on the VM indicated by the vmx file path argument.
=cut
sub vm_power_on {
my $self = shift;
if (ref($self) !~ /VCL::Module/i) {
notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
return;
}
# Get the vmx file path argument
my $vmx_file_path = shift;
if (!$vmx_file_path) {
notify($ERRORS{'WARNING'}, 0, "vmx file path argument was not supplied");
return;
}
my $vmx_file_name = $self->_get_file_name($vmx_file_path);
my $vmware_cmd_arguments = "\"$vmx_file_path\" start";
my ($exit_status, $output) = $self->_run_vmware_cmd($vmware_cmd_arguments);
return if !$output;
# Expected output if the VM was not previously powered on:
# start() = 1
# Expected output if the VM was previously powered on:
# VMControl error -8: Invalid operation for virtual machine's current state:
# The requested operation ("start") could not be completed because it
# conflicted with the state of the virtual machine ("on") at the time the
# request was received. This error often occurs because the state of the
# virtual machine changed before it received the request.
# Expected output if the VM is not registered: /usr/bin/vmware-cmd: Could not
# connect to VM /var/lib/vmware/Virtual Machines/Windows XP
# Professional/Windows XP Professional.vmx
# (VMControl error -11: No such virtual machine: The config file
# /var/lib/vmware/Virtual Machines/Windows XP Professional/Windows XP
# Professional.vmx is not registered.
# Please register the config file on the server. For example: vmware-cmd -s
# register "/var/lib/vmware/Virtual Machines/Windows XP Professional/Windows
# XP Professional.vmx")
if (grep(/\(\"on\"\)/i, @$output)) {
notify($ERRORS{'OK'}, 0, "VM is already powered on: '$vmx_file_name'");
return 1;
}
elsif (grep(/=\s*1/i, @$output)) {
notify($ERRORS{'OK'}, 0, "powered on VM: '$vmx_file_name'");
return 1;
}
elsif (grep(/error -11/i, @$output)) {
notify($ERRORS{'WARNING'}, 0, "unable to power on VM because it is not registered: '$vmx_file_path'");
return;
}
else {
notify($ERRORS{'WARNING'}, 0, "unexpected output returned while attempting to power on VM '$vmx_file_path', vmware-cmd arguments: '$vmware_cmd_arguments', output:\n" . join("\n", @$output));
return;
}
}
#//////////////////////////////////////////////////////////////////////////////
=head2 vm_power_off
Parameters : $vmx_file_path
Returns : boolean
Description : Powers off the VM indicated by the vmx file path argument.
=cut
sub vm_power_off {
my $self = shift;
if (ref($self) !~ /VCL::Module/i) {
notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
return;
}
# Get the vmx file path argument
my $vmx_file_path = shift;
if (!$vmx_file_path) {
notify($ERRORS{'WARNING'}, 0, "vmx file path argument was not supplied");
return;
}
my $vmx_file_name = $self->_get_file_name($vmx_file_path);
my $vmware_cmd_arguments = "\"$vmx_file_path\" stop hard";
my ($exit_status, $output) = $self->_run_vmware_cmd($vmware_cmd_arguments);
return if !$output;
# Expected output if the VM was not previously powered on:
# stop(hard) = 1
# Expected output if the VM was previously powered on: VMControl error -8:
# Invalid operation for virtual machine's current state: The requested
# operation ("stop") could not be completed because it conflicted with the
# state of the virtual machine ("off") at the time the request was received.
# This error often occurs because the state of the virtual machine changed
# before it received the request.
# Expected output if the VM is not registered: /usr/bin/vmware-cmd: Could not
# connect to VM /var/lib/vmware/Virtual Machines/Windows XP
# Professional/Windows XP Professional.vmx
# (VMControl error -11: No such virtual machine: The config file
# /var/lib/vmware/Virtual Machines/Windows XP Professional/Windows XP
# Professional.vmx is not registered.
# Please register the config file on the server. For example: vmware-cmd -s
# register "/var/lib/vmware/Virtual Machines/Windows XP Professional/Windows
# XP Professional.vmx")
if (grep(/\(\"off\"\)/i, @$output)) {
notify($ERRORS{'OK'}, 0, "VM is already powered off: '$vmx_file_name'");
return 1;
}
elsif (grep(/=\s*1/i, @$output)) {
notify($ERRORS{'OK'}, 0, "powered off VM: '$vmx_file_name'");
return 1;
}
elsif (grep(/error -11/i, @$output)) {
notify($ERRORS{'WARNING'}, 0, "unable to power off VM because it is not registered: '$vmx_file_path'");
return;
}
else {
notify($ERRORS{'WARNING'}, 0, "unexpected output returned while attempting to power off VM '$vmx_file_path', vmware-cmd arguments: '$vmware_cmd_arguments', output:\n" . join("\n", @$output));
return;
}
}
#//////////////////////////////////////////////////////////////////////////////
=head2 vm_register
Parameters : $vmx_file_path
Returns : boolean
Description : Registers the VM indicated by the vmx file path argument.
=cut
sub vm_register {
my $self = shift;
if (ref($self) !~ /VCL::Module/i) {
notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
return;
}
# Get the vmx file path argument
my $vmx_file_path = shift;
if (!$vmx_file_path) {
notify($ERRORS{'WARNING'}, 0, "vmx file path argument was not supplied");
return;
}
my $vmx_file_name = $self->_get_file_name($vmx_file_path);
my $vmware_cmd_arguments = "-s register \"$vmx_file_path\"";
my ($exit_status, $output) = $self->_run_vmware_cmd($vmware_cmd_arguments);
return if !$output;
# Expected output if the VM is already registered:
# VMControl error -20: Virtual machine already exists
# Expected output if the VM is successfully registered:
# register(<vmx path>) = 1
if (grep(/error -20/i, @$output)) {
notify($ERRORS{'OK'}, 0, "VM is already registered: '$vmx_file_name'");
return 1;
}
elsif (grep(/=\s*1/i, @$output)) {
notify($ERRORS{'OK'}, 0, "registered VM: '$vmx_file_name'");
return 1;
}
else {
notify($ERRORS{'WARNING'}, 0, "unexpected output returned while attempting to register VM '$vmx_file_path', vmware-cmd arguments: '$vmware_cmd_arguments', output:\n" . join("\n", @$output));
return;
}
}
#//////////////////////////////////////////////////////////////////////////////
=head2 vm_unregister
Parameters : $vmx_file_path
Returns : boolean
Description : Unregisters the VM indicated by the vmx file path argument.
=cut
sub vm_unregister {
my $self = shift;
if (ref($self) !~ /VCL::Module/i) {
notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
return;
}
# Get the vmx file path argument
my $vmx_file_path = shift;
if (!$vmx_file_path) {
notify($ERRORS{'WARNING'}, 0, "vmx file path argument was not supplied");
return;
}
my $vmx_file_name = $self->_get_file_name($vmx_file_path);
# Check if the VM is not registered
if (!$self->is_vm_registered($vmx_file_path)) {
notify($ERRORS{'OK'}, 0, "VM not unregistered because it is not registered: '$vmx_file_name'");
return 1;
}
# Power off the VM if it is on
my $vm_power_state = $self->get_vm_power_state($vmx_file_path) || '';
if ($vm_power_state =~ /on/i && !$self->vm_power_off($vmx_file_path)) {
notify($ERRORS{'WARNING'}, 0, "failed to power off VM before unregistering it: '$vmx_file_name', VM power state: $vm_power_state");
return;
}
my $vmware_cmd_arguments = "-s unregister \"$vmx_file_path\"";
my ($exit_status, $output) = $self->_run_vmware_cmd($vmware_cmd_arguments);
return if !$output;
# Expected output if the VM is not registered:
# VMControl error -11: No such virtual machine
# Expected output if the VM is successfully unregistered:
# unregister(<vmx path>) = 1
if (grep(/error -11/i, @$output)) {
notify($ERRORS{'OK'}, 0, "VM is not registered: '$vmx_file_name'");
}
elsif (grep(/=\s*1/i, @$output)) {
notify($ERRORS{'OK'}, 0, "unregistered VM: '$vmx_file_name'");
}
else {
notify($ERRORS{'WARNING'}, 0, "unexpected output returned while attempting to unregister VM '$vmx_file_path', vmware-cmd arguments: '$vmware_cmd_arguments', output:\n" . join("\n", @$output));
return;
}
# Make sure the VM is not registered
if ($self->is_vm_registered($vmx_file_path)) {
notify($ERRORS{'WARNING'}, 0, "failed to unregister VM, it appears to still be registered: '$vmx_file_path'");
return;
}
return 1;
}
#//////////////////////////////////////////////////////////////////////////////
=head2 get_virtual_disk_controller_type
Parameters : $vmdk_file_path
Returns :
Description : Retrieves the disk controller type configured for the virtual
disk specified by the vmdk file path argument. A string is
returned containing one of the following values:
-ide
-buslogic
-lsilogic
=cut
sub get_virtual_disk_controller_type {
my $self = shift;
if (ref($self) !~ /VCL::Module/i) {
notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
return;
}
# Get the vmdk file path argument
my $vmdk_file_path = shift;
if (!$vmdk_file_path) {
notify($ERRORS{'WARNING'}, 0, "vmdk file path argument was not supplied");
return;
}
my $vmdk_file_name = $self->_get_file_name($vmdk_file_path);
my $vmhost_computer_name = $self->vmhost_os->data->get_computer_short_name();
my $command = "grep -i adapterType \"$vmdk_file_path\"";
my ($exit_status, $output) = $self->vmhost_os->execute($command);
if (!defined($output)) {
notify($ERRORS{'WARNING'}, 0, "failed to run command on VM host $vmhost_computer_name: '$command'");
}
my ($adapter_type) = "@$output" =~ /adapterType\s*=\s*\"(\w+)\"/i;
if ($adapter_type) {
notify($ERRORS{'DEBUG'}, 0, "adapter type configured in '$vmdk_file_name': $adapter_type");
return $adapter_type;
}
else {
notify($ERRORS{'WARNING'}, 0, "unable to determine adapter type configured in '$vmdk_file_name', command: '$command', output:\n" . join("\n", @$output));
return;
}
}
#//////////////////////////////////////////////////////////////////////////////
=head2 get_virtual_disk_type
Parameters : $vmdk_file_path
Returns :
Description : Retrieves the disk type configured for the virtual
disk specified by the vmdk file path argument. A string is
returned containing one of the following values:
-monolithicSparse
-twoGbMaxExtentSparse
-monolithicFlat
-twoGbMaxExtentFlat
=cut
sub get_virtual_disk_type {
my $self = shift;
if (ref($self) !~ /VCL::Module/i) {
notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
return;
}
# Get the vmdk file path argument
my $vmdk_file_path = shift;
if (!$vmdk_file_path) {
notify($ERRORS{'WARNING'}, 0, "vmdk file path argument was not supplied");
return;
}
my $vmdk_file_name = $self->_get_file_name($vmdk_file_path);
my $vmhost_computer_name = $self->vmhost_os->data->get_computer_short_name();
my $command = "grep -i createType \"$vmdk_file_path\"";
my ($exit_status, $output) = $self->vmhost_os->execute($command);
if (!defined($output)) {
notify($ERRORS{'WARNING'}, 0, "failed to run command on VM host $vmhost_computer_name: '$command'");
}
my ($disk_type) = "@$output" =~ /createType\s*=\s*\"(\w+)\"/i;
if ($disk_type) {
notify($ERRORS{'DEBUG'}, 0, "disk type configured in '$vmdk_file_name': $disk_type");
return $disk_type;
}
else {
notify($ERRORS{'WARNING'}, 0, "unable to determine disk type configured in '$vmdk_file_name', command: '$command', output:\n" . join("\n", @$output));
return;
}
}
#//////////////////////////////////////////////////////////////////////////////
=head2 get_virtual_disk_hardware_version
Parameters : $vmdk_file_path
Returns : integer
Description : Retrieves the hardware version configured for the virtual
disk specified by the vmdk file path argument. False is returned
if the hardware version cannot be retrieved.
=cut
sub get_virtual_disk_hardware_version {
my $self = shift;
if (ref($self) !~ /VCL::Module/i) {
notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
return;
}
# Get the vmdk file path argument
my $vmdk_file_path = shift;
if (!$vmdk_file_path) {
notify($ERRORS{'WARNING'}, 0, "vmdk file path argument was not supplied");
return;
}
my $vmdk_file_name = $self->_get_file_name($vmdk_file_path);
my $vmhost_computer_name = $self->vmhost_os->data->get_computer_short_name();
my $command = "grep -i virtualHWVersion \"$vmdk_file_path\"";
my ($exit_status, $output) = $self->vmhost_os->execute($command);
if (!defined($output)) {
notify($ERRORS{'WARNING'}, 0, "failed to run command on VM host $vmhost_computer_name: '$command'");
}
my ($hardware_version) = "@$output" =~ /virtualHWVersion\s*=\s*\"(\w+)\"/i;
if (defined($hardware_version)) {
notify($ERRORS{'DEBUG'}, 0, "hardware version configured in '$vmdk_file_name': $hardware_version");
return $hardware_version;
}
else {
notify($ERRORS{'WARNING'}, 0, "unable to determine hardware version configured in '$vmdk_file_name', command: '$command', output:\n" . join("\n", @$output));
return;
}
}
#//////////////////////////////////////////////////////////////////////////////
=head2 _get_datastore_info
Parameters : none
Returns : hash reference
Description : Retrieves information about the VM host's datastore from the
/etc/vmware/config file and returns a hash containing the
information.
=cut
sub _get_datastore_info {
my $self = shift;
if (ref($self) !~ /VCL::Module/i) {
notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
return;
}
my $vmhost_profile_datastore_path = $self->data->get_vmhost_profile_datastore_path();
my $vmhost_profile_vmpath = $self->data->get_vmhost_profile_vmpath();
$vmhost_profile_datastore_path = normalize_file_path($vmhost_profile_datastore_path);
$vmhost_profile_vmpath = normalize_file_path($vmhost_profile_vmpath);
# Get the contents of the VMware config file
my $config_file_path = '/etc/vmware/config';
my $config_datastore_name;
my $config_datastore_path;
my @config_contents = $self->vmhost_os->get_file_contents($config_file_path);
if (@config_contents) {
notify($ERRORS{'DEBUG'}, 0, "retrieved contents of $config_file_path\n" . join("\n", @config_contents));
# Get the datastore name and path from the file contents
($config_datastore_name) = map { $_ =~ /datastore\.name\s*=\s*"([^"]+)"/ } @config_contents;
if (!$config_datastore_name) {
notify($ERRORS{'WARNING'}, 0, "failed to locate the 'datastore.name' line in $config_file_path");
}
($config_datastore_path) = map { $_ =~ /datastore\.localpath\s*=\s*"([^"]+)"/ } @config_contents;
if ($config_datastore_path) {
$config_datastore_path = normalize_file_path($config_datastore_path);
}
else {
notify($ERRORS{'WARNING'}, 0, "failed to locate the 'datastore.localpath' line in $config_file_path");
}
}
else {
notify($ERRORS{'WARNING'}, 0, "failed to retrieve the contents of $config_file_path");
}
# Create a hash containing datastore names and their paths
my %datastore_info;
# Keep track of paths added to returning %datastore_info hash so the same path isn't added more than once
my %datastore_paths;
# Add the datastore found in the config file
if (defined($config_datastore_name) && defined($config_datastore_path)) {
$datastore_info{$config_datastore_name}{normal_path} = $config_datastore_path;
$datastore_paths{$config_datastore_path} = 1;
};
# Add datastores for the VM host profile vmpath and datastore if they are different than what's in the config file
if (!defined($datastore_paths{$vmhost_profile_vmpath})) {
$datastore_info{'vmprofile-vmpath'}{normal_path} = $vmhost_profile_vmpath;
$datastore_paths{$vmhost_profile_vmpath} = 1;
}
if (!defined($datastore_paths{$vmhost_profile_datastore_path})) {
$datastore_info{'vmprofile-datastore'}{normal_path} = $vmhost_profile_datastore_path;
$datastore_paths{$vmhost_profile_vmpath} = 1;
}
# Construct a hash containing
for my $datastore_name (keys %datastore_info) {
my $datastore_path = $datastore_info{$datastore_name}{normal_path};
$datastore_info{$datastore_name}{accessible} = 'true';
$datastore_info{$datastore_name}{type} = 'local';
$datastore_info{$datastore_name}{url} = $datastore_path;
my $available_space = $self->vmhost_os->get_available_space($datastore_path);
if (defined($available_space)) {
$datastore_info{$datastore_name}{freeSpace} = $available_space;
}
else {
notify($ERRORS{'WARNING'}, 0, "failed to determine the amount of space available in datastore '$datastore_name' ($datastore_path)");
}
my $total_space = $self->vmhost_os->get_total_space($datastore_path);
if (defined($total_space)) {
$datastore_info{$datastore_name}{capacity} = $total_space;
}
else {
notify($ERRORS{'WARNING'}, 0, "failed to determine the total amount of space of the volume where datastore '$datastore_name' ($datastore_path) resides");
}
}
notify($ERRORS{'DEBUG'}, 0, "retrieved datastore info:\n" . format_data(\%datastore_info));
return \%datastore_info;
}
#//////////////////////////////////////////////////////////////////////////////
=head2 create_snapshot
Parameters : $vmx_file_path
Returns : boolean
Description : Creates a snapshot of the VM.
=cut
sub create_snapshot {
my $self = shift;
if (ref($self) !~ /VCL::Module/i) {
notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
return;
}
# Get the vmx file path argument
my $vmx_file_path = shift;
if (!$vmx_file_path) {
notify($ERRORS{'WARNING'}, 0, "vmx file path argument was not supplied");
return;
}
my $command = "vmrun snapshot \"$vmx_file_path\"";
my ($exit_status, $output) = $self->vmhost_os->execute($command, 1);
if (!defined($output)) {
notify($ERRORS{'WARNING'}, 0, "failed to execute vmrun to create a snapshot of VM: $vmx_file_path, command: '$command'");
return;
}
elsif ($exit_status != 0 || grep(/error/i, @$output)) {
notify($ERRORS{'WARNING'}, 0, "error occurred executing vmrun to create a snapshot of VM: $vmx_file_path, command: '$command', output:\n" . join("\n", @$output));
return;
}
else {
notify($ERRORS{'OK'}, 0, "created snapshot of VM: $vmx_file_path, output:\n" . join("\n", @$output));
return 1;
}
}
#//////////////////////////////////////////////////////////////////////////////
1;
__END__
=head1 SEE ALSO
L<http://cwiki.apache.org/VCL/>
=cut