in managementnode/lib/VCL/Module/Provisioning/vbox.pm [897:1037]
sub retrieve_image {
my $self = shift;
unless (ref($self) && $self->isa('VCL::Module')) {
notify($ERRORS{'CRITICAL'}, 0, "subroutine can only be called as a VCL::Module module object method");
return;
}
# Make sure image library functions are enabled
my $image_lib_enable = $self->data->get_management_node_image_lib_enable();
if (!$image_lib_enable) {
notify($ERRORS{'OK'}, 0, "image library functions are disabled");
return;
}
# If an argument was specified, use it as the image name
# If not, get the image name from the reservation data
my $image_name = shift || $self->data->get_image_name();
if (!$image_name) {
notify($ERRORS{'WARNING'}, 0, "unable to determine image name from argument or reservation data");
return;
}
# Get the last digit of the reservation ID and sleep that number of seconds
# This is done in case 2 reservations for the same image were started at the same time
# Both may attempt to retrieve an image and execute the SCP command at nearly the same time
# does_image_exist() may not catch this and allow 2 SCP retrieval processes to start
# It's likely that the reservation IDs are consecutive and the the last digits will be different
my ($pre_retrieval_sleep) = $self->data->get_reservation_id() =~ /(\d)$/;
notify($ERRORS{'DEBUG'}, 0, "sleeping for $pre_retrieval_sleep seconds to prevent multiple SCP image retrieval processes");
sleep $pre_retrieval_sleep;
# Make sure image does not already exist on this management node
if ($self->does_image_exist($image_name)) {
notify($ERRORS{'OK'}, 0, "$image_name already exists on this management node");
return 1;
}
# Get the image library partner string
my $image_lib_partners = $self->data->get_management_node_image_lib_partners();
if (!$image_lib_partners) {
notify($ERRORS{'WARNING'}, 0, "image library partners could not be determined");
return;
}
# Split up the partner list
my @partner_list = split(/,/, $image_lib_partners);
if ((scalar @partner_list) == 0) {
notify($ERRORS{'WARNING'}, 0, "image lib partners variable is not listed correctly or does not contain any information: $image_lib_partners");
return;
}
# Get the local image repository path
my $image_repository_path_local = $self->_get_image_repository_path();
if (!$image_repository_path_local) {
notify($ERRORS{'WARNING'}, 0, "image repository path could not be determined");
return;
}
# Loop through the partners
# Find partners which have the image
# Check size for each partner
# Retrieve image from partner with largest image
# It's possible that another partner (management node) is currently copying the image from another managment node
# This should prevent copying a partial image
my $largest_partner;
my $largest_partner_hostname;
my $largest_partner_image_lib_user;
my $largest_partner_image_lib_key;
my $largest_partner_ssh_port;
my $largest_partner_path;
my $largest_partner_size = 0;
notify($ERRORS{'OK'}, 0, "attempting to find another management node that contains $image_name");
foreach my $partner (@partner_list) {
# Get the connection information for the partner management node
my $partner_hostname = $self->data->get_management_node_hostname($partner) || '';
my $partner_image_lib_user = $self->data->get_management_node_image_lib_user($partner) || '';
my $partner_image_lib_key = $self->data->get_management_node_image_lib_key($partner) || '';
my $partner_ssh_port = $self->data->get_management_node_ssh_port($partner) || '';
my $image_repository_path_remote = $self->_get_image_repository_path($partner);
notify($ERRORS{'OK'}, 0, "checking if $partner_hostname has image $image_name");
notify($ERRORS{'DEBUG'}, 0, "remote image repository path on $partner: $image_repository_path_remote");
# Run du to get the size of the image files on the partner if the image exists
my ($du_exit_status, $du_output) = run_ssh_command($partner, $partner_image_lib_key, "du -c $image_repository_path_remote\/*$image_name* | grep total", $partner_image_lib_user, $partner_ssh_port, 1);
# If the partner doesn't have the image, a "no such file" error should be displayed
if (defined($du_output) && grep(/no such file/i, @$du_output)) {
notify($ERRORS{'OK'}, 0, "$image_name does NOT exist on $partner_hostname");
next;
}
elsif (defined($du_output) && !grep(/\d+\s+total/i, @$du_output)) {
notify($ERRORS{'WARNING'}, 0, "du output does not contain a total line:\n" . join("\n", @$du_output));
next;
}
elsif (!defined($du_exit_status)) {
notify($ERRORS{'WARNING'}, 0, "failed to run ssh command to determine if image $image_name exists on $partner_hostname");
next;
}
# Extract the image size in bytes from the du total output line
my ($partner_image_size) = (@$du_output[0] =~ /(\d+)\s+total/);
notify($ERRORS{'OK'}, 0, "$image_name exists on $partner_hostname, size: $partner_image_size bytes");
# Check if the image size is larger than any previously found, if so, save the partner info
if ($partner_image_size > $largest_partner_size) {
$largest_partner = $partner;
$largest_partner_hostname = $partner_hostname;
$largest_partner_size = $partner_image_size;
$largest_partner_image_lib_user = $partner_image_lib_user;
$largest_partner_image_lib_key = $partner_image_lib_key;
$largest_partner_ssh_port = $partner_ssh_port;
$largest_partner_path = $image_repository_path_remote;
}
}
# Check if any partner was found
if (!$largest_partner) {
notify($ERRORS{'WARNING'}, 0, "unable to find $image_name on other management nodes");
return;
}
# Attempt copy
notify($ERRORS{'OK'}, 0, "attempting to retrieve $image_name from $largest_partner_hostname");
if (run_scp_command("$largest_partner_image_lib_user\@$largest_partner:$largest_partner_path/$image_name*", $image_repository_path_local, $largest_partner_image_lib_key, $largest_partner_ssh_port)) {
notify($ERRORS{'OK'}, 0, "image $image_name was copied from $largest_partner_hostname");
}
else {
notify($ERRORS{'WARNING'}, 0, "failed to copy image $image_name from $largest_partner_hostname");
return 0;
}
# Make sure image was copied
if (!$self->does_image_exist($image_name)) {
notify($ERRORS{'WARNING'}, 0, "$image_name was not copied to this management node");
return 0;
}
return 1;
} ## end sub retrieve_image