managementnode/lib/VCL/Module/Provisioning/one.pm (678 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::Provisioning::one - VCL module to support OpenNebula Cloud =head1 SYNOPSIS Needs to be written =head1 DESCRIPTION This module provides VCL support for OpenNebula Cloud =cut ############################################################################### package VCL::Module::Provisioning::one; # Specify the lib path using FindBin use FindBin; use lib "$FindBin::Bin/../../.."; # Configure inheritance use base qw(VCL::Module::Provisioning); # 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 qw(-no_match_vars); use VCL::utils; use Fcntl qw(:DEFAULT :flock); use Frontier::Client; use XML::Simple; use Data::Dumper; my %one; my $xml; =head2 initialize Parameters : Returns : Description : =cut sub initialize { 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 $one_username = $self->data->get_vmhost_profile_username(); my $one_password = $self->data->get_vmhost_profile_password(); my $one_server_url = $self->data->get_vmhost_profile_resource_path(); if (defined($one_username) and defined($one_password) and defined($one_server_url)) { $one{'server_url'} = $one_server_url; $one{'auth'} = "$one_username:$one_password"; $one{'server'} = Frontier::Client->new(url => $one{'server_url'}); $one{'false'} = $one{'server'}->boolean(0); $one{'true'} = $one{'server'}->boolean(1); $xml = XML::Simple->new(); notify($ERRORS{'DEBUG'}, 0, "Module ONE initialized with following parameters: \n one_server_url -> $one{'server_url'}, one_username:one_password -> $one{'auth'}\n"); return 1; } else { notify($ERRORS{'CRITICAL'}, 0,"one_username, one_password, one_server_url not defined in VM Host profile. Abort."); return 0; } } #////////////////////////////////////////////////////////////////////////////// =head2 provision Parameters : hash Returns : 1(success) or 0(failure) Description : loads node with provided image =cut sub load { my $self = shift; if (ref($self) !~ /one/i) { notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method"); return 0; } my $reservation_id = $self->data->get_reservation_id(); my $computer_id = $self->data->get_computer_id(); my $image_name = $self->data->get_image_name(); my $eth0_ip = $self->data->get_computer_private_ip_address(); my $image_os_type = $self->data->get_image_os_type(); my $one_network_0 = $self->data->get_vmhost_profile_virtualswitch0(); my $one_network_1 = $self->data->get_vmhost_profile_virtualswitch1(); my $vm_name = $self->data->get_image_prettyname(); my $cpu_count = $self->data->get_image_minprocnumber() || 1; my $image_arch = $self->data->get_image_architecture(); if ($image_arch ne "x86_64") {$image_arch = "i686";} my $memory = $self->data->get_image_minram(); my $computer_name = $self->data->get_computer_hostname(); if ($memory < 512) { $memory = 512; #$memory = $cpu_count * 2048; } my $one_vm_name = "$computer_name ($image_name)"; #delete running VM, if present notify($ERRORS{'OK'}, 0, "Checking if computer $computer_name already loaded on ONE..."); my $one_computer_id = $self->_one_get_object_id("computer",$computer_name); if ($one_computer_id) { $self->_one_delete_vm($one_computer_id); notify($ERRORS{'OK'}, 0, "Computer $computer_name was running on ONE ... deleted."); # sleep for 2sec to allow ONE process the request: sleep 2; } # check if there is ONE template already exsist for the image # and create VM based on the template. If no template create 'manually' my $one_template_id = $self->_one_get_template_id($image_name); if ($one_template_id) { 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; $template = $data->{TEMPLATE}; $template->{NAME} = $one_vm_name; $template->{NIC}[0]{IP} = $eth0_ip; my $one_new_vmid = $self->_one_create_vm(XMLout($template,NoAttr => 1,RootName=>'TEMPLATE',)); if ($one_new_vmid) { notify($ERRORS{'OK'}, 0, "New VM $template->{NAME} deployed with ID $one_new_vmid using template ID $one_template_id"); insertloadlog($reservation_id, $computer_id, "vmsetupconfig", "defined $computer_name"); insertloadlog($reservation_id, $computer_id, "startvm", "powered on $computer_name"); } else { notify($ERRORS{'CRITICAL'}, 0, "Could't create requested VM. Abort."); return 0; } } else { notify($ERRORS{'CRITICAL'}, 0, "Error while making one.template.info call: $template_info[0][1]"); } } else { # No template, create VM manually: my $template = {}; my $one_network_0_id = $self->_one_get_object_id("network",$one_network_0); my $one_network_1_id = $self->_one_get_object_id("network",$one_network_1); my $one_image_id = $self->_one_get_object_id("image",$image_name); my $one_virtio = $self->_one_get_virtio($one_image_id); my $virtio = 0; if ($self->_one_get_image_tag_value($image_name,"DEV_PREFIX") eq "vd") { $virtio = 1; } $template->{NAME} = $one_vm_name; $template->{CPU} = $cpu_count; $template->{VCPU} = $cpu_count; $template->{MEMORY} = $memory; $template->{OS}{ARCH} = $image_arch; $template->{INPUT}{BUS} = "usb"; $template->{INPUT}{TYPE} = "tablet"; $template->{GRAPHICS}{TYPE} = "VNC"; $template->{GRAPHICS}{LISTEN} = "0.0.0.0"; $template->{REQUIREMENTS} = "CLUSTER_ID=\"100\""; #$template->{REQUIREMENTS} = "CLUSTER_ID=\"100\" | CLUSTER_ID=\"108\""; $template->{DISK}[0]{IMAGE_ID} = $one_image_id; $template->{NIC}[0]{NETWORK_ID} = $one_network_0_id; $template->{NIC}[0]{IP} = $eth0_ip; $template->{NIC}[0]{MODEL} = "virtio" if ($virtio); $template->{NIC}[1]{NETWORK_ID} = $one_network_1_id; $template->{NIC}[1]{MODEL} = "virtio" if ($virtio); # Check if SWAP disk needed. Does image have SWAP=<size_MB> attribute? my $swap_disk = ''; my $swap_size = $self->_one_get_image_tag_value($image_name,"SWAP"); if ($swap_size) { $template->{DISK}[1]{TYPE} = "swap"; $template->{DISK}[1]{SIZE} = $swap_size; $template->{DISK}[1]{DEV_PREFIX} = "vd" if ($virtio); } # create VM my $one_new_vmid = $self->_one_create_vm(XMLout($template,NoAttr => 1,RootName=>'TEMPLATE',)); if ($one_new_vmid) { notify($ERRORS{'OK'}, 0, "New VM $template->{NAME} deployed with ID $one_new_vmid"); insertloadlog($reservation_id, $computer_id, "vmsetupconfig", "defined $computer_name"); insertloadlog($reservation_id, $computer_id, "startvm", "powered on $computer_name"); } } # VM is created and loading, execute "post_load" if ($self->os->can("post_load")) { if ($self->os->post_load()) { insertloadlog($reservation_id, $computer_id, "loadimagecomplete", "performed OS post-load tasks for $computer_name"); } else { notify($ERRORS{'WARNING'}, 0, "failed to perform OS post-load tasks on $computer_name"); return; } } else { insertloadlog($reservation_id, $computer_id, "loadimagecomplete", "OS post-load tasks not necessary $computer_name"); } return 1; } #////////////////////////////////////////////////////////////////////////////// =head2 does_image_exist Parameters : imagename Returns : 0 or 1 Description : scans our image local image library for requested image returns 1 if found or 0 if not attempts to scp image files from peer management nodes =cut sub does_image_exist { 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; } my $image_name = $self->data->get_image_name(); if (!$image_name) { notify($ERRORS{'WARNING'}, 0, "unable to determine image name"); return; } my $one_image_id = $self->_one_get_object_id("image",$image_name); if ($one_image_id) { notify($ERRORS{'DEBUG'}, 0, "Found image $image_name with id $one_image_id"); return $one_image_id; } notify($ERRORS{'DEBUG'}, 0, "Image $image_name NOT found on ONE"); return 0; } #////////////////////////////////////////////////////////////////////////////// #////////////////////////////////////////////////////////////////////////////// =head2 capture Parameters : Returns : Description : =cut 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; } =head2 power_off Parameters : 'hard' (optional), execute shutdown-hard Returns : Description : send 'shutdown' to VM via controller. * need to add check if VM is OFF. Sometimes VM won't power off * =cut sub power_off { 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 $action = shift; my $computer_name = $self->data->get_computer_hostname(); my $vmid = $self->_one_get_object_id("computer",$computer_name); my @poweroff; if (defined($action) and $action eq 'hard') { @poweroff = $one{'server'}->call('one.vm.action', $one{'auth'},'shutdown-hard',$vmid); } else { @poweroff = $one{'server'}->call('one.vm.action', $one{'auth'},'shutdown',$vmid); } if ($poweroff[0][0]->value()) { notify($ERRORS{'OK'}, 0, "Sent shutdown signal to VM $vmid"); return 1; } else { notify($ERRORS{'DEBUG'}, 0, $poweroff[0][1]); return 0; } } ## end sub power_off =head2 power_reset =cut sub power_reset() { 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 $computer_name = $self->data->get_computer_hostname(); my $vmid = $self->_one_get_object_id("computer",$computer_name); my @poweroff = $one{'server'}->call('one.vm.action', $one{'auth'},'reboot',$vmid); if ($poweroff[0][0]->value()) { notify($ERRORS{'OK'}, 0, "Sent reboot signal to VM $vmid"); return 1; } else { notify($ERRORS{'CRITICAL'}, 0, $poweroff[0][1]); return 0; } } #////////////////////////////////////////////////////////////////////////////// =head2 power_status Parameters : $domain_name (optional) Returns : string Description : Determines the power state of the domain. A string is returned containing one of the following values: * 'on' * 'off' * 'suspended' =cut sub power_status { 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 $computer_name = $self->data->get_computer_hostname(); my $vmid = $self->_one_get_object_id("computer",$computer_name); my @result = $one{'server'}->call('one.vm.info', $one{'auth'},$vmid); if ($result[0][0]->value()) { my $data = $xml->XMLin($result[0][1]); if ($data->{STATE} == 3) { if ($data->{LCM_STATE} == 3) { notify($ERRORS{'OK'}, 0, "vm $vmid is RUNNING, STATE=3 and LCM_STATE=3"); return 'on'; } } } else { notify($ERRORS{'CRITICAL'}, 0, $result[0][1]); return 0; } return 'off'; } ## end sub power_status =head2 power_on Parameters : $domain_name (optional) Returns : string Description : powers on VM =cut sub power_on { 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 $computer_name = $self->data->get_computer_hostname(); my $vmid = $self->_one_get_object_id("computer",$computer_name); #later return 1; } ## end sub power_on #////////////////////////////////////////////////////////////////////////////// =head2 new Parameters : Returns : Description : =cut sub get_image_size { 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; } return $self->_one_get_image_tag_value($self->data->get_image_name(),"SIZE"); } sub _one_get_image_tag_value { my $self = shift; my $image_name = shift; my $tag = shift; my $imid = $self->_one_get_object_id("image",$image_name); my @result = $one{server}->call('one.image.info',$one{'auth'},$imid); if ($result[0][0]->value()) { my $data = $xml->XMLin($result[0][1]); if ($tag eq 'SIZE') { if (defined($data->{$tag})) { return $data->{$tag}; } else { return 0; } } if ($tag eq 'SWAP') { if (defined($data->{TEMPLATE}{$tag})) { return $data->{TEMPLATE}{$tag}; } else { return 0; } } if ($tag eq 'DEV_PREFIX') { if (defined($data->{TEMPLATE}{$tag})) { return $data->{TEMPLATE}{$tag}; } else { return 0; } } } else { notify($ERRORS{'CRITICAL'}, 0, "Error while making one.image.info call: $result[0][1]"); return 0; } notify($ERRORS{'CRITICAL'},0,"requested tag = $tag, don't know how to get it..."); return 0; } sub _one_get_template_id { # in: $template_name # out: $template_id or 0 my $self = shift; my $template_name = shift; my @templatepool_info = $one{'server'}->call('one.templatepool.info',$one{'auth'},-1,-1,-1); if ($templatepool_info[0][0]->value()) { my $data = XMLin($templatepool_info[0][1]); #print Dumper($data); if (ref($data->{VMTEMPLATE}) eq "ARRAY") { foreach (@{$data->{VMTEMPLATE}}) { notify($ERRORS{'OK'}, 0, "Looking for template $template_name in template ID ".$_->{ID}.", name ".$_->{NAME}."..."); if ($_->{NAME} eq $template_name) { notify($ERRORS{'OK'}, 0, "Found template ".$template_name." with ID ".$_->{ID}); return $_->{ID}; } } } else { #HASH, single entry unless (defined($data->{VMTEMPLATE}{NAME})) { notify($ERRORS{'WARNING'}, 0, "Template not found: $template_name"); return 0; } if ($data->{VMTEMPLATE}{NAME} eq $template_name) { notify($ERRORS{'OK'}, 0, "Found template ".$template_name." with ID ".$data->{VMTEMPLATE}{ID}); return $data->{VMTEMPLATE}{ID}; } } } else { notify($ERRORS{'WARNING'}, 0, "Error while making one.templatepool.info call: $templatepool_info[0][1]"); } notify($ERRORS{'WARNING'}, 0, "No value found after one.templatepool.info call for template $template_name"); return 0; } #////////////////////////////////////////////////////////////////////////////// =head2 _one_get_virtio Parameters : imagename Returns : '' or MODEL="virtio" Description : =cut sub _one_get_virtio { my $self = shift; my $one_image_id = shift; my @reply = $one{'server'}->call('one.image.info',$one{'auth'},$one_image_id); if ($reply[0][0]->value()) { my $data = $xml->XMLin($reply[0][1]); if ($data->{TEMPLATE}{DEV_PREFIX} eq 'vd' ) { return ',MODEL="virtio"'; } } else { notify($ERRORS{'WARNING'}, 0, "couldn't get image configuration for image_id $one_image_id, won't use VIRTIO driver."); return ''; } return ''; } #////////////////////////////////////////////////////////////////////////////// =head2 one_wait_for_vm_status Parameters : Returns : Description : =cut sub _one_wait_for_vm_state { my $self = shift; my $vmid = shift; my $state = shift; my $wait = shift; my $sleep = 15; my $num_state = 0; # 6 - POWEROFF $num_state = 6 if ($state eq "SHUTDOWN"); if (!$num_state) { notify($ERRORS{'CRITICAL'}, 0, "Unknown vm_state $state requested"); return 0; } while (1) { notify($ERRORS{'OK'}, 0, "Check state of VM $vmid ..."); my $ttime; my $one_vm_state = $self->_one_get_vm_state($vmid); if ($self->_one_get_vm_state($vmid) == $num_state) { notify($ERRORS{'OK'}, 0, "VM $vmid is in $state state"); return 1; } else { notify($ERRORS{'OK'}, 0, "VM $vmid is NOT in $state state. Waiting $sleep sec..."); sleep $sleep; $ttime = $ttime + $sleep; if ($ttime >= $wait) { notify($ERRORS{'CRITICAL'}, 0, "VM $vmid is still NOT in $state state after $wait sec, abort"); last; } } } return 0; } ## end sub one_wait_for_vm_status # sub _one_get_vm_state { my $self = shift; my $vmid = shift; my @result = $one{'server'}->call('one.vm.info', $one{'auth'},$vmid); if ($result[0][0]->value()) { my $data = $xml->XMLin($result[0][1]); return $data->{STATE}; } else { notify($ERRORS{'CRITICAL'}, 0, $result[0][1]); return 0; } } # gets LCM_STATE values, this sub-state is relevant only when STATE is ACTIVE (3) sub _one_get_vm_lcm_state { my $self = shift; my $vmid = shift; my @result = $one{'server'}->call('one.vm.info', $one{'auth'},$vmid); if ($result[0][0]->value()) { my $data = $xml->XMLin($result[0][1]); if ($data->{STATE} == 3) { return $data->{LCM_STATE}; } else { notify($ERRORS{'DEBUG'}, 0, "Cannot return LCM_STATE of VM $vmid, VM's STATE is not ACTIVE"); return; } } else { notify($ERRORS{'CRITICAL'}, 0, $result[0][1]); return 0; } } sub _one_get_image_state { my $self = shift; my $image_id = shift; my @status = $one{'server'}->call('one.image.info',$one{'auth'},$image_id); if ($status[0][0]->value()) { my $data = $xml->XMLin($status[0][1]); return $data->{STATE}; } else { notify($ERRORS{'CRITICAL'}, 0, $status[0][1]); } } =head2 _one_get_object_id Parameters : $o_type, $o_name Returns : ONE Object ID (INT) Description : =cut sub _one_get_object_id { my $self = shift; my $o_type = shift; my $o_name = shift; if ($o_type eq "computer") { notify($ERRORS{'OK'}, 0, "Searching for running VM $o_name ..."); my @reply = $one{'server'}->call('one.vmpool.info',$one{'auth'},-3,-1,-1,-1); if ($reply[0][0]->value()) { my $data = $xml->XMLin($reply[0][1]); if ((ref($data->{VM})) eq "ARRAY") { foreach (@{$data->{VM}}) { if ($_->{NAME} =~ /^$o_name\s/) { notify($ERRORS{'OK'}, 0, "Found ".$_->{NAME}." matching $o_name in ARRAY"); return $_->{ID}; } } } else { #HASH, found only one entry unless (defined($data->{VM}{NAME})) {return 0;} if ($data->{VM}{NAME} =~ /^$o_name\s/) { notify($ERRORS{'OK'}, 0, "Found ".$data->{VM}{NAME}." matching $o_name in HASH"); return $data->{VM}{ID}; } } } else { notify($ERRORS{'CRITICAL'}, 0, $reply[0][1]); return 0; } } elsif ($o_type eq "image") { my @reply = $one{'server'}->call('one.imagepool.info', $one{'auth'},-3,-1,-1); if ($reply[0][0]->value()) { my $rs_data = $xml->XMLin($reply[0][1]); if ((ref($rs_data->{IMAGE})) eq "ARRAY" ) { foreach (@{$rs_data->{IMAGE}}) { if ($_->{NAME} eq $o_name) { return $_->{ID}; } } } else { #HASH, only one entry if ($rs_data->{IMAGE}{NAME} eq $o_name) { return $rs_data->{IMAGE}{ID}; } } } else { notify($ERRORS{'CRITICAL'}, 0, $reply[0][1]); return 0; } } elsif ($o_type eq "network") { my @reply = $one{'server'}->call('one.vnpool.info',$one{'auth'},-1,-1,-1); if ($reply[0][0]->value()) { my $rs_data = $xml->XMLin($reply[0][1]); # don't check if ARRAY or HASH since we always have more then 1 network foreach (@{$rs_data->{VNET}}) { # if $o_name is in VLAN_ID= then lookup by VLAN_ID, not NAME if ($o_name =~ /^VLAN_ID=/i) { my @vlan_id = split('=',$o_name); if ($_->{VLAN_ID} == $vlan_id[1]) { return $_->{ID}; } } else { if ($_->{NAME} eq $o_name) { return $_->{ID}; } } } } else { notify($ERRORS{'CRITICAL'},0,$reply[0][1]); return 0; } } else { notify($ERRORS{'CRITICAL'}, 0, "$o_type is UNKNOWN type"); return 0; } return 0; } #////////////////////////////////////////////////////////////////////////////// =head2 _one_delete_vm Parameters : $vmid Returns : Description : one.vm.action =cut sub _one_delete_vm { my $self = shift; my $vmid = shift; my @reply; @reply = $one{'server'}->call('one.vm.action', $one{'auth'},'delete',$vmid); if ($reply[0][0]->value()) { notify($ERRORS{'OK'}, 0, "ONE VM $vmid deleted"); } else { notify($ERRORS{'CRITICAL'}, 0, $reply[0][1]); } } sub _one_create_vm { # in: $VM_TEMPLATE in XML # out: new VM ID | 0 my $self = shift; my $VM_TEMPLATE = shift; my @vm_allocate = $one{'server'}->call('one.vm.allocate',$one{'auth'},$VM_TEMPLATE,$one{'false'}); if ($vm_allocate[0][0]->value()) { return $vm_allocate[0][1]; } else { notify($ERRORS{'CRITICAL'}, 0, "Error while making one.vm.allocate call : $vm_allocate[0][1]"); return 0; } } sub _one_create_template { # in: VM_TEMPLATE # OUT: template_id | 0 # http://opennebula.org/documentation:rel4.2:api#onetemplateallocate my $self = shift; my $VM_TEMPLATE = shift; my @template_allocate = $one{'server'}->call('one.template.allocate',$one{'auth'},$VM_TEMPLATE); if ($template_allocate[0][0]->value()) { notify($ERRORS{'OK'}, 0, "New template created with id $template_allocate[0][1]"); } else { notify($ERRORS{'CRITICAL'}, 0, "Error while making one.template.allocate call : $template_allocate[0][1]"); } } sub _one_get_vm_disk { my $self = shift; my $vmid = shift; my @vm_info = $one{'server'}->call('one.vm.info', $one{'auth'},$vmid); if ($vm_info[0][0]->value()) { my $data = $xml->XMLin($vm_info[0][1]); if ((ref($data->{TEMPLATE}{DISK})) eq "ARRAY" ) { # template has multiple disks, return [0] return $data->{TEMPLATE}{DISK}[0]{IMAGE}; } else { #template has one disk return $data->{TEMPLATE}{DISK}{IMAGE}; } } else { notify($ERRORS{'CRITICAL'}, 0, "Error while making one.vm.info call : $vm_info[0][1]"); } } 1; __END__