in managementnode/lib/VCL/Module/Provisioning/one.pm [292:481]
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;
my $image_name = $self->data->get_image_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 $computer_name = $self->data->get_computer_hostname();
my $one_new_image_id = 0;
$self->data->set_imagemeta_sysprep(0);
notify($ERRORS{'OK'}, 0, "ONE module starting image capture.");
my $vmid = $self->_one_get_object_id("computer",$computer_name);
if ($vmid) {
# get {TEMPLATE}{DISK}{IMAGE} of $vmid, the name of current image
$old_image_name = $self->_one_get_vm_disk($vmid);
my @savedisk = $one{'server'}->call('one.vm.savedisk', $one{'auth'},$vmid,0,$image_name,'OS',$one{'false'});
if ($savedisk[0][0]->value()) {
notify($ERRORS{'OK'}, 0, "VM $vmid will be captured as $image_name");
} else {
notify($ERRORS{'CRITICAL'}, 0, $savedisk[0][1]);
return;
}
} else {
notify($ERRORS{'CRITICAL'}, 0, "Couldn't find vmid for $computer_name. Abort.");
return 0;
}
# Call the OS module's pre_capture() subroutine (don't shutdown at the end)
if ($self->os->can("pre_capture")) {
if (!$self->os->pre_capture({end_state => 'on'})) {
notify($ERRORS{'CRITICAL'}, 0, "failed to complete OS module's pre_capture tasks");
return;
} else {
notify($ERRORS{'OK'}, 0, "OS's pre_capture complited OK.");
}
} else {
notify($ERRORS{'CRITICAL'}, 0, "OS module doesn't implement pre_capture(). Abort.");
return;
}
# pre_capture was called with {end_state => 'on'}. Need to shutdown VM via ACPI.
if (!$self->power_off()) {
notify($ERRORS{'CRITICAL'}, 0, "Couldn't shutdown $computer_name with power_off()");
return 0;
} else {
# notify($ERRORS{'DEBUG'}, 0, "Sent 'shutdown' to computer $computer_name via provisioning module");
# make sure VM enters STATE=ACTIVE (3) & LCM_STATE=EPILOG(11)
# if VM doesn't reach EPILOG, wait for ACTIVE/RUNNING (3/3) and then send 'shutdown-hard', check for EPILOG again.
my $sleep = 5;
my $wait_time = 5 * 60; # how long to wait for LCM_STATE = EPILOG
my $flag = 0;
my $state;
my $lcm_state;
notify($ERRORS{'OK'}, 0, "Wait for the VM $vmid to enter ACTIVE/EPILOG (3/11) state...");
EPILOG: while (1) {
$state = $self->_one_get_vm_state($vmid);
notify($ERRORS{'OK'}, 0, "VM $vmid is in $state state");
if ($state == 3) {
$lcm_state = $self->_one_get_vm_lcm_state($vmid);
notify($ERRORS{'OK'}, 0, "VM $vmid is in $lcm_state lcm_state");
if ($lcm_state == 11) {
notify($ERRORS{'OK'}, 0, "VM $vmid is in EPILOG state. OK");
last EPILOG;
} else {
notify($ERRORS{'OK'}, 0, "VM $vmid is in $state / $lcm_state state...");
}
} else {
notify($ERRORS{'DEBUG'}, 0, "VM $vmid should be in ACTIVE (3) state, but it's in $state state");
return 0;
}
sleep $sleep;
$wait_time = $wait_time - $sleep;
notify($ERRORS{'OK'}, 0, "Waiting for VM $vmid to enter ACTIVE/EPILOG state, $wait_time sec left ...");
if ($wait_time <= $sleep) {
notify($ERRORS{'DEBUG'}, 0, "VM $vmid never reached EPILOG state. Wait for ACTIVE/RUNNING (3/3) and send 'shutdown-hard'");
my $sleep = 15;
my $wait_time = 20 * 60; #how long to wait for ACTIVE/RUNNING (3/3)
while (1) {
$state = $self->_one_get_vm_state($vmid);
if ($state == 3) {
$lcm_state = $self->_one_get_vm_lcm_state($vmid);
if ($lcm_state == 3) {
notify($ERRORS{'OK'}, 0, "VM $vmid is in $state / $lcm_state state. Wait $sleep sec and send 'shutdown-hard'");
sleep $sleep;
if (!$self->power_off('hard')) {
notify($ERRORS{'CRITICAL'}, 0, "Couldn't shutdown $computer_name with power_off('hard')");
return 0;
}
last EPILOG;
} else {
notify($ERRORS{'OK'}, 0, "VM $vmid is in $state / $lcm_state state...");
}
} else {
notify($ERRORS{'OK'}, 0, "VM $vmid is in $state state...");
}
sleep $sleep if ($wait_time > 0);
$wait_time = $wait_time - $sleep;
notify($ERRORS{'OK'}, 0, "Waiting for VM $vmid to enter ACTIVE/RUNNING state, $wait_time sec left ...");
if ($wait_time <= $sleep) {
notify($ERRORS{'CRITICAL'}, 0, "VM $vmid is in $state / $lcm_state after $wait_time sec ... Fail!");
return 0;
}
}
}
}
}
# Check that we have new_image_name created on ONE (it will be in LOCKED state until disk_save is done).
# just procation, image stub should be created already.
my $sleep = 5;
my $wait_time = 20 * 60; # in min * 60 = seconds
while (1) {
$one_new_image_id = $self->_one_get_object_id("image",$image_name);
last if ($one_new_image_id);
$wait_time = $wait_time - $sleep;
if ($wait_time <= 0) {
notify($ERRORS{'CRITICAL'}, 0, "Could not locate new disk id for $image_name. disk_save wasn't successfull.");
last;
}
sleep $sleep;
}
# wait until disk_save is done
$wait_time = 30 * 60; # in min * 60 = seconds
while (1) {
notify($ERRORS{'OK'}, 0, "check status for new image id $one_new_image_id, $wait_time sec left...");
my $one_image_state = $self->_one_get_image_state($one_new_image_id);
if ($one_image_state == 4) {
notify($ERRORS{'OK'}, 0, "disk save in pregress, image id $one_new_image_id is LOCKED");
}
if ($one_image_state == 5) {
notify($ERRORS{'CRITICAL'}, 0, "disk save failed, image id $one_new_image_id is ERROR");
return 0;
}
if ($one_image_state == 1) {
notify($ERRORS{'OK'}, 0, "disk save OK, image id $one_new_image_id is READY");
# check if template exists for the old image and create template for the new image.
my $one_template_id = $self->_one_get_template_id($old_image_name);
if ($one_template_id) {
notify($ERRORS{'OK'}, 0, "Found existing template id $one_template_id for $old_image_name");
my @template_info = $one{'server'}->call('one.template.info',$one{'auth'},$one_template_id);
if ($template_info[0][0]->value()) {
my $data = XMLin($template_info[0][1]);
my $template = $data->{TEMPLATE};
$template->{NAME} = $image_name;
if ((ref($template->{DISK})) eq "ARRAY" ) { # template has multiple disks, update [0]
$template->{DISK}[0]{IMAGE_ID} = $one_new_image_id;
} else { #template has one disk
$template->{DISK}{IMAGE_ID} = $one_new_image_id;
}
if (!$self->_one_create_template(XMLout($template,NoAttr => 1,RootName=>'TEMPLATE',))) {
notify($ERRORS{'CRITICAL'}, 0, "Could't create $image_name template. Abort.");
}
} else {
notify($ERRORS{'CRITICAL'}, 0, "Error while making one.template.info call: $template_info[0][1]");
}
} else {
notify($ERRORS{'OK'}, 0, "No template exists for $old_image_name");
}
return 1;
}
if ($wait_time <= 0) {
notify($ERRORS{'CRITICAL'}, 0, "disk save failed, image id $one_new_image_id is NOT READY. Fail.");
return 0;
}
sleep $sleep;
$wait_time = $wait_time - $sleep;
}
return 0;
}