in managementnode/lib/VCL/Module/Provisioning/libvirt.pm [353:557]
sub capture {
my $self = shift;
unless (ref($self) && $self->isa('VCL::Module')) {
notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
return;
}
my $old_image_name = $self->data->get_image_name();
# Construct the new image name
my $new_image_name = $self->get_new_image_name();
$self->data->set_image_name($new_image_name);
my $request_state_name = $self->data->get_request_state_name();
my $image_id = $self->data->get_image_id();
my $imagerevision_id = $self->data->get_imagerevision_id();
my $image_type = $self->data->get_imagetype_name();
my $node_name = $self->data->get_vmhost_short_name();
my $computer_name = $self->data->get_computer_short_name();
my $master_image_directory_path = $self->get_master_image_directory_path();
my $master_image_file_path = $self->get_master_image_file_path();
my $datastore_image_type = $self->data->get_vmhost_datastore_imagetype_name();
my $repository_image_directory_path = $self->get_repository_image_directory_path();
my $repository_image_file_path = $self->get_repository_image_file_path();
my $repository_image_type = $self->data->get_vmhost_repository_imagetype_name();
# Set the imagemeta Sysprep value to 0 to prevent Sysprep from being used
$self->data->set_imagemeta_sysprep(0);
# Get the domain name
my $domain_name = $self->get_domain_name();
if (!$domain_name) {
notify($ERRORS{'WARNING'}, 0, "unable to capture image on $node_name, domain name could not be determined");
return;
}
notify($ERRORS{'DEBUG'}, 0, "beginning image capture:\n" . <<EOF
image id: $image_id
imagerevision id: $imagerevision_id
old image name: $old_image_name
new image name: $new_image_name
---
host node: $node_name
computer: $computer_name
---
master image directory path: $master_image_directory_path
master image file path: $master_image_file_path
---
old image type: $image_type
datastore image type: $datastore_image_type
---
repository image type: $repository_image_type
repository image directory path: $repository_image_directory_path
repository image file path: $repository_image_file_path
EOF
);
# Call the OS module's pre_capture() subroutine
if ($self->os->can("pre_capture") && !$self->os->pre_capture({end_state => 'on'})) {
notify($ERRORS{'WARNING'}, 0, "failed to complete OS module's pre_capture tasks");
return;
}
# Check the power status before proceeding
my $power_status = $self->power_status();
if (!$power_status) {
notify($ERRORS{'WARNING'}, 0, "unable to capture image on $node_name, power status of '$domain_name' domain could not be determined");
return;
}
elsif ($power_status !~ /on/i) {
notify($ERRORS{'WARNING'}, 0, "unable to capture image on $node_name, power status of '$domain_name' domain is $power_status");
return;
}
# Make sure the master image file doesn't already exist
if ($self->vmhost_os->file_exists($master_image_file_path)) {
notify($ERRORS{'WARNING'}, 0, "master image file already exists on $node_name: $master_image_file_path");
return;
}
# Make sure the repository image file doesn't already exist if the repository path is configured
if ($repository_image_file_path && $self->vmhost_os->file_exists($repository_image_file_path)) {
notify($ERRORS{'WARNING'}, 0, "repository image file already exists on $node_name: $repository_image_file_path");
return;
}
# Get the domain XML definition
my $domain_xml_string = $self->get_domain_xml_string($domain_name);
if (!$domain_xml_string) {
notify($ERRORS{'WARNING'}, 0, "failed to capture image on $node_name, unable to retrieve domain XML definition: $domain_name");
return;
}
# Delete existing XML definition files
$self->os->delete_file("~/*-v*.xml");
# Save the domain XML definition to a file in the image
my $image_xml_file_path = "~/$new_image_name.xml";
if ($self->os->create_text_file($image_xml_file_path, $domain_xml_string)) {
notify($ERRORS{'OK'}, 0, "saved domain XML definition text file in image: $image_xml_file_path");
}
else {
notify($ERRORS{'WARNING'}, 0, "failed to capture image on $node_name, unable to save domain XML definition text file in image: $image_xml_file_path, contents:\n$domain_xml_string");
return;
}
# Save the domain XML definition to a file in the master image directory
my $master_xml_file_path = $self->get_master_xml_file_path();
if ($self->vmhost_os->create_text_file($master_xml_file_path, $domain_xml_string)) {
notify($ERRORS{'OK'}, 0, "saved domain XML definition text file to master image directory: $master_xml_file_path");
}
else {
notify($ERRORS{'WARNING'}, 0, "failed to capture image on $node_name, unable to save domain XML definition text file: $master_xml_file_path");
return;
}
# Update the image name in the database
if ($old_image_name ne $new_image_name && !update_image_name($image_id, $imagerevision_id, $new_image_name)) {
notify($ERRORS{'WARNING'}, 0, "failed to update image name in the database: $old_image_name --> $new_image_name");
return;
}
# Update the image type in the database to the datastore image type
if ($image_type ne $datastore_image_type && !update_image_type($image_id, $datastore_image_type)) {
notify($ERRORS{'WARNING'}, 0, "failed to update image type in the database: $image_type --> $datastore_image_type");
return;
}
# Shutdown domain
if (!$self->os->shutdown()) {
notify($ERRORS{'WARNING'}, 0, "$domain_name has not powered off after the OS module's pre_capture tasks were completed, powering off forcefully");
if (!$self->power_off($domain_name)) {
notify($ERRORS{'WARNING'}, 0, "failed to power off $domain_name after the OS module's pre_capture tasks were completed");
return;
}
}
# Get the disk file paths from the domain definition
my @disk_file_paths = $self->get_domain_disk_file_paths($domain_name);
if (scalar @disk_file_paths == 0) {
notify($ERRORS{'WARNING'}, 0, "did not find any disks defined in the XML definition for $domain_name:\n" . format_data($domain_name));
return;
}
elsif (scalar @disk_file_paths > 1) {
notify($ERRORS{'WARNING'}, 0, "found multiple disks defined in the XML definition for $domain_name, only the first disk will be captured:\n" . format_data(\@disk_file_paths));
}
# Copy the linked clone to create a new master image file
my $linked_clone_file_path = $disk_file_paths[0];
notify($ERRORS{'DEBUG'}, 0, "retrieved linked clone file path from domain $domain_name: $linked_clone_file_path");
if ($self->driver->can('copy_virtual_disk')) {
# Get a semaphore so that multiple processes don't try to copy/access the image at the same time
# Since this is a new image, should get semaphore on 1st try
if (my $semaphore = $self->get_master_image_semaphore()) {
if ($self->driver->copy_virtual_disk($linked_clone_file_path, $master_image_file_path, $datastore_image_type)) {
notify($ERRORS{'DEBUG'}, 0, "created master image from linked clone: $linked_clone_file_path --> $master_image_file_path");
}
else {
notify($ERRORS{'WARNING'}, 0, "failed to create master image from linked clone: $linked_clone_file_path --> $master_image_file_path");
return;
}
}
else {
notify($ERRORS{'WARNING'}, 0, "failed to capture image on $node_name, unable to obtain semaphore before creating master image from linked clone: $linked_clone_file_path --> $master_image_file_path");
return;
}
# Copy the master image to the repository if the repository path is configured in the VM host profile
if ($repository_image_file_path) {
if (my $semaphore = $self->get_repository_image_semaphore()) {
if ($self->driver->copy_virtual_disk($master_image_file_path, $repository_image_file_path, $repository_image_type)) {
notify($ERRORS{'DEBUG'}, 0, "created repository image from master image: $master_image_file_path --> $repository_image_file_path");
}
else {
notify($ERRORS{'WARNING'}, 0, "failed to create repository image from master image: $master_image_file_path --> $repository_image_file_path");
return;
}
}
else {
notify($ERRORS{'WARNING'}, 0, "failed to capture image on $node_name, unable to obtain semaphore before copying master image to repository mounted on $node_name: $master_image_file_path --> $repository_image_file_path");
return;
}
# Save the domain XML definition to a file in the repository image directory
my $repository_xml_file_path = $self->get_repository_xml_file_path();
if ($self->vmhost_os->create_text_file($repository_xml_file_path, $domain_xml_string)) {
notify($ERRORS{'OK'}, 0, "saved domain XML definition text file to repository image directory: $master_xml_file_path");
}
else {
notify($ERRORS{'WARNING'}, 0, "failed to capture image on $node_name, unable to save domain XML definition text file to repository image directory: $master_xml_file_path");
return;
}
}
}
if ($request_state_name !~ /^(image)$/) {
notify($ERRORS{'OK'}, 0, "domain will NOT be deleted because the request state is '$request_state_name'");
}
else {
# Image has been captured, delete the domain
$self->delete_domain($domain_name);
}
return 1;
} ## end sub capture