Author: arkurth Date: Wed Aug 3 18:43:06 2011 New Revision: 1153606 URL: http://svn.apache.org/viewvc?rev=1153606&view=rev Log: VCL-350 Added snapshot support to the VMware code. Added VMware.pm::snapshot() subroutine and create_snapshot subroutines in the helper modules.
Changed default virtual disk mode to persistent instead of independent-persistent or independent-nonpersistent. A snapshot is created after the VM is registered but before it is powered on. This causes changes to be written to a delta file in the directory where the vmx resides. This eliminates the need to create a full copy of the vmdk for imaging and long-term reservations. Imaging and long-term reservations now use this mode. A full copy of the vmdk is only created for server requests. Added DataStructure.pm::is_server_request subroutine to tell if a request is a server request or not. Changed all things named nonpersistent to shared, and persistent to dedicated to avoid confusion. Other Added some missing block request values to DataStructure.pm. Modified: incubator/vcl/trunk/managementnode/lib/VCL/DataStructure.pm incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VIM_SSH.pm incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VMware.pm incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/vSphere_SDK.pm incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/vmware_cmd.pm incubator/vcl/trunk/managementnode/lib/VCL/utils.pm Modified: incubator/vcl/trunk/managementnode/lib/VCL/DataStructure.pm URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/DataStructure.pm?rev=1153606&r1=1153605&r2=1153606&view=diff ============================================================================== --- incubator/vcl/trunk/managementnode/lib/VCL/DataStructure.pm (original) +++ incubator/vcl/trunk/managementnode/lib/VCL/DataStructure.pm Wed Aug 3 18:43:06 2011 @@ -105,7 +105,7 @@ $SUBROUTINE_MAPPINGS{blockrequest_name} $SUBROUTINE_MAPPINGS{blockrequest_image_id} = '$self->blockrequest_data->{BLOCKREQUEST_ID}{imageid}'; $SUBROUTINE_MAPPINGS{blockrequest_number_machines} = '$self->blockrequest_data->{BLOCKREQUEST_ID}{numMachines}'; $SUBROUTINE_MAPPINGS{blockrequest_group_id} = '$self->blockrequest_data->{BLOCKREQUEST_ID}{groupid}'; -$SUBROUTINE_MAPPINGS{blockrequest_group_name} = '$self->blockrequest_data->{BLOCKREQUEST_ID}{groupname}'; +$SUBROUTINE_MAPPINGS{blockrequest_group_name} = '$self->blockrequest_data->{BLOCKREQUEST_ID}{usergroup}{name}'; $SUBROUTINE_MAPPINGS{blockrequest_repeating} = '$self->blockrequest_data->{BLOCKREQUEST_ID}{repeating}'; $SUBROUTINE_MAPPINGS{blockrequest_owner_id} = '$self->blockrequest_data->{BLOCKREQUEST_ID}{ownerid}'; $SUBROUTINE_MAPPINGS{blockrequest_admin_group_id} = '$self->blockrequest_data->{BLOCKREQUEST_ID}{admingroupid}'; @@ -114,6 +114,13 @@ $SUBROUTINE_MAPPINGS{blockrequest_expire $SUBROUTINE_MAPPINGS{blockrequest_processing} = '$self->blockrequest_data->{BLOCKREQUEST_ID}{processing}'; $SUBROUTINE_MAPPINGS{blockrequest_mode} = '$self->blockrequest_data->{BLOCKREQUEST_ID}{MODE}'; +$SUBROUTINE_MAPPINGS{blockrequest_blocktimes_id} = '$self->blockrequest_data->{BLOCKREQUEST_ID}{BLOCKTIMES_ID}'; + +$SUBROUTINE_MAPPINGS{blockrequest_owner_email} = '$self->blockrequest_data->{BLOCKREQUEST_ID}{owner}{email}'; +$SUBROUTINE_MAPPINGS{blockrequest_owner_affiliation_helpaddress} = '$self->blockrequest_data->{BLOCKREQUEST_ID}{owner}{affiliation}{helpaddress}'; + +$SUBROUTINE_MAPPINGS{blockrequest_image_prettyname} = '$self->blockrequest_data->{BLOCKREQUEST_ID}{image}{prettyname}'; + $SUBROUTINE_MAPPINGS{blocktime_id} = '$self->blockrequest_data->{BLOCKREQUEST_ID}{blockTimes}{BLOCKTIME_ID}{id}'; #$SUBROUTINE_MAPPINGS{blocktime_blockrequest_id} = '$self->blockrequest_data->{BLOCKREQUEST_ID}{blockTimes}{BLOCKTIME_ID}{blockRequestid}'; $SUBROUTINE_MAPPINGS{blocktime_start} = '$self->blockrequest_data->{BLOCKREQUEST_ID}{blockTimes}{BLOCKTIME_ID}{start}'; @@ -230,6 +237,7 @@ $SUBROUTINE_MAPPINGS{computer_provisioni $SUBROUTINE_MAPPINGS{vmhost_computer_id} = '$self->request_data->{reservation}{RESERVATION_ID}{computer}{vmhost}{computerid}'; $SUBROUTINE_MAPPINGS{vmhost_hostname} = '$self->request_data->{reservation}{RESERVATION_ID}{computer}{vmhost}{computer}{hostname}'; +$SUBROUTINE_MAPPINGS{vmhost_short_name} = '$self->request_data->{reservation}{RESERVATION_ID}{computer}{vmhost}{computer}{SHORTNAME}'; $SUBROUTINE_MAPPINGS{vmhost_id} = '$self->request_data->{reservation}{RESERVATION_ID}{computer}{vmhost}{id}'; $SUBROUTINE_MAPPINGS{vmhost_image_id} = '$self->request_data->{reservation}{RESERVATION_ID}{computer}{vmhost}{vmprofile}{imageid}'; $SUBROUTINE_MAPPINGS{vmhost_image_name} = '$self->request_data->{reservation}{RESERVATION_ID}{computer}{vmhost}{vmprofile}{image}{name}'; @@ -2132,6 +2140,29 @@ sub is_blockrequest { #///////////////////////////////////////////////////////////////////////////// +=head2 is_server_request + + Parameters : None. + Returns : + Description : This subroutine determines whether or not the DataStructure + contains data for a server request. + +=cut + +sub is_server_request { + my $self = shift; + + # Check if subroutine was called as an object method + unless (ref($self) && $self->isa('VCL::DataStructure')) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine can only be called as a VCL::DataStructure module object method"); + return; + } + + return $self->get_server_request_id() ? 1 : 0; +} + +#///////////////////////////////////////////////////////////////////////////// + =head2 get_management_node_public_default_gateway Parameters : None Modified: incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VIM_SSH.pm URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VIM_SSH.pm?rev=1153606&r1=1153605&r2=1153606&view=diff ============================================================================== --- incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VIM_SSH.pm (original) +++ incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/VMware/VIM_SSH.pm Wed Aug 3 18:43:06 2011 @@ -1666,6 +1666,131 @@ sub get_network_names { #///////////////////////////////////////////////////////////////////////////// +=head2 create_snapshot + + Parameters : $vmx_file_path, $name (optional) + 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 $snapshot_name = shift || ("VCL: " . convert_to_datetime()); + + # Get the VM ID + my $vm_id = $self->_get_vm_id($vmx_file_path); + if (!defined($vm_id)) { + notify($ERRORS{'WARNING'}, 0, "unable to create snapshot because VM ID could not be determined"); + return; + } + + my $vim_cmd_arguments = "vmsvc/snapshot.create $vm_id '$snapshot_name'"; + my ($exit_status, $output) = $self->_run_vim_cmd($vim_cmd_arguments); + return if !$output; + + notify($ERRORS{'DEBUG'}, 0, "create snapshot output:\n" . join("\n", @$output)); + + if (grep(/failed|invalid/i, @$output)) { + notify($ERRORS{'WARNING'}, 0, "failed to create snapshot of VM $vmx_file_path, VIM command arguments: '$vim_cmd_arguments', output:\n" . join("\n", @$output)); + return; + } + + # Get the task ID + my @task_ids = $self->_get_task_ids($vmx_file_path, 'createSnapshot'); + if (!@task_ids) { + notify($ERRORS{'WARNING'}, 0, "unable to retrieve the ID of the task created to create snapshot"); + return; + } + + # Wait for the task to complete + if ($self->_wait_for_task($task_ids[0])) { + notify($ERRORS{'OK'}, 0, "created snapshot of VM: $vmx_file_path, snapshot name: $snapshot_name"); + return 1; + } + else { + notify($ERRORS{'WARNING'}, 0, "failed to create snapshot VM: $vmx_file_path, the vim task did not complete successfully, vim-cmd $vim_cmd_arguments output:\n" . join("\n", @$output)); + return; + } +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 snapshot_exists + + Parameters : $vmx_file_path + Returns : boolean + Description : Determines if a snapshot exists for the VM. + +=cut + +sub snapshot_exists { + 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; + } + + # Get the VM ID + my $vm_id = $self->_get_vm_id($vmx_file_path); + if (!defined($vm_id)) { + notify($ERRORS{'WARNING'}, 0, "unable to determine if snapshot exists because VM ID could not be determined"); + return; + } + + my $vim_cmd_arguments = "vmsvc/snapshot.get $vm_id"; + my ($exit_status, $output) = $self->_run_vim_cmd($vim_cmd_arguments); + return if !$output; + + notify($ERRORS{'DEBUG'}, 0, "snapshot.get output:\n" . join("\n", @$output)); + + if (grep(/failed|invalid/i, @$output)) { + notify($ERRORS{'WARNING'}, 0, "failed to determine if snapshot exists for VM $vmx_file_path, VIM command arguments: '$vim_cmd_arguments', output:\n" . join("\n", @$output)); + return; + } + + # Expected output if shapshot exists: + # Get Snapshot: + # |-ROOT + # --Snapshot Name : 1311966951 + # --Snapshot Desciption : + # --Snapshot Created On : 7/29/2011 19:15:59 + # --Snapshot State : powered off + + # Expected output if snapshot does not exist: + # Get Snapshot: + + if (grep(/-ROOT/, @$output)) { + notify($ERRORS{'DEBUG'}, 0, "snapshot exists for VM $vmx_file_path"); + return 1; + } + else { + notify($ERRORS{'DEBUG'}, 0, "snapshot does NOT exist for VM $vmx_file_path"); + return 0; + } +} + +#///////////////////////////////////////////////////////////////////////////// + =head2 DESTROY Parameters : none