managementnode/lib/VCL/image.pm (582 lines of code) (raw):

#!/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::image - Perl module for the VCL image state =head1 SYNOPSIS use VCL::image; use VCL::utils; # Set variables containing the IDs of the request and reservation my $request_id = 5; my $reservation_id = 6; # Call the VCL::utils::get_request_info subroutine to populate a hash my $request_info = get_request_info($request_id); # Set the reservation ID in the hash $request_info->{RESERVATIONID} = $reservation_id; # Create a new VCL::image object based on the request information my $image = VCL::image->new($request_info); =head1 DESCRIPTION This module supports the VCL "image" state. =cut ############################################################################### package VCL::image; # Specify the lib path using FindBin use FindBin; use lib "$FindBin::Bin/.."; # Configure inheritance use base qw(VCL::Module::State); # Specify the version of this module our $VERSION = '2.5.1'; # Specify the version of Perl to use use 5.008000; use strict; use warnings; use diagnostics; use English '-no_match_vars'; use VCL::utils; ############################################################################### =head1 OBJECT METHODS =cut #////////////////////////////////////////////////////////////////////////////// =head2 process Parameters : $request_data_hash_reference Returns : 1 if successful, 0 otherwise Description : Processes a reservation in the timout state. You must pass this method a reference to a hash containing request data. =cut sub process { my $self = shift; # Check if image OS needs to be updated # Do this before retrieving data because it may change if ($self->provisioner->can('check_image_os')) { if (!$self->provisioner->check_image_os()) { return; } } my $request_id = $self->data->get_request_id(); my $request_state_name = $self->data->get_request_state_name(); my $reservation_id = $self->data->get_reservation_id(); my $user_id = $self->data->get_user_id(); my $user_unityid = $self->data->get_user_login_id(); my $affiliation_helpaddress = $self->data->get_user_affiliation_helpaddress(); my $image_id = $self->data->get_image_id(); my $image_name = $self->data->get_image_name(); my $image_size = $self->data->get_image_size(); my $imagerevision_id = $self->data->get_imagerevision_id(); my $imagemeta_sysprep = $self->data->get_imagemeta_sysprep(); my $computer_id = $self->data->get_computer_id(); my $computer_type = $self->data->get_computer_type(); my $computer_shortname = $self->data->get_computer_short_name(); my $managementnode_shortname = $self->data->get_management_node_short_name(); my $sysadmin_mail_address = $self->data->get_management_node_sysadmin_email(0); # Send an email to administrators indicating image capture started if ($sysadmin_mail_address) { my ($admin_subject, $admin_message) = $self->get_admin_message('image_creation_started'); if (defined($admin_subject) && defined($admin_message)) { mail($sysadmin_mail_address, $admin_subject, $admin_message, $affiliation_helpaddress); } } # Make sure image does not already exist my $image_already_exists = $self->provisioner->does_image_exist(); if ($image_already_exists) { notify($ERRORS{'CRITICAL'}, 0, "image $image_name already exists"); $self->reservation_failed(); } elsif (!defined($image_already_exists)) { notify($ERRORS{'CRITICAL'}, 0, "failed to determine if image $image_name already exists"); $self->reservation_failed(); } else { notify($ERRORS{'OK'}, 0, "image $image_name does not exist"); } # Get the current timestamp # This will be used for image.lastupdate, imagerevision.datecreated and currentimage.txt my $timestamp = makedatestring(); $self->data->set_image_lastupdate($timestamp); $self->data->set_imagerevision_date_created($timestamp); # Check if capture() subroutine has been implemented by the provisioning module if (!$self->provisioner->can("capture")) { notify($ERRORS{'CRITICAL'}, 0, "failed to capture image, " . ref($self->provisioner) . " provisioning module does not implement a 'capture' subroutine"); $self->reservation_failed(); } # If this was a checkpoint, make sure the provisioning module implements a power_on subroutine if ($request_state_name eq 'checkpoint' && !$self->provisioner->can('power_on')) { notify($ERRORS{'CRITICAL'}, 0, "failed to create checkpoint of image, " . ref($self->provisioner) . " provisioning module does not implement a 'power_on' subroutine, won't be able to power the computer back on after image is captured in order to return it to a usable state for the user"); $self->reservation_failed(); } # Make sure post_reservation scripts get executed before capturing computer # This is normally done by reclaim.pm, but this won't be called in the following capture/reload sequence $self->os->post_reservation(); # Call the provisioning modules's capture() subroutine # The provisioning module should do everything necessary to capture the image notify($ERRORS{'OK'}, 0, "calling provisioning module's capture() subroutine"); if ($self->provisioner->capture()) { notify($ERRORS{'OK'}, 0, "$image_name image was successfully captured by the provisioning module"); } else { notify($ERRORS{'WARNING'}, 0, "$image_name image failed to be captured by provisioning module"); $self->reservation_failed(); } # If this was a checkpoint, power the computer back on and wait for it to respond if ($request_state_name eq 'checkpoint') { if (!$self->provisioner->power_on()) { notify($ERRORS{'CRITICAL'}, 0, "failed to create checkpoint of image, failed to power $computer_shortname back on after image was captured"); $self->reservation_failed(); } # Check if the OS module implements a post_load subroutine if ($self->os->can('post_load')) { if ($self->os->post_load()) { # Add a line to currentimage.txt indicating post_load has run $self->os->set_post_load_status(); } else { notify($ERRORS{'CRITICAL'}, 0, "failed to create checkpoint of image, unable to complete OS post-load tasks on $computer_shortname after image was captured and computer was powered on"); $self->reservation_failed(); } } if (!$self->os->reserve()) { notify($ERRORS{'CRITICAL'}, 0, "failed to create checkpoint of image, unable to complete OS reserve tasks on $computer_shortname"); $self->reservation_failed(); } # Disable user connection checking for this request to prevent timeouts update_request_checkuser($request_id, 0); } # Get the new image size my $image_size_new; if ($image_size_new = $self->provisioner->get_image_size($image_name)) { notify($ERRORS{'OK'}, 0, "size of $image_name: $image_size_new"); } else { notify($ERRORS{'WARNING'}, 0, "unable to retrieve size of new revision: $image_name, old size will be used"); $image_size_new = $image_size; } $self->data->set_image_size($image_size_new); # Update image timestamp, image size, clear deleted flag my $update_image_statement = <<EOF; UPDATE image, imagerevision SET image.lastupdate = '$timestamp', image.deleted = '0', image.size = '$image_size_new', image.name = '$image_name', imagerevision.deleted = '0', imagerevision.datecreated = '$timestamp' WHERE image.id = $image_id AND imagerevision.id = $imagerevision_id EOF # Execute the image update statement if (database_execute($update_image_statement)) { notify($ERRORS{'OK'}, 0, "image and imagerevision tables updated for image=$image_id, imagerevision=$imagerevision_id, name=$image_name, lastupdate=$timestamp, deleted=0, size=$image_size_new"); } else { notify($ERRORS{'WARNING'}, 0, "image table could not be updated for image=$image_id"); } # Call the OS module's post_capture subroutine # This call might be relocated to each provisioning module's process subroutine like the call to pre_capture $self->os->post_capture(); $self->reservation_successful($image_size); } ## end sub process #////////////////////////////////////////////////////////////////////////////// =head2 reservation_successful Parameters : $image_size_old Returns : exits Description : Handles final steps when an image capture is successful. Sends message to image creator. Inserts reload request into the database for the newly captured image revision on the computer which was used to capture it. =cut sub reservation_successful { my $self = shift; my $image_size_old = shift || 0; my $request_data = $self->data->get_request_data(); my $request_state_name = $self->data->get_request_state_name(); my $user_email = $self->data->get_user_email(); my $affiliation_helpaddress = $self->data->get_user_affiliation_helpaddress(); my $computer_id = $self->data->get_computer_id(); my $sysadmin_mail_address = $self->data->get_management_node_sysadmin_email(0); # Send a capture completed message to the image owner my ($user_subject, $user_message); if ($request_state_name =~ /(checkpoint)/i) { ($user_subject, $user_message) = $self->get_user_message('image_checkpoint_success'); } else { ($user_subject, $user_message) = $self->get_user_message('image_creation_success'); } if (defined($user_subject) && defined($user_message)) { mail($user_email, $user_subject, $user_message, $affiliation_helpaddress); } # Send mail to administrators if ($sysadmin_mail_address) { # Get the administrator email subject and message my ($admin_subject, $admin_message) = $self->get_admin_message('image_creation_complete'); if (defined($admin_subject) && defined($admin_message)) { mail($sysadmin_mail_address, $admin_subject, $admin_message, $affiliation_helpaddress); } } if ($request_state_name eq 'checkpoint') { $self->state_exit('reserved', 'checkpoint'); } else { # Insert reload request data into the datbase if (!insert_reload_request($request_data)) { notify($ERRORS{'CRITICAL'}, 0, "failed to insert reload request into database for computer ID: $computer_id"); } # Switch the request state to complete, leave the computer state as is, update log ending to EOR, exit $self->state_exit('complete', undef, 'EOR'); } } ## end sub reservation_successful #////////////////////////////////////////////////////////////////////////////// =head2 reservation_failed Parameters : $message (optional) Returns : exits Description : Handles final steps when a request in the image state fails. Sets the request and computer states to maintenance. Sends "processing delayed" message to image creator. =cut sub reservation_failed { my $self = shift; my $request_id = $self->data->get_request_id(); my $request_state_name = $self->data->get_request_state_name(); my $request_laststate_name = $self->data->get_request_laststate_name(); my $user_email = $self->data->get_user_email(); my $affiliation_helpaddress = $self->data->get_user_affiliation_helpaddress(); my $image_name = $self->data->get_image_name(); my $computer_id = $self->data->get_computer_id(); my $computer_shortname = $self->data->get_computer_short_name(); my $sysadmin_mail_address = $self->data->get_management_node_sysadmin_email(0); my $image_capture_type = $self->data->get_image_capture_type(); # Image process failed my $message = shift; if ($message) { notify($ERRORS{'CRITICAL'}, 0, "$image_name Image $image_capture_type Failed - $message"); } else { notify($ERRORS{'CRITICAL'}, 0, "$image_name Image $image_capture_type Failed"); } # Send a capture delayed message to the image owner my $user_message_key = 'image_creation_delayed'; my ($user_subject, $user_message) = $self->get_user_message($user_message_key); if ($request_laststate_name ne "maintenance" && defined($user_subject) && defined($user_message)) { mail($user_email, $user_subject, $user_message, $affiliation_helpaddress); } # Send mail to administrators if ($sysadmin_mail_address) { # Get the administrator email subject and message # Pass a hash containing an IMAGE_CAPTURE_TYPE key - this gets replaced in the subject of the message my $admin_message_key = 'image_creation_failed'; my ($admin_subject, $admin_message) = $self->get_admin_message($admin_message_key); if (defined($admin_subject) && defined($admin_message)) { mail($sysadmin_mail_address, $admin_subject, $admin_message, $affiliation_helpaddress); } } $self->state_exit('maintenance', 'maintenance'); } ## end sub reservation_failed #////////////////////////////////////////////////////////////////////////////// =head2 setup_get_menu Parameters : none Returns : hash reference Description : Assembles the image-related 'vcld -setup' menu items. =cut sub setup_get_menu { return { 'Image Management' => { 'Capture a Base Image' => \&setup_capture_base_image, }, }; } #////////////////////////////////////////////////////////////////////////////// =head2 setup_capture_base_image Parameters : none Returns : true Description : This subroutine is used when vcld is run in setup mode. It inserts the database entries necessary to capture a base image. Several questions are presented to the user via the command line. =cut sub setup_capture_base_image { 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; } # Get the management node id, needed to insert a reservation row later on my $management_node_id = $self->data->get_management_node_id(); if (!$management_node_id) { print "ERROR: failed to determine the management node ID\n"; return; } my ($request_id, $reservation_id) = 0; my $image_is_virtual = 0; print "\nTesting api call\n"; if ($self->setup_test_rpc_xml(0)) { print "VCL API call successful\n\n"; } # Is vcld service running if (!run_command('service vcld restart')) { print "ERROR: Unable to confirm vcld is running, Attempted to use service vcld restart\n"; return; } # Get the user who the reservation and image will belong to my $user_id; my $username; while (!$user_id) { my $user_identifier = setup_get_input_string("Enter the VCL login name or ID of the user who will own the image:", 'admin'); return if (!defined($user_identifier)); my $user_info = get_user_info($user_identifier); if (!$user_info) { print "User was not found: $user_identifier\n"; } else { $user_id = $user_info->{id}; $username = $user_info->{unityid}; } } print "\nUser who will own the image: $username (ID: $user_id)\n\n"; # Determine the computer ID my $computer_id; my %computer_info; while (!$computer_id) { my $computer_identifier = setup_get_input_string("Enter the hostname or IP address of the computer to be captured:"); return if (!defined($computer_identifier)); # Search the computer table for a match my @computer_ids = get_computer_ids($computer_identifier); if (!@computer_ids) { print "No VCL computers were found with the name or IP address: $computer_identifier\n"; next; } # Get information from the database for all of the computers found for my $computer_id (@computer_ids) { $computer_info{$computer_id} = get_computer_info($computer_id); if (!$computer_info{$computer_id}) { print "ERROR: unable to retrieve information for computer ID: $computer_id\n"; return; } } if (scalar(@computer_ids) > 1) { print "Multiple VCL computers were found with the name or IP address: '$computer_identifier' (@computer_ids)\n\n"; print "Choose a computer:\n"; $computer_id = setup_get_hash_choice(\%computer_info, 'hostname'); return if (!defined($computer_id)); } else { $computer_id = (keys %computer_info)[0]; } } my $computer_hostname = $computer_info{$computer_id}{hostname}; my $computer_state_name = $computer_info{$computer_id}{state}{name}; my $computer_provisioning_id = $computer_info{$computer_id}{provisioning}{id}; my $computer_provisioning_module_name = $computer_info{$computer_id}{provisioning}{module}{name}; my $computer_provisioning_module_pretty_name = $computer_info{$computer_id}{provisioning}{module}{prettyname}; my $computer_provisioning_pretty_name = $computer_info{$computer_id}{provisioning}{prettyname}; my $computer_provisioning_name = $computer_info{$computer_id}{provisioning}{name}; my $computer_node_name = $computer_info{$computer_id}{SHORTNAME}; my $osinstalltype_info = get_provisioning_osinstalltype_info($computer_provisioning_id); my @provisioning_osinstalltype_names = map { $osinstalltype_info->{$_}{name} } keys %$osinstalltype_info; print "\nComputer to be captured: $computer_hostname (ID: $computer_id)\n"; print "Computer shortname: $computer_node_name\n"; print "Computer State: $computer_state_name\n"; print "Provisioning module: $computer_provisioning_module_pretty_name\n"; print "OS install types: " . join(", ", sort @provisioning_osinstalltype_names) . "\n"; my $vmhost_name; if ($computer_provisioning_module_name !~ /xcat/i) { $image_is_virtual = 1; #should have a vmhost assigned if ($computer_info{$computer_id}{vmhostid}) { $vmhost_name = $computer_info{$computer_id}{vmhost}{computer}{SHORTNAME}; print "VM host name: $vmhost_name\n"; print "VM host profile: $computer_info{$computer_id}{vmhost}{vmprofile}{profilename}\n"; print "\n"; } else { print "ERROR: Install type is vmware, $computer_node_name is NOT assigned to a vmhost\n"; print "ERROR: Assign $computer_node_name to a vmhost before proceeding.\n"; print "\n"; return; } } print "Testing ssh access to $computer_hostname\n"; # Node Checks # is the node up and accessible through ssh pki # If it is a vm, is it assigned to a vmhost # Try nmap to see if any of the ssh ports are open before attempting to run a test command my $port_22_status = nmap_port($computer_node_name, 22) ? "open" : "closed"; my $port_24_status = nmap_port($computer_node_name, 24) ? "open" : "closed"; if ($port_22_status ne 'open' && $port_24_status ne 'open') { print "Error: ssh port on $computer_node_name is NOT responding to SSH, ports 22 or 24 are both closed\n"; return; } my ($exit_status, $output) = run_ssh_command({ node => $computer_node_name, command => "echo \"testing ssh on $computer_node_name\"", max_attempts => 2, output_level => 0, timeout_seconds => 30, }); # The exit status will be 0 if the command succeeded if (defined($output) && grep(/testing/, @$output)) { print "$computer_node_name is responding to SSH, port 22: $port_22_status, port 24: $port_24_status\n"; print "\n"; } else { print "ERROR: $computer_node_name is NOT responding to SSH, SSH command failed, port 22: $port_22_status, port 24: $port_24_status\n"; print "Make sure you can login using ssh PKI on $computer_node_name before continuing\n"; print "\n"; return; } # Check if computer id is in an existing or failed imaging reservation my $computer_requests = get_request_by_computerid($computer_id); my %existing_requests_array_choices; if (keys(%$computer_requests)) { $existing_requests_array_choices{0}{"prettyname"} = "Delete all existing reservations for $computer_node_name"; for my $competing_request_id (sort keys %$computer_requests) { my $competing_reservation_id = $computer_requests->{$competing_request_id}{data}->get_reservation_id(); my $competing_imagerevision_id = $computer_requests->{$competing_request_id}{data}->get_imagerevision_id(); my $competing_image_id = $computer_requests->{$competing_request_id}{data}->get_image_id(); my $competing_prettyimage_name = $computer_requests->{$competing_request_id}{data}->get_image_prettyname(); my $competing_image_name = $computer_requests->{$competing_request_id}{data}->get_image_name(); my $competing_request_state = $computer_requests->{$competing_request_id}{data}->get_request_state_name(); $existing_requests_array_choices{$competing_request_id}{"prettyname"} = $competing_prettyimage_name; $existing_requests_array_choices{$competing_request_id}{"name"} = $competing_image_name; $existing_requests_array_choices{$competing_request_id}{"image_id"} = $competing_image_id; $existing_requests_array_choices{$competing_request_id}{"image_revision_id"} = $competing_imagerevision_id; $existing_requests_array_choices{$competing_request_id}{"current_state"} = $competing_request_state; $existing_requests_array_choices{$competing_request_id}{"reservation_id"} = $competing_reservation_id; } my $num_computer_requests = keys(%$computer_requests); print "WARNING: Image capture reservation exists for $computer_node_name.\n"; print "Either choose the image name to restart image capture for that request or choose none to delete the previous reservations:\n"; my $chosen_request_id = setup_get_hash_choice(\%existing_requests_array_choices, 'prettyname'); return if (!defined($chosen_request_id)); my $chosen_prettyname = $existing_requests_array_choices{$chosen_request_id}{prettyname}; print "\nSelected reservation: $chosen_request_id $chosen_prettyname\n\n"; # if 0 selected, delete all reservations related to $computer_node_name # Set $computer_node_name to available, proceed with questions my $epoch_time = convert_to_epoch_seconds; if ($chosen_request_id == 0) { delete $existing_requests_array_choices{0}; foreach my $request_id_del (sort keys %existing_requests_array_choices) { my $del_reservation_id = $existing_requests_array_choices{$request_id_del}{reservation_id}; my $del_image_id = $existing_requests_array_choices{$request_id_del}{image_id}; my $del_imagerevision_id = $existing_requests_array_choices{$request_id_del}{image_revision_id}; my $del_image_name = $existing_requests_array_choices{$request_id_del}{name}; print "del_image_name= $del_image_name\n"; my $new_image_name = $del_image_name . $epoch_time; my $new_prettyimage_name = $existing_requests_array_choices{$request_id_del}{prettyname} . $epoch_time; if (reservation_being_processed($del_reservation_id)) { print "WARNING: The selected reservation is currently being processed. You must wait until it has completed.\n"; print "Reservation id: $del_reservation_id\n"; print "\n"; next; } if (delete_request($request_id_del)) { print "Removed reservation id $request_id_del for $del_image_name\n"; if (update_image_name($del_image_id, $del_imagerevision_id, $new_image_name, $new_prettyimage_name)) { } if (update_computer_state($computer_id, "available")) { print "Set $computer_node_name to available state\n"; } } } } # Elseif a request id is choosen. set $computer_node_name to available, test ssh access, restart image capture if ($chosen_request_id) { $request_id = $chosen_request_id; $reservation_id = $existing_requests_array_choices{$chosen_request_id}{reservation_id}; if (reservation_being_processed($chosen_request_id)) { print "WARNING: The selected reservation is currently being processed. You must wait until it has completed.\n"; print "Reservation id: $chosen_request_id\n"; print "\n"; my @yes_no_choices = ( 'Yes', 'No', ); print "Monitor vcld.log for completion?:\n"; my $monitor_choice_index = setup_get_array_choice(@yes_no_choices); last if (!defined($monitor_choice_index)); my $monitor_choice = $yes_no_choices[$monitor_choice_index]; if ($monitor_choice =~ /yes/i) { print ".\n"; goto MONITOR_LOG_OUTPUT; } else { return; } } if (update_computer_state($computer_id, "available")) { print "Set $computer_node_name to available state\n"; } $chosen_prettyname = $existing_requests_array_choices{$chosen_request_id}{prettyname}; print "Restarting image capture for: \nRequest id= $chosen_request_id \nImage Name: $chosen_prettyname \nNode Name: $computer_node_name\n"; if (update_request_state($chosen_request_id, "image", "image", 1)) { print "Set request_id= $chosen_request_id to image state\n\n"; print "Starting monitor process:\n\n"; goto MONITOR_LOG_OUTPUT; } else { print "ERROR: failed to update request state for $chosen_request_id, state_name= image, last_state: image\n"; } } } # Make sure the computer state is valid if ($computer_state_name =~ /(maintenance|deleted)/i) { print "ERROR: state of $computer_node_name is $computer_state_name\n"; print "\n"; return; } # Get the OS table contents from the database my $os_info = get_os_info(); if (!$os_info) { print "ERROR: failed to retrieve OS info from the database\n"; return; } # Loop through the OS table info OS_ID: for my $os_id (keys %$os_info) { my $osinstalltype_name = $os_info->{$os_id}{installtype}; # Remove keys where the name begins with esx - deprecated OS type if ($osinstalltype_name =~ /^vmwareesx/i) { delete $os_info->{$os_id}; next; } # Remove keys which don't match the selected computer type for my $provisioning_osinstalltype_name (@provisioning_osinstalltype_names) { if ($provisioning_osinstalltype_name eq $osinstalltype_name) { next OS_ID; } } delete $os_info->{$os_id}; } print "Select the OS to be captured (install type: " . join(', ', sort @provisioning_osinstalltype_names) . "):\n"; my $os_id = setup_get_hash_choice($os_info, 'prettyname'); return if (!defined($os_id)); my $os_prettyname = $os_info->{$os_id}{prettyname}; my $os_module_perl_package = $os_info->{$os_id}{module}{perlpackage}; my $os_type = $os_info->{$os_id}{type}; print "\nSelected OS: $os_prettyname\n\n"; my @architecture_choices = ( 'x86', 'x86_64', ); print "Image architecture:\n"; my $architecture_choice_index = setup_get_array_choice(@architecture_choices); last if (!defined($architecture_choice_index)); my $architecture_choice = $architecture_choices[$architecture_choice_index]; print "\nImage architecture: $architecture_choice\n\n"; # If Windows, ask if Sysprep should be used my $use_sysprep = 1; if ($os_type =~ /windows/i) { my @yes_no_choices = ( 'Yes', 'No', ); print "Use Sysprep:\n"; my $sysprep_choice_index = setup_get_array_choice(@yes_no_choices); last if (!defined($sysprep_choice_index)); my $use_sysprep_choice = $yes_no_choices[$sysprep_choice_index]; print "\nUse Sysprep: $use_sysprep_choice\n\n"; if ($use_sysprep_choice =~ /no/i) { $use_sysprep = 0; } } my $image_prettyname; while (!$image_prettyname) { $image_prettyname = setup_get_input_string("Enter the name of the image to be captured:"); return if (!defined($image_prettyname)); #if ($image_prettyname =~ //) { # print "Image name is not valid: $image_prettyname\n"; # $image_prettyname = 0; #} } my $image_name = $image_prettyname; $image_name =~ s/[\s\W]//g; $image_name = $os_info->{$os_id}{name} . "-$image_name-v0"; my $insert_imagemeta_statement = <<EOF; INSERT INTO imagemeta (sysprep) VALUES ('$use_sysprep') EOF my $imagemeta_id = database_execute($insert_imagemeta_statement); if (!defined($imagemeta_id)) { print "ERROR: failed to insert into imagemeta table.\n"; return; } my $insert_image_statement = <<EOF; INSERT INTO image (name, prettyname, ownerid, platformid, OSid, imagemetaid, deleted, lastupdate, size, architecture, basedoffrevisionid) VALUES ( '$image_name', '$image_prettyname', '$user_id', '1', $os_id, $imagemeta_id, '1', NOW(), '1', '$architecture_choice', (SELECT id FROM imagerevision WHERE imagename = 'noimage') ) EOF my $image_id = database_execute($insert_image_statement); if (!defined($image_id)) { print "ERROR: failed to insert into image table. Please choose another name.\n"; return; } # Add the newly inserted image ID to the image name $image_name =~ s/-v0$/$image_id-v0/; # Upadate the name in the image table my $update_image_statement = <<EOF; UPDATE image SET name = '$image_name' WHERE id = $image_id EOF if (!database_execute($update_image_statement)) { print "ERROR: failed to update the image table with the correct image name: $image_name\n"; return; } my $insert_imagerevision_statement = <<EOF; INSERT INTO imagerevision (imageid, revision, userid, datecreated, deleted, production, imagename) VALUES ($image_id, '0', '$user_id', NOW(), '1', '1', '$image_name') EOF my $imagerevision_id = database_execute($insert_imagerevision_statement); if (!defined($imagerevision_id)) { print "ERROR: failed to insert into imagerevision table\n"; return; } my $insert_resource_statement = <<EOF; INSERT INTO resource (resourcetypeid, subid) VALUES ('13', '$image_id') EOF my $resource_id = database_execute($insert_resource_statement); if (!defined($resource_id)) { print "ERROR: failed to insert into resource table\n"; return; } # Add image resource_id to users' new image group if (!add_imageid_to_newimages($user_id, $resource_id, $image_is_virtual)) { print "\nWARNING: Failed to add image to user's new images group\n"; print "You might need to add manually to the new images or all images image groups\n"; print "Continuing to with image capture\n\n"; } print "\nAdded new image to database: '$image_prettyname'\n"; print " image.name: $image_name\n"; print " image.id: $image_id\n"; print " imagerevision.id: $imagerevision_id\n"; print " imagemeta.id: $imagemeta_id\n"; print " resource.id: $resource_id\n\n"; ($request_id, $reservation_id) = insert_request($management_node_id, 'image', 'image', $username, $computer_id, $image_id, $imagerevision_id, 0, 60); if (!defined($request_id) || !defined($reservation_id)) { print "ERROR: failed to insert new imaging request\n"; return; } my $process_regex = get_reservation_vcld_process_name_regex($reservation_id) || $reservation_id; $process_regex =~ s/^\w+\s//; my $message = <<EOF; Inserted imaging request to the database: request ID: $request_id reservation ID: $reservation_id This process will now display the contents of the vcld.log file if the vcld daemon is running. If you do not see many lines of additional output, exit this process, start the vcld daemon, and monitor the image capture process by running the command: tail -f $LOGFILE | grep -P '$process_regex' EOF print '-' x 76 . "\n"; print "$message"; print '-' x 76 . "\n"; MONITOR_LOG_OUTPUT: # Pipe the command output to a file handle # The open function returns the pid of the process if (open(COMMAND, "tail -f $LOGFILE 2>&1 |")) { # Capture the output of the command while (my $output = <COMMAND>) { if ($output =~ /$reservation_id/) { print $output; if ($output =~ /complete/i) { last; } } } } exit; } #////////////////////////////////////////////////////////////////////////////// 1; __END__ =head1 SEE ALSO L<http://cwiki.apache.org/VCL/> =cut