blob: 10df935e571b7d12ff1860873cf727289a85199f [file] [log] [blame]
#!/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';
# 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__