diff --git a/include/DispatchManager.h b/include/DispatchManager.h index 1bf3e4cf22..2ad6b03649 100644 --- a/include/DispatchManager.h +++ b/include/DispatchManager.h @@ -219,6 +219,17 @@ public: int reboot( int vid); + /** + * Set the re-scheduling flag for the VM (must be in RUNNING state) + * @param vid VirtualMachine identification + * @param do_resched set or unset the flag + * @return 0 on success, -1 if the VM does not exits or -2 if the VM is + * in a wrong a state + */ + int resched( + int vid, + bool do_resched); + private: /** * Thread id for the Dispatch Manager diff --git a/include/Image.h b/include/Image.h index 871046a443..3b4027b9bf 100644 --- a/include/Image.h +++ b/include/Image.h @@ -329,13 +329,18 @@ public: * Modifies the given disk attribute adding the following attributes: * * SOURCE: the file-path. * * BUS: will only be set if the Image's definition includes it. - * * TARGET: if not set uses that in the image template + * * TARGET: will only be set if the Image's definition includes it. + * * @param disk attribute for the VM template - * - * @return -1 if there is no TARGET in the disk nor in the template, 0 - * otherwise + * @param img_type will be set to the used image's type + * @param dev_prefix will be set to the defined dev_prefix, + * or the default one + * + * @return 0 on success, -1 otherwise */ - int disk_attribute(VectorAttribute * disk); + int disk_attribute( VectorAttribute * disk, + ImageType& img_type, + string& dev_prefix); /** * Factory method for image templates diff --git a/include/ImagePool.h b/include/ImagePool.h index e4792b6677..1bc30383cd 100644 --- a/include/ImagePool.h +++ b/include/ImagePool.h @@ -40,6 +40,7 @@ public: ImagePool(SqlDB * db, const string& _default_type, + const string& _default_dev_prefix, vector& restricted_attrs); ~ImagePool(){}; @@ -133,17 +134,22 @@ public: /** * Generates a DISK attribute for VM templates using the Image metadata + * * @param disk the disk to be generated * @param disk_id the id for this disk + * @param img_type will be set to the used image's type + * @param dev_prefix will be set to the image defined dev_prefix, + * or the default one * @param uid of VM owner (to look for the image id within its images) * @param image_id on success returns the acquired image id * @param error_str string describing the error - * @return 0 on success, - * -1 error, - * -2 not using the pool, + * + * @return 0 on success, -1 otherwise */ int disk_attribute(VectorAttribute * disk, int disk_id, + Image::ImageType& img_type, + string& dev_prefix, int uid, int& image_id, string& error_str); @@ -160,6 +166,11 @@ public: return _default_type; }; + static const string& default_dev_prefix() + { + return _default_dev_prefix; + }; + private: //-------------------------------------------------------------------------- // Configuration Attributes for Images @@ -170,6 +181,11 @@ private: **/ static string _default_type; + /** + * Default device prefix + **/ + static string _default_dev_prefix; + //-------------------------------------------------------------------------- // Pool Attributes // ------------------------------------------------------------------------- diff --git a/include/RequestManagerVirtualMachine.h b/include/RequestManagerVirtualMachine.h index 6b5472807e..2955bbd79b 100644 --- a/include/RequestManagerVirtualMachine.h +++ b/include/RequestManagerVirtualMachine.h @@ -49,10 +49,11 @@ protected: RequestAttributes& att) = 0; bool vm_authorization(int id, - ImageTemplate * tmpl, - RequestAttributes& att, - PoolObjectAuth * host_perms, - PoolObjectAuth * ds_perm); + ImageTemplate * tmpl, + RequestAttributes& att, + PoolObjectAuth * host_perms, + PoolObjectAuth * ds_perm, + AuthRequest::Operation op); int get_host_information(int hid, string& name, string& vmm, string& vnm, RequestAttributes& att, PoolObjectAuth& host_perms); @@ -73,6 +74,8 @@ protected: class VirtualMachineAction : public RequestManagerVirtualMachine { public: + //auth_op is MANAGE for all actions but "resched" and "unresched" + //this is dynamically set for each request in the execute method VirtualMachineAction(): RequestManagerVirtualMachine("VirtualMachineAction", "Performs an action on a virtual machine", diff --git a/include/VirtualMachine.h b/include/VirtualMachine.h index 9254ec2b4c..be2ba87c0f 100644 --- a/include/VirtualMachine.h +++ b/include/VirtualMachine.h @@ -586,6 +586,22 @@ public: lcm_state = s; }; + /** + * Sets the re-scheduling flag + * @param set or unset the re-schedule flag + */ + void set_resched(bool do_sched) + { + if ( do_sched == true ) + { + resched = 1; + } + else + { + resched = 0; + } + }; + // ------------------------------------------------------------------------ // Timers // ------------------------------------------------------------------------ @@ -720,6 +736,11 @@ private: */ LcmState lcm_state; + /** + * Marks the VM as to be re-scheduled + */ + int resched; + /** * Start time, the VM enter the nebula system (in epoch) */ diff --git a/include/test/NebulaTest.h b/include/test/NebulaTest.h index 754289367c..bd73d4f201 100644 --- a/include/test/NebulaTest.h +++ b/include/test/NebulaTest.h @@ -104,7 +104,8 @@ public: virtual UserPool* create_upool(SqlDB* db); - virtual ImagePool* create_ipool(SqlDB* db, + virtual ImagePool* create_ipool( SqlDB* db, + string default_image_type, string default_device_prefix); virtual VMTemplatePool* create_tpool(SqlDB* db); diff --git a/install.sh b/install.sh index 5db567dd3b..c668e02297 100755 --- a/install.sh +++ b/install.sh @@ -230,6 +230,7 @@ VAR_DIRS="$VAR_LOCATION/remotes \ $VAR_LOCATION/remotes/tm/ssh \ $VAR_LOCATION/remotes/tm/vmware \ $VAR_LOCATION/remotes/tm/iscsi \ + $VAR_LOCATION/remotes/tm/lvm \ $VAR_LOCATION/remotes/hooks \ $VAR_LOCATION/remotes/hooks/ft \ $VAR_LOCATION/remotes/datastore \ @@ -237,6 +238,7 @@ VAR_DIRS="$VAR_LOCATION/remotes \ $VAR_LOCATION/remotes/datastore/fs \ $VAR_LOCATION/remotes/datastore/vmware \ $VAR_LOCATION/remotes/datastore/iscsi \ + $VAR_LOCATION/remotes/datastore/lvm \ $VAR_LOCATION/remotes/auth \ $VAR_LOCATION/remotes/auth/plain \ $VAR_LOCATION/remotes/auth/ssh \ @@ -391,12 +393,14 @@ INSTALL_FILES=( TM_SSH_FILES:$VAR_LOCATION/remotes/tm/ssh TM_VMWARE_FILES:$VAR_LOCATION/remotes/tm/vmware TM_ISCSI_FILES:$VAR_LOCATION/remotes/tm/iscsi + TM_LVM_FILES:$VAR_LOCATION/remotes/tm/lvm TM_DUMMY_FILES:$VAR_LOCATION/remotes/tm/dummy DATASTORE_DRIVER_COMMON_SCRIPTS:$VAR_LOCATION/remotes/datastore/ DATASTORE_DRIVER_DUMMY_SCRIPTS:$VAR_LOCATION/remotes/datastore/dummy DATASTORE_DRIVER_FS_SCRIPTS:$VAR_LOCATION/remotes/datastore/fs DATASTORE_DRIVER_VMWARE_SCRIPTS:$VAR_LOCATION/remotes/datastore/vmware DATASTORE_DRIVER_ISCSI_SCRIPTS:$VAR_LOCATION/remotes/datastore/iscsi + DATASTORE_DRIVER_LVM_SCRIPTS:$VAR_LOCATION/remotes/datastore/lvm NETWORK_FILES:$VAR_LOCATION/remotes/vnm NETWORK_8021Q_FILES:$VAR_LOCATION/remotes/vnm/802.1Q NETWORK_DUMMY_FILES:$VAR_LOCATION/remotes/vnm/dummy @@ -769,6 +773,7 @@ NETWORK_VMWARE_FILES="src/vnm_mad/remotes/vmware/clean \ # - DUMMY TM, $VAR_LOCATION/tm/dummy # - VMWARE TM, $VAR_LOCATION/tm/vmware # - ISCSI TM, $VAR_LOCATION/tm/iscsi +# - LVM TM, $VAR_LOCATION/tm/lvm #------------------------------------------------------------------------------- TM_FILES="src/tm_mad/tm_common.sh" @@ -823,10 +828,20 @@ TM_ISCSI_FILES="src/tm_mad/iscsi/clone \ src/tm_mad/iscsi/mv \ src/tm_mad/iscsi/mvds \ src/tm_mad/iscsi/delete" + +TM_LVM_FILES="src/tm_mad/lvm/clone \ + src/tm_mad/lvm/ln \ + src/tm_mad/lvm/mv \ + src/tm_mad/lvm/mvds \ + src/tm_mad/lvm/delete" + #------------------------------------------------------------------------------- # Datastore drivers, to be installed under $REMOTES_LOCATION/datastore +# - Dummy Image Repository, $REMOTES_LOCATION/datastore/dummy # - FS based Image Repository, $REMOTES_LOCATION/datastore/fs # - VMware based Image Repository, $REMOTES_LOCATION/datastore/vmware +# - iSCSI based Image Repository, $REMOTES_LOCATION/datastore/iscsi +# - LVM based Image Repository, $REMOTES_LOCATION/datastore/lvm #------------------------------------------------------------------------------- DATASTORE_DRIVER_COMMON_SCRIPTS="src/datastore_mad/remotes/xpath.rb \ @@ -849,6 +864,11 @@ DATASTORE_DRIVER_ISCSI_SCRIPTS="src/datastore_mad/remotes/iscsi/cp \ src/datastore_mad/remotes/iscsi/rm \ src/datastore_mad/remotes/iscsi/iscsi.conf" +DATASTORE_DRIVER_LVM_SCRIPTS="src/datastore_mad/remotes/lvm/cp \ + src/datastore_mad/remotes/lvm/mkfs \ + src/datastore_mad/remotes/lvm/rm \ + src/datastore_mad/remotes/lvm/lvm.conf" + #------------------------------------------------------------------------------- # Migration scripts for onedb command, to be installed under $LIB_LOCATION #------------------------------------------------------------------------------- diff --git a/share/etc/oned.conf b/share/etc/oned.conf index c49a503ecd..0bf1cd0492 100644 --- a/share/etc/oned.conf +++ b/share/etc/oned.conf @@ -88,11 +88,19 @@ MAC_PREFIX = "02:00" # DEFAULT_IMAGE_TYPE: This can take values # OS Image file holding an operating system # CDROM Image file holding a CDROM -# DATABLOCK Image file holding a datablock, created as an empty block +# DATABLOCK Image file holding a datablock, +# always created as an empty block +# DEFAULT_DEVICE_PREFIX: This can be set to +# hd IDE prefix +# sd SCSI +# xvd XEN Virtual Disk +# vd KVM virtual disk #******************************************************************************* #DATASTORE_LOCATION = /var/lib/one/datastores -DEFAULT_IMAGE_TYPE = "OS" + +DEFAULT_IMAGE_TYPE = "OS" +DEFAULT_DEVICE_PREFIX = "hd" #******************************************************************************* # Information Driver Configuration diff --git a/src/acct/watch_client.rb b/src/acct/watch_client.rb index 7a63251a48..c3da4289bf 100644 --- a/src/acct/watch_client.rb +++ b/src/acct/watch_client.rb @@ -154,7 +154,7 @@ module OneWatchClient if filter[:uid] filter[:uid]==0 ? (hosts = pool) : (return nil) elsif filter[:gid] - filter[:uid]==0 ? (hosts = pool) : (return nil) + filter[:gid]==0 ? (hosts = pool) : (return nil) else hosts = pool end diff --git a/src/cli/one_helper/onevm_helper.rb b/src/cli/one_helper/onevm_helper.rb index b772ce61bb..b7d32be70d 100644 --- a/src/cli/one_helper/onevm_helper.rb +++ b/src/cli/one_helper/onevm_helper.rb @@ -57,7 +57,11 @@ class OneVMHelper < OpenNebulaHelper::OneHelper column :NAME, "Name of the Virtual Machine", :left, :size=>15 do |d| - d["NAME"] + if d["RESCHED"] == "1" + "*#{d["NAME"]}" + else + d["NAME"] + end end column :USER, "Username of the Virtual Machine owner", :left, @@ -132,6 +136,7 @@ class OneVMHelper < OpenNebulaHelper::OneHelper puts str % ["GROUP", vm['GNAME']] puts str % ["STATE", vm.state_str] puts str % ["LCM_STATE", vm.lcm_state_str] + puts str % ["RESCHED", OpenNebulaHelper.boolean_to_str(vm['RESCHED'])] puts str % ["HOSTNAME", vm['/VM/HISTORY_RECORDS/HISTORY[last()]/HOSTNAME']] if %w{ACTIVE SUSPENDED}.include? vm.state_str diff --git a/src/cli/onevm b/src/cli/onevm index e8dd16b71f..ddf1d7d52f 100755 --- a/src/cli/onevm +++ b/src/cli/onevm @@ -354,6 +354,30 @@ cmd=CommandParser::CmdParser.new(ARGV) do end end + resched_desc = <<-EOT.unindent + Sets the rescheduling flag for the VM. + + States: RUNNING + EOT + + command :resched, resched_desc, [:range,:vmid_list] do + helper.perform_actions(args[0],options,"Setting resched flag") do |vm| + vm.resched + end + end + + unresched_desc = <<-EOT.unindent + Clears the rescheduling flag for the VM. + + States: RUNNING + EOT + + command :unresched, unresched_desc, [:range,:vmid_list] do + helper.perform_actions(args[0],options,"Clearing resched flag") do |vm| + vm.unresched + end + end + list_desc = <<-EOT.unindent Lists VMs in the pool EOT diff --git a/src/cloud/ec2/etc/templates/m1.small.erb b/src/cloud/ec2/etc/templates/m1.small.erb index 3f9ad0a8b8..4883e539fd 100644 --- a/src/cloud/ec2/etc/templates/m1.small.erb +++ b/src/cloud/ec2/etc/templates/m1.small.erb @@ -11,7 +11,7 @@ MEMORY = 256 # root = sda1, # kernel_cmd = "ro xencons=tty console=tty1"] -DISK = [ IMAGE_ID = <%= erb_vm_info[:img_id] %>, TARGET = "hda" ] +DISK = [ IMAGE_ID = <%= erb_vm_info[:img_id] %> ] # Put here the ID of the VNET with the IPs for the EC2 VMs NIC=[NETWORK_ID=] @@ -20,8 +20,5 @@ IMAGE_ID = <%= erb_vm_info[:ec2_img_id] %> INSTANCE_TYPE = <%= erb_vm_info[:instance_type ]%> <% if erb_vm_info[:user_data] %> -CONTEXT = [ - EC2_USER_DATA="<%= erb_vm_info[:user_data] %>", - TARGET="hdb" - ] +CONTEXT = [ EC2_USER_DATA="<%= erb_vm_info[:user_data] %>" ] <% end %> diff --git a/src/cloud/occi/bin/occi-compute b/src/cloud/occi/bin/occi-compute index 85277961e4..722ee2a91c 100755 --- a/src/cloud/occi/bin/occi-compute +++ b/src/cloud/occi/bin/occi-compute @@ -93,7 +93,8 @@ opts = GetoptLong.new( ['--url', '-R',GetoptLong::REQUIRED_ARGUMENT], ['--timeout', '-T',GetoptLong::REQUIRED_ARGUMENT], ['--debug', '-D',GetoptLong::NO_ARGUMENT], - ['--verbose', GetoptLong::NO_ARGUMENT] + ['--verbose', GetoptLong::NO_ARGUMENT], + ['--plain', GetoptLong::NO_ARGUMENT] ) url = nil @@ -103,6 +104,7 @@ auth = nil timeout = nil debug = false verbose = false +plain = false begin opts.each do |opt, arg| @@ -125,6 +127,8 @@ begin debug = true when '--verbose' verbose = true + when '--plain' + plain = true end end rescue Exception => e @@ -132,7 +136,7 @@ rescue Exception => e end begin - occi_client = OCCIClient::Client.new(url,username,password, timeout, debug) + occi_client = OCCIClient::Client.new(url,username,password, timeout, debug, plain) rescue Exception => e puts "#{cmd_name}: #{e.message}" exit(-1) diff --git a/src/cloud/occi/bin/occi-instance-type b/src/cloud/occi/bin/occi-instance-type index f4482fabc9..a05294b13a 100755 --- a/src/cloud/occi/bin/occi-instance-type +++ b/src/cloud/occi/bin/occi-instance-type @@ -62,6 +62,9 @@ Options: --verbose Show resources in verbose mode +--plain + The password provided will not be hashed + EOT require 'occi/OCCIClient' @@ -77,7 +80,8 @@ opts = GetoptLong.new( ['--url', '-R',GetoptLong::REQUIRED_ARGUMENT], ['--timeout', '-T',GetoptLong::REQUIRED_ARGUMENT], ['--debug', '-D',GetoptLong::NO_ARGUMENT], - ['--verbose', GetoptLong::NO_ARGUMENT] + ['--verbose', GetoptLong::NO_ARGUMENT], + ['--plain', GetoptLong::NO_ARGUMENT] ) url = nil @@ -87,6 +91,7 @@ auth = nil timeout = nil debug = false verbose = false +plain = false begin opts.each do |opt, arg| @@ -109,6 +114,8 @@ begin debug = true when '--verbose' verbose = true + when '--plain' + plain = true end end rescue Exception => e @@ -116,7 +123,7 @@ rescue Exception => e end begin - occi_client = OCCIClient::Client.new(url,username,password, timeout, debug) + occi_client = OCCIClient::Client.new(url,username,password, timeout, debug,plain) rescue Exception => e puts "#{cmd_name}: #{e.message}" exit(-1) diff --git a/src/cloud/occi/bin/occi-network b/src/cloud/occi/bin/occi-network index d2377bb31c..e2af20c6fb 100755 --- a/src/cloud/occi/bin/occi-network +++ b/src/cloud/occi/bin/occi-network @@ -79,6 +79,9 @@ Options: --verbose Show resources in verbose mode +--plain + The password provided will not be hashed + EOT require 'occi/OCCIClient' @@ -94,7 +97,8 @@ opts = GetoptLong.new( ['--url', '-R',GetoptLong::REQUIRED_ARGUMENT], ['--timeout', '-T',GetoptLong::REQUIRED_ARGUMENT], ['--debug', '-D',GetoptLong::NO_ARGUMENT], - ['--verbose', GetoptLong::NO_ARGUMENT] + ['--verbose', GetoptLong::NO_ARGUMENT], + ['--plain', GetoptLong::NO_ARGUMENT] ) url = nil @@ -104,6 +108,7 @@ auth = nil timeout = nil debug = false verbose = false +plain = false begin opts.each do |opt, arg| @@ -126,6 +131,8 @@ begin debug = true when '--verbose' verbose = true + when '--plain' + plain = true end end rescue Exception => e @@ -133,7 +140,7 @@ rescue Exception => e end begin - occi_client = OCCIClient::Client.new(url,username,password,timeout,debug) + occi_client = OCCIClient::Client.new(url,username,password,timeout,debug,plain) rescue Exception => e puts "#{cmd_name}: #{e.message}" exit(-1) diff --git a/src/cloud/occi/bin/occi-server b/src/cloud/occi/bin/occi-server index e9615a2108..72625a1d61 100755 --- a/src/cloud/occi/bin/occi-server +++ b/src/cloud/occi/bin/occi-server @@ -54,7 +54,7 @@ setup() start() { - if [ ! -x "$OCCI_SERVER" ]; then + if [ ! -f "$OCCI_SERVER" ]; then echo "Cannot find $OCCI_SERVER." exit 1 fi diff --git a/src/cloud/occi/bin/occi-storage b/src/cloud/occi/bin/occi-storage index fb9eddb375..ad70987f71 100755 --- a/src/cloud/occi/bin/occi-storage +++ b/src/cloud/occi/bin/occi-storage @@ -82,6 +82,9 @@ Options: --verbose Show resources in verbose mode +--plain + The password provided will not be hashed + EOT require 'occi/OCCIClient' @@ -99,7 +102,8 @@ opts = GetoptLong.new( ['--debug', '-D',GetoptLong::NO_ARGUMENT], ['--timeout', '-T',GetoptLong::REQUIRED_ARGUMENT], ['--multipart', '-M',GetoptLong::NO_ARGUMENT], - ['--verbose', GetoptLong::NO_ARGUMENT] + ['--verbose', GetoptLong::NO_ARGUMENT], + ['--plain', GetoptLong::NO_ARGUMENT] ) url = nil @@ -110,6 +114,7 @@ timeout = nil debug = false curb = true verbose = false +plain = false begin opts.each do |opt, arg| @@ -134,6 +139,8 @@ begin curb = false when '--verbose' verbose = true + when '--plain' + plain = true end end rescue Exception => e @@ -148,7 +155,7 @@ end begin - occi_client = OCCIClient::Client.new(url,username,password,timeout,debug) + occi_client = OCCIClient::Client.new(url,username,password,timeout,debug,plain) rescue Exception => e puts "#{cmd_name}: #{e.message}" exit(-1) diff --git a/src/cloud/occi/lib/OCCIClient.rb b/src/cloud/occi/lib/OCCIClient.rb index 1844d90e58..9b1ffbf600 100755 --- a/src/cloud/occi/lib/OCCIClient.rb +++ b/src/cloud/occi/lib/OCCIClient.rb @@ -36,7 +36,7 @@ module OCCIClient # Initialize client library ###################################################################### def initialize(endpoint_str=nil, user=nil, pass=nil, - timeout=nil, debug_flag=true) + timeout=nil, debug_flag=true, plain=false) @debug = debug_flag @timeout = timeout @@ -60,7 +60,7 @@ module OCCIClient raise "No authorization data present" end - @occiauth[1] = Digest::SHA1.hexdigest(@occiauth[1]) + @occiauth[1] = Digest::SHA1.hexdigest(@occiauth[1]) unless plain end ################################# diff --git a/src/datastore_mad/remotes/lvm/cp b/src/datastore_mad/remotes/lvm/cp new file mode 100755 index 0000000000..6c95b0c814 --- /dev/null +++ b/src/datastore_mad/remotes/lvm/cp @@ -0,0 +1,104 @@ +#!/bin/bash + +# -------------------------------------------------------------------------- # +# Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) # +# # +# Licensed 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. # +#--------------------------------------------------------------------------- # + +############################################################################### +# This script is used to copy a VM image (SRC) to the image repository as DST +# Several SRC types are supported +############################################################################### + +# -------- Set up the environment to source common tools & conf ------------ + +if [ -z "${ONE_LOCATION}" ]; then + LIB_LOCATION=/usr/lib/one +else + LIB_LOCATION=$ONE_LOCATION/lib +fi + +. $LIB_LOCATION/sh/scripts_common.sh + +DRIVER_PATH=$(dirname $0) +source ${DRIVER_PATH}/../libfs.sh +source ${DRIVER_PATH}/lvm.conf + +# -------- Get cp and datastore arguments from OpenNebula core ------------ + +DRV_ACTION=$1 +ID=$2 + +XPATH="${DRIVER_PATH}/../xpath.rb -b $DRV_ACTION" + +unset i XPATH_ELEMENTS + +while IFS= read -r -d '' element; do + XPATH_ELEMENTS[i++]="$element" +done < <($XPATH /DS_DRIVER_ACTION_DATA/DATASTORE/BASE_PATH \ + /DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/RESTRICTED_DIRS \ + /DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/SAFE_DIRS \ + /DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/UMASK \ + /DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/HOST \ + /DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VG_NAME \ + /DS_DRIVER_ACTION_DATA/IMAGE/PATH) + +BASE_PATH="${XPATH_ELEMENTS[0]}" +RESTRICTED_DIRS="${XPATH_ELEMENTS[1]}" +SAFE_DIRS="${XPATH_ELEMENTS[2]}" +UMASK="${XPATH_ELEMENTS[3]}" +DST_HOST="${XPATH_ELEMENTS[4]:-$HOST}" +VG_NAME="${XPATH_ELEMENTS[5]:-$VG_NAME}" +SRC="${XPATH_ELEMENTS[6]}" + +set_up_datastore "$BASE_PATH" "$RESTRICTED_DIRS" "$SAFE_DIRS" "$UMASK" + +SIZE=`fs_du $SRC` + +LV_NAME="lv-one-${ID}" +LVM_SOURCE="$DST_HOST:$VG_NAME.$LV_NAME" +DEV="/dev/$VG_NAME/$LV_NAME" + +REGISTER_CMD=$(cat < e @@ -42,7 +48,13 @@ end values = "" -tmp = Base64::decode64(tmp64) +case source +when :stdin + tmp = STDIN.read +when :b64 + tmp = Base64::decode64(tmp64) +end + xml = REXML::Document.new(tmp).root ARGV.each do |xpath| diff --git a/src/dm/DispatchManagerActions.cc b/src/dm/DispatchManagerActions.cc index 4907ed7194..f573c3218d 100644 --- a/src/dm/DispatchManagerActions.cc +++ b/src/dm/DispatchManagerActions.cc @@ -580,6 +580,52 @@ error: return -2; } + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int DispatchManager::resched(int vid, bool do_resched) +{ + VirtualMachine * vm; + ostringstream oss; + + vm = vmpool->get(vid,true); + + if ( vm == 0 ) + { + return -1; + } + + oss << "Setting rescheduling flag on VM " << vid; + NebulaLog::log("DiM",Log::DEBUG,oss); + + if (vm->get_state() == VirtualMachine::ACTIVE && + vm->get_lcm_state() == VirtualMachine::RUNNING ) + { + Nebula& nd = Nebula::instance(); + LifeCycleManager * lcm = nd.get_lcm(); + + vm->set_resched(do_resched); + vmpool->update(vm); + } + else + { + goto error; + } + + vm->unlock(); + + return 0; + +error: + oss.str(""); + oss << "Could not set rescheduling flag for VM " << vid << ", wrong state."; + NebulaLog::log("DiM",Log::ERROR,oss); + + vm->unlock(); + + return -2; +} /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ diff --git a/src/image/Image.cc b/src/image/Image.cc index 389b7ef0fd..b0eb1b53a9 100644 --- a/src/image/Image.cc +++ b/src/image/Image.cc @@ -130,6 +130,17 @@ int Image::insert(SqlDB *db, string& error_str) persistent_img = (persistent_attr == "YES"); + // ------------ PREFIX -------------------- + + get_template_attribute("DEV_PREFIX", dev_prefix); + + if( dev_prefix.empty() ) + { + SingleAttribute * dev_att = new SingleAttribute("DEV_PREFIX", + ImagePool::default_dev_prefix()); + obj_template->set(dev_att); + } + // ------------ PATH & SOURCE -------------------- erase_template_attribute("PATH", path); @@ -426,7 +437,9 @@ int Image::from_xml(const string& xml) /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ -int Image::disk_attribute(VectorAttribute * disk) +int Image::disk_attribute( VectorAttribute * disk, + ImageType& img_type, + string& dev_prefix) { string bus; string target; @@ -435,9 +448,10 @@ int Image::disk_attribute(VectorAttribute * disk) ostringstream iid; - bus = disk->vector_value("BUS"); - target = disk->vector_value("TARGET"); - driver = disk->vector_value("DRIVER"); + img_type = type; + bus = disk->vector_value("BUS"); + target = disk->vector_value("TARGET"); + driver = disk->vector_value("DRIVER"); iid << oid; string template_bus; @@ -448,19 +462,11 @@ int Image::disk_attribute(VectorAttribute * disk) get_template_attribute("TARGET", template_target); get_template_attribute("DRIVER", template_driver); - //--------------------------------------------------------------------------- - // TARGET attribute - //--------------------------------------------------------------------------- - if (target.empty()) + get_template_attribute("DEV_PREFIX", dev_prefix); + + if (dev_prefix.empty())//Removed from image template, get it again from defaults { - if (!template_target.empty()) - { - disk->replace("TARGET", template_target); - } - else //No TARGET in DISK nor in Image (ERROR!) - { - return -1; - } + dev_prefix = ImagePool::default_dev_prefix(); } //--------------------------------------------------------------------------- @@ -510,7 +516,17 @@ int Image::disk_attribute(VectorAttribute * disk) } disk->replace("TYPE",disk_attr_type); - + + //--------------------------------------------------------------------------- + // TARGET attribute + //--------------------------------------------------------------------------- + + // TARGET defined in the Image template, but not in the DISK attribute + if ( target.empty() && !template_target.empty() ) + { + disk->replace("TARGET", template_target); + } + return 0; } diff --git a/src/image/ImagePool.cc b/src/image/ImagePool.cc index 48ad8be838..251c037a0e 100644 --- a/src/image/ImagePool.cc +++ b/src/image/ImagePool.cc @@ -26,12 +26,14 @@ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ string ImagePool::_default_type; +string ImagePool::_default_dev_prefix; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -ImagePool::ImagePool(SqlDB * db, - const string& __default_type, +ImagePool::ImagePool(SqlDB * db, + const string& __default_type, + const string& __default_dev_prefix, vector& restricted_attrs): PoolSQL(db, Image::table, true) { @@ -39,6 +41,7 @@ ImagePool::ImagePool(SqlDB * db, // Init static defaults _default_type = __default_type; + _default_dev_prefix = __default_dev_prefix; // Set default type if (_default_type != "OS" && @@ -211,11 +214,13 @@ static int get_disk_id(const string& id_s) /* -------------------------------------------------------------------------- */ -int ImagePool::disk_attribute(VectorAttribute * disk, - int disk_id, - int uid, - int& image_id, - string& error_str) +int ImagePool::disk_attribute(VectorAttribute * disk, + int disk_id, + Image::ImageType& img_type, + string& dev_prefix, + int uid, + int& image_id, + string& error_str) { string source; Image * img = 0; @@ -272,13 +277,8 @@ int ImagePool::disk_attribute(VectorAttribute * disk, if ( type == "SWAP" || type == "FS" ) { - string target = disk->vector_value("TARGET"); - - if ( target.empty() ) - { - error_str = "Missing target for disk of type " + type; - return -1; - } + dev_prefix = _default_dev_prefix; + img_type = Image::DATABLOCK; } else { @@ -293,7 +293,7 @@ int ImagePool::disk_attribute(VectorAttribute * disk, Datastore * ds; iid = img->get_oid(); - rc = img->disk_attribute(disk); + rc = img->disk_attribute(disk, img_type, dev_prefix); image_id = img->get_oid(); datastore_id = img->get_ds_id(); @@ -303,7 +303,7 @@ int ImagePool::disk_attribute(VectorAttribute * disk, if (rc == -1) { imagem->release_image(iid, false); - error_str = "Missing TARGET in disk"; + error_str = "Unknown internal error"; return -1; } diff --git a/src/image/test/ImagePoolTest.cc b/src/image/test/ImagePoolTest.cc index ab63e93cf5..11f1d82003 100644 --- a/src/image/test/ImagePoolTest.cc +++ b/src/image/test/ImagePoolTest.cc @@ -90,10 +90,12 @@ class ImagePoolFriend : public ImagePool public: ImagePoolFriend(SqlDB * db, const string& _default_type, + const string& _default_dev_prefix, vector _restricted_attrs): ImagePool( db, _default_type, + _default_dev_prefix, _restricted_attrs){}; @@ -113,7 +115,7 @@ public: string gname = gnames[uid]; return ImagePool::allocate(uid, 1, uname, gname, - img_template, 0, "none", "", oid, err); + img_template, 0,"none", "", oid, err); } else { @@ -143,6 +145,7 @@ class ImagePoolTest : public PoolTest CPPUNIT_TEST ( duplicates ); CPPUNIT_TEST ( extra_attributes ); CPPUNIT_TEST ( wrong_templates ); + CPPUNIT_TEST ( target_generation ); CPPUNIT_TEST ( bus_source_assignment ); CPPUNIT_TEST ( persistence ); CPPUNIT_TEST ( imagepool_disk_attribute ); @@ -253,7 +256,7 @@ public: // Create a new pool, using the same DB. This new pool should read the // allocated images. vector restricted_attrs; - imp = new ImagePool(db,"OS", restricted_attrs); + imp = new ImagePool(db,"OS", "hd", restricted_attrs); img = imp->get(0, false); CPPUNIT_ASSERT( img != 0 ); @@ -424,6 +427,107 @@ public: } } +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + + void target_generation() + { + ImagePoolFriend * imp = static_cast(pool); + Image * img; + + VectorAttribute * disk; + int oid; + string value; + int index=0; + Image::ImageType img_type; + + disk = new VectorAttribute("DISK"); + + // Allocate an OS type image + oid = allocate(0); + img = imp->get(oid, false); + + CPPUNIT_ASSERT( img != 0 ); + CPPUNIT_ASSERT( oid == 0 ); + + img->set_state(Image::READY); + img->disk_attribute(disk, &index, &img_type); + + value = disk->vector_value("TARGET"); + + CPPUNIT_ASSERT( value == "hda" ); + CPPUNIT_ASSERT( img_type == Image::OS ); + + // clean up + delete disk; + value = ""; + + disk = new VectorAttribute("DISK"); + + // Allocate a CDROM type image + string templ = "NAME = \"name A\" TYPE = CDROM PATH = /tmp"; + imp->allocate(0, templ, &oid); + + CPPUNIT_ASSERT(oid >= 0); + + img = imp->get(oid, false); + CPPUNIT_ASSERT( img != 0 ); + + img->set_state(Image::READY); + img->disk_attribute(disk, &index, &img_type); + + value = disk->vector_value("TARGET"); + CPPUNIT_ASSERT(value == "hdc"); + CPPUNIT_ASSERT( img_type == Image::CDROM ); + + // clean up + delete disk; + value = ""; + + disk = new VectorAttribute("DISK"); + + // Allocate a DATABLOCK type image + templ = "NAME = \"name B\" TYPE = DATABLOCK PATH=\"/dev/null\""; + imp->allocate(0, templ, &oid); + + CPPUNIT_ASSERT(oid >= 0); + + img = imp->get(oid, false); + CPPUNIT_ASSERT( img != 0 ); + + img->set_state(Image::READY); + img->disk_attribute(disk, &index, &img_type); + + value = disk->vector_value("TARGET"); + CPPUNIT_ASSERT(value == "hde"); + CPPUNIT_ASSERT( img_type == Image::DATABLOCK ); + + // clean up + delete disk; + value = ""; + + disk = new VectorAttribute("DISK"); + + // Allocate a DATABLOCK type image + templ = "NAME = \"name C\" TYPE = DATABLOCK DEV_PREFIX = \"sd\"" + " SIZE=4 FSTYPE=ext3"; + imp->allocate(0, templ, &oid); + + CPPUNIT_ASSERT(oid >= 0); + + img = imp->get(oid, false); + CPPUNIT_ASSERT( img != 0 ); + + img->set_state(Image::READY); + img->disk_attribute(disk, &index, &img_type); + + value = disk->vector_value("TARGET"); + CPPUNIT_ASSERT(value == "sdf"); + + // clean up + delete disk; + } + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ @@ -500,10 +604,11 @@ public: // Allocate 2 images, with different dev_prefix string template_0 = "NAME = \"Image 0\"\n" - "TARGET = \"hdx\"\n" + "DEV_PREFIX = \"hd\"\n" "PATH = /dev/null\n"; string template_1 = "NAME = \"Image 1\"\n" + "DEV_PREFIX = \"sd\"\n" "PATH = /dev/null\n"; @@ -527,25 +632,29 @@ public: disk = new VectorAttribute("DISK"); disk->replace("IMAGE_ID", "0"); - ((ImagePool*)imp)->disk_attribute(disk, 0, 0, img_id,error); + ((ImagePool*)imp)->disk_attribute(disk, 0, &index, &img_type,0, img_id,error); value = ""; value = disk->vector_value("TARGET"); - CPPUNIT_ASSERT( value == "hdx" ); + CPPUNIT_ASSERT( value == "hda" ); - value = ""; - value = disk->vector_value("IMAGE"); - CPPUNIT_ASSERT( value == "Image 0" ); delete disk; + // Disk using image 1 index disk = new VectorAttribute("DISK"); disk->replace("IMAGE_ID", "1"); - int rc = ((ImagePool*)imp)->disk_attribute(disk, 0, 0, img_id,error); + ((ImagePool*)imp)->disk_attribute(disk, 0, &index, &img_type,0, img_id,error); - CPPUNIT_ASSERT( rc == -1 ); + value = ""; + value = disk->vector_value("TARGET"); + CPPUNIT_ASSERT( value == "sda" ); + + value = ""; + value = disk->vector_value("IMAGE"); + CPPUNIT_ASSERT( value == "Image 1" ); delete disk; } diff --git a/src/lcm/LifeCycleActions.cc b/src/lcm/LifeCycleActions.cc index 6b316d5f14..234e686a58 100644 --- a/src/lcm/LifeCycleActions.cc +++ b/src/lcm/LifeCycleActions.cc @@ -111,6 +111,8 @@ void LifeCycleManager::suspend_action(int vid) vm->set_state(VirtualMachine::SAVE_SUSPEND); + vm->set_resched(false); + vmpool->update(vm); vm->log("LCM", Log::INFO, "New VM state is SAVE_SUSPEND"); @@ -154,7 +156,9 @@ void LifeCycleManager::stop_action(int vid) //---------------------------------------------------- vm->set_state(VirtualMachine::SAVE_STOP); - + + vm->set_resched(false); + vmpool->update(vm); vm->log("LCM", Log::INFO, "New VM state is SAVE_STOP"); @@ -200,6 +204,8 @@ void LifeCycleManager::migrate_action(int vid) vm->set_state(VirtualMachine::SAVE_MIGRATE); + vm->set_resched(false); + vmpool->update(vm); vm->set_stime(time(0)); @@ -254,6 +260,8 @@ void LifeCycleManager::live_migrate_action(int vid) vm->set_state(VirtualMachine::MIGRATE); + vm->set_resched(false); + vmpool->update(vm); vm->set_stime(time(0)); @@ -306,6 +314,8 @@ void LifeCycleManager::shutdown_action(int vid) vm->set_state(VirtualMachine::SHUTDOWN); + vm->set_resched(false); + vmpool->update(vm); vm->log("LCM",Log::INFO,"New VM state is SHUTDOWN"); @@ -410,6 +420,8 @@ void LifeCycleManager::cancel_action(int vid) vm->set_state(VirtualMachine::CANCEL); + vm->set_resched(false); + vmpool->update(vm); vm->log("LCM", Log::INFO, "New state is CANCEL"); @@ -448,6 +460,10 @@ void LifeCycleManager::reboot_action(int vid) VirtualMachineManager * vmm = nd.get_vmm(); vmm->trigger(VirtualMachineManager::REBOOT,vid); + + vm->set_resched(false); //Rebooting cancel re-scheduling actions + + vmpool->update(vm); } else { @@ -595,6 +611,7 @@ void LifeCycleManager::clean_up_vm(VirtualMachine * vm) int vid = vm->get_oid(); vm->set_state(VirtualMachine::CLEANUP); + vm->set_resched(false); vmpool->update(vm); vm->set_etime(the_time); diff --git a/src/lcm/LifeCycleStates.cc b/src/lcm/LifeCycleStates.cc index 391238680b..11cf2bd7be 100644 --- a/src/lcm/LifeCycleStates.cc +++ b/src/lcm/LifeCycleStates.cc @@ -719,6 +719,8 @@ void LifeCycleManager::monitor_suspend_action(int vid) vm->set_state(VirtualMachine::SAVE_SUSPEND); + vm->set_resched(false); + vmpool->update(vm); vm->set_running_etime(the_time); @@ -762,6 +764,8 @@ void LifeCycleManager::monitor_done_action(int vid) vm->set_state(VirtualMachine::UNKNOWN); + vm->set_resched(false); + vmpool->update(vm); vm->log("LCM", Log::INFO, "New VM state is UNKNOWN"); @@ -789,6 +793,8 @@ void LifeCycleManager::failure_action(VirtualMachine * vm) vm->set_state(VirtualMachine::FAILURE); + vm->set_resched(false); + vmpool->update(vm); vm->set_etime(the_time); diff --git a/src/mad/sh/scripts_common.sh b/src/mad/sh/scripts_common.sh index 9889741187..0f2b477e1c 100644 --- a/src/mad/sh/scripts_common.sh +++ b/src/mad/sh/scripts_common.sh @@ -176,6 +176,48 @@ function timeout_exec_and_log fi } +# Parameters are times (seconds) and monitoring command (or function). +# Executes monitoring command until it is successful (VM is no longer +# running) or the timeout is reached. +function retry +{ + times=$1 + function=$2 + + count=1 + + ret=$($function) + error=$? + + while [ $count -lt $times -a "$error" != "0" ]; do + sleep 1 + count=$(( $count + 1 )) + ret=$($function) + error=$? + done + + [ "x$error" = "x0" ] +} + +# Parameters are deploy_id and cancel command. If the last command is +# unsuccessful and $FORCE_DESTROY=yes then calls cancel command +function force_shutdown { + error=$? + deploy_id=$1 + command=$2 + + if [ "x$error" != "x0" ]; then + if [ "$FORCE_DESTROY" = "yes" ]; then + log_error "Timeout shutting down $deploy_id. Destroying it" + $($command) + sleep 2 + else + error_message "Timed out shutting down $deploy_id" + exit -1 + fi + fi +} + # This function will return a command that upon execution will format a # filesystem with its proper parameters based on the filesystem type function mkfs_command { diff --git a/src/nebula/Nebula.cc b/src/nebula/Nebula.cc index d2cef5f284..7ccb90c74b 100644 --- a/src/nebula/Nebula.cc +++ b/src/nebula/Nebula.cc @@ -299,9 +299,16 @@ void Nebula::start() upool = new UserPool(db, expiration_time); nebula_configuration->get("DEFAULT_IMAGE_TYPE", default_image_type); - - ipool = new ImagePool(db, default_image_type, img_restricted_attrs); + nebula_configuration->get("DEFAULT_DEVICE_PREFIX", + default_device_prefix); + + ipool = new ImagePool(db, + default_image_type, + default_device_prefix, + img_restricted_attrs); + tpool = new VMTemplatePool(db); + dspool = new DatastorePool(db); } catch (exception&) diff --git a/src/nebula/NebulaTemplate.cc b/src/nebula/NebulaTemplate.cc index 4e216a105d..db998d2a17 100644 --- a/src/nebula/NebulaTemplate.cc +++ b/src/nebula/NebulaTemplate.cc @@ -179,6 +179,7 @@ void OpenNebulaTemplate::set_conf_default() #******************************************************************************* # DATASTORE_LOCATION # DEFAULT_IMAGE_TYPE +# DEFAULT_DEVICE_PREFIX #******************************************************************************* */ //DATASTORE_LOCATION @@ -192,6 +193,11 @@ void OpenNebulaTemplate::set_conf_default() attribute = new SingleAttribute("DEFAULT_IMAGE_TYPE",value); conf_default.insert(make_pair(attribute->name(),attribute)); + //DEFAULT_DEVICE_PREFIX + value = "hd"; + + attribute = new SingleAttribute("DEFAULT_DEVICE_PREFIX",value); + conf_default.insert(make_pair(attribute->name(),attribute)); /* #******************************************************************************* # Auth Manager Configuration diff --git a/src/oca/java/src/org/opennebula/client/vm/VirtualMachine.java b/src/oca/java/src/org/opennebula/client/vm/VirtualMachine.java index 9cefefe188..ef10adbdb8 100644 --- a/src/oca/java/src/org/opennebula/client/vm/VirtualMachine.java +++ b/src/oca/java/src/org/opennebula/client/vm/VirtualMachine.java @@ -501,6 +501,24 @@ public class VirtualMachine extends PoolElement{ return action("resubmit"); } + /** + * Sets the re-scheduling flag for the VM + * @return If an error occurs the error message contains the reason. + */ + public OneResponse resched() + { + return action("resched"); + } + + /** + * Unsets the re-scheduling flag for the VM + * @return If an error occurs the error message contains the reason. + */ + public OneResponse unresched() + { + return action("unresched"); + } + /** * Migrates the virtual machine to the target host (hid). *
diff --git a/src/oca/ruby/OpenNebula/VirtualMachine.rb b/src/oca/ruby/OpenNebula/VirtualMachine.rb index a22726f330..d99f30712b 100644 --- a/src/oca/ruby/OpenNebula/VirtualMachine.rb +++ b/src/oca/ruby/OpenNebula/VirtualMachine.rb @@ -194,6 +194,16 @@ module OpenNebula action('resubmit') end + # Sets the re-scheduling flag for the VM + def resched + action('resched') + end + + # Unsets the re-scheduling flag for the VM + def unresched + action('unresched') + end + # Saves a running VM and starts it again in the specified host def migrate(host_id) return Error.new('ID not defined') if !@pe_id diff --git a/src/ozones/test/test.sh b/src/ozones/test/test.sh index d6de0d2f42..76dad892a2 100755 --- a/src/ozones/test/test.sh +++ b/src/ozones/test/test.sh @@ -38,9 +38,9 @@ for j in `ls ./spec/*_spec.rb` ; do ONE_LOCATION=$ONE_LOCATION_A rspec $j -f s CODE=$? - if [ $CODE != 0 ] ; then - break - fi +# if [ $CODE != 0 ] ; then +# break +# fi ONE_LOCATION=$ONE_LOCATION_A oneA/bin/one stop ONE_LOCATION=$ONE_LOCATION_B oneB/bin/one stop @@ -54,4 +54,4 @@ if (($CODE == 0)); then # Delete directories rm -rf oneA rm -rf oneB -fi \ No newline at end of file +fi diff --git a/src/rm/RequestManagerVirtualMachine.cc b/src/rm/RequestManagerVirtualMachine.cc index 1f3973c669..b252330b84 100644 --- a/src/rm/RequestManagerVirtualMachine.cc +++ b/src/rm/RequestManagerVirtualMachine.cc @@ -22,10 +22,11 @@ /* -------------------------------------------------------------------------- */ bool RequestManagerVirtualMachine::vm_authorization(int oid, - ImageTemplate * tmpl, - RequestAttributes& att, - PoolObjectAuth * host_perm, - PoolObjectAuth * ds_perm) + ImageTemplate * tmpl, + RequestAttributes& att, + PoolObjectAuth * host_perm, + PoolObjectAuth * ds_perm, + AuthRequest::Operation op) { PoolObjectSQL * object; PoolObjectAuth vm_perms; @@ -52,7 +53,7 @@ bool RequestManagerVirtualMachine::vm_authorization(int oid, AuthRequest ar(att.uid, att.gid); - ar.add_auth(auth_op, vm_perms); + ar.add_auth(op, vm_perms); if (host_perm != 0) { @@ -184,7 +185,14 @@ void VirtualMachineAction::request_execute(xmlrpc_c::paramList const& paramList, Nebula& nd = Nebula::instance(); DispatchManager * dm = nd.get_dm(); - if ( vm_authorization(id, 0, att, 0, 0) == false ) + AuthRequest::Operation op = auth_op; + + if (action == "resched" || action == "unresched") + { + op = AuthRequest::ADMIN; + } + + if ( vm_authorization(id, 0, att, 0, 0, op) == false ) { return; } @@ -233,6 +241,14 @@ void VirtualMachineAction::request_execute(xmlrpc_c::paramList const& paramList, { rc = dm->reboot(id); } + else if (action == "resched") + { + rc = dm->resched(id, true); + } + else if (action == "unresched") + { + rc = dm->resched(id, false); + } switch (rc) { @@ -289,7 +305,7 @@ void VirtualMachineDeploy::request_execute(xmlrpc_c::paramList const& paramList, return; } - auth = vm_authorization(id, 0, att, &host_perms, 0); + auth = vm_authorization(id, 0, att, &host_perms, 0, auth_op); if ( auth == false ) { @@ -351,7 +367,7 @@ void VirtualMachineMigrate::request_execute(xmlrpc_c::paramList const& paramList return; } - auth = vm_authorization(id, 0, att, &host_perms, 0); + auth = vm_authorization(id, 0, att, &host_perms, 0, auth_op); if ( auth == false ) { @@ -523,7 +539,7 @@ void VirtualMachineSaveDisk::request_execute(xmlrpc_c::paramList const& paramLis // Authorize the operation // ------------------------------------------------------------------------- - if ( vm_authorization(id, itemplate, att, 0, &ds_perms) == false ) + if ( vm_authorization(id, itemplate, att, 0, &ds_perms, auth_op) == false ) { delete itemplate; return; diff --git a/src/scheduler/etc/sched.conf b/src/scheduler/etc/sched.conf index b72f48dd37..73a4a91c6d 100644 --- a/src/scheduler/etc/sched.conf +++ b/src/scheduler/etc/sched.conf @@ -18,6 +18,8 @@ # MAX_HOST: Maximum number of Virtual Machines dispatched to a given host in # each scheduling action # +# LIVE_RESCHEDS: Perform live (1) or cold migrations (0) when rescheduling a VM +# # DEFAULT_SCHED: Definition of the default scheduling algorithm # - policy: # 0 = Packing. Heuristic that minimizes the number of hosts in use by @@ -41,6 +43,8 @@ MAX_DISPATCH = 30 MAX_HOST = 1 +LIVE_RESCHEDS = 0 + DEFAULT_SCHED = [ policy = 1 ] diff --git a/src/scheduler/include/VirtualMachinePoolXML.h b/src/scheduler/include/VirtualMachinePoolXML.h index 3fa2901812..b2b97e169b 100644 --- a/src/scheduler/include/VirtualMachinePoolXML.h +++ b/src/scheduler/include/VirtualMachinePoolXML.h @@ -27,10 +27,10 @@ class VirtualMachinePoolXML : public PoolXML { public: - VirtualMachinePoolXML( - Client* client, - unsigned int machines_limit - ):PoolXML(client, machines_limit){}; + VirtualMachinePoolXML(Client* client, + unsigned int machines_limit, + bool _live_resched): + PoolXML(client, machines_limit), live_resched(_live_resched){}; ~VirtualMachinePoolXML(){}; @@ -47,18 +47,28 @@ public: return static_cast(PoolXML::get(oid)); }; - int dispatch(int vid, int hid) const; + /** + * Dispatch a VM to the given host + * @param vid the VM id + * @param hid the id of the target host + * @param resched the machine is going to be rescheduled + */ + int dispatch(int vid, int hid, bool resched) const; protected: int get_suitable_nodes(vector& content) { - return get_nodes("/VM_POOL/VM", content); + return get_nodes("/VM_POOL/VM[STATE=1 or (LCM_STATE=3 and RESCHED=1)]", + content); }; virtual void add_object(xmlNodePtr node); virtual int load_info(xmlrpc_c::value &result); + + /* Do live migrations to resched VMs*/ + bool live_resched; }; #endif /* VM_POOL_XML_H_ */ diff --git a/src/scheduler/include/VirtualMachineXML.h b/src/scheduler/include/VirtualMachineXML.h index f677ae9671..befb264083 100644 --- a/src/scheduler/include/VirtualMachineXML.h +++ b/src/scheduler/include/VirtualMachineXML.h @@ -56,10 +56,19 @@ public: return gid; }; + int get_hid() const + { + return hid; + }; + + bool is_resched() const + { + return (resched == 1); + } + /** - * Adds a new share to the map of suitable shares to start this VM + * Adds a new host to the list of suitable hosts to start this VM * @param hid of the selected host - * @param hsid of the selected host share */ void add_host(int hid); @@ -151,6 +160,10 @@ protected: int uid; int gid; + int hid; + + int resched; + int memory; float cpu; diff --git a/src/scheduler/src/pool/HostPoolXML.cc b/src/scheduler/src/pool/HostPoolXML.cc index 5c6ab100eb..316cca5a2d 100644 --- a/src/scheduler/src/pool/HostPoolXML.cc +++ b/src/scheduler/src/pool/HostPoolXML.cc @@ -27,7 +27,7 @@ int HostPoolXML::set_up() if ( rc == 0 ) { oss.str(""); - oss << "Discovered Hosts (enabled):"; + oss << "Discovered Hosts (enabled):" << endl; map::iterator it; diff --git a/src/scheduler/src/pool/VirtualMachinePoolXML.cc b/src/scheduler/src/pool/VirtualMachinePoolXML.cc index 8dedf4fe8e..1b4852cb69 100644 --- a/src/scheduler/src/pool/VirtualMachinePoolXML.cc +++ b/src/scheduler/src/pool/VirtualMachinePoolXML.cc @@ -21,11 +21,13 @@ int VirtualMachinePoolXML::set_up() { ostringstream oss; int rc; + rc = PoolXML::set_up(); + if ( rc == 0 ) { oss.str(""); - oss << "Pending virtual machines :"; + oss << "Pending and rescheduling VMs:" << endl; map::iterator it; @@ -72,7 +74,7 @@ int VirtualMachinePoolXML::load_info(xmlrpc_c::value &result) -2, // VM from all users -1, // start_id (none) -1, // end_id (none) - 1); // in pending state + -1); // not in DONE state return 0; } catch (exception const& e) @@ -90,27 +92,48 @@ int VirtualMachinePoolXML::load_info(xmlrpc_c::value &result) /* -------------------------------------------------------------------------- */ -int VirtualMachinePoolXML::dispatch(int vid, int hid) const +int VirtualMachinePoolXML::dispatch(int vid, int hid, bool resched) const { ostringstream oss; xmlrpc_c::value deploy_result; - oss.str(""); - oss << "Dispatching virtual machine " << vid - << " to HID: " << hid; + if (resched == true) + { + oss << "Rescheduling "; + } + else + { + oss << "Dispatching "; + } + + oss << "virtual machine " << vid << " to host " << hid; NebulaLog::log("VM",Log::INFO,oss); try { - client->call( client->get_endpoint(), // serverUrl - "one.vm.deploy", // methodName - "sii", // arguments format - &deploy_result, // resultP - client->get_oneauth().c_str(), // argument 0 - vid, // argument 1 - hid // argument 2 - ); + //TODO Get live migration from config file + if (resched == true) + { + client->call(client->get_endpoint(), // serverUrl + "one.vm.migrate", // methodName + "siib", // arguments format + &deploy_result, // resultP + client->get_oneauth().c_str(), // argument 0 (AUTH) + vid, // argument 1 (VM) + hid, // argument 2 (HOST) + live_resched); // argument 3 (LIVE) + } + else + { + client->call(client->get_endpoint(), // serverUrl + "one.vm.deploy", // methodName + "sii", // arguments format + &deploy_result, // resultP + client->get_oneauth().c_str(), // argument 0 (AUTH) + vid, // argument 1 (VM) + hid); // argument 2 (HOST) + } } catch (exception const& e) { diff --git a/src/scheduler/src/pool/VirtualMachineXML.cc b/src/scheduler/src/pool/VirtualMachineXML.cc index f4c0137ba1..2fd1ca2702 100644 --- a/src/scheduler/src/pool/VirtualMachineXML.cc +++ b/src/scheduler/src/pool/VirtualMachineXML.cc @@ -66,7 +66,29 @@ void VirtualMachineXML::init_attributes() else { requirements = ""; + } + + result = ((*this)["/VM/HISTORY_RECORDS/HISTORY/HID"]); + + if (result.size() > 0) + { + hid = atoi(result[0].c_str()); } + else + { + hid = -1; + } + + result = ((*this)["/VM/RESCHED"]); + + if (result.size() > 0) + { + resched = atoi(result[0].c_str()); + } + else + { + resched = 0; + } } /* -------------------------------------------------------------------------- */ @@ -87,13 +109,16 @@ VirtualMachineXML::~VirtualMachineXML() /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -void VirtualMachineXML::add_host(int hid) +void VirtualMachineXML::add_host(int host_id) { - VirtualMachineXML::Host * ss; + if (( resched == 1 && host_id != hid ) || ( resched == 0 )) + { + VirtualMachineXML::Host * ss; - ss = new VirtualMachineXML::Host(hid); + ss = new VirtualMachineXML::Host(host_id); - hosts.push_back(ss); + hosts.push_back(ss); + } } /* -------------------------------------------------------------------------- */ diff --git a/src/scheduler/src/sched/Scheduler.cc b/src/scheduler/src/sched/Scheduler.cc index 03a5cea226..d40bb1740b 100644 --- a/src/scheduler/src/sched/Scheduler.cc +++ b/src/scheduler/src/sched/Scheduler.cc @@ -65,15 +65,17 @@ extern "C" void * scheduler_action_loop(void *arg) void Scheduler::start() { - int rc; + int rc; ifstream file; ostringstream oss; string etc_path; - int oned_port; - pthread_attr_t pattr; + int oned_port; + unsigned int live_rescheds; + + pthread_attr_t pattr; // ----------------------------------------------------------- // Log system & Configuration File @@ -136,6 +138,8 @@ void Scheduler::start() conf.get("MAX_DISPATCH", dispatch_limit); conf.get("MAX_HOST", host_dispatch_limit); + + conf.get("LIVE_RESCHEDS", live_rescheds); oss.str(""); @@ -169,8 +173,9 @@ void Scheduler::start() // ----------------------------------------------------------- hpool = new HostPoolXML(client); - vmpool = new VirtualMachinePoolXML(client, machines_limit); - + vmpool = new VirtualMachinePoolXML(client, + machines_limit, + (live_rescheds == 1)); acls = new AclXML(client); // ----------------------------------------------------------- @@ -329,7 +334,6 @@ void Scheduler::match() const map pending_vms = vmpool->get_objects(); const map hosts = hpool->get_objects(); - for (vm_it=pending_vms.begin(); vm_it != pending_vms.end(); vm_it++) { vm = static_cast(vm_it->second); @@ -516,15 +520,15 @@ void Scheduler::dispatch() map host_vms; - oss << "Select hosts" << endl; - oss << "\tPRI\tHID" << endl; - oss << "\t-------------------" << endl; + oss << "Selected hosts:" << endl; for (vm_it=pending_vms.begin(); vm_it != pending_vms.end(); vm_it++) { vm = static_cast(vm_it->second); - oss << "Virtual Machine: " << vm->get_oid() << "\n" << *vm << endl; + oss << "\t PRI\tHID VM: " << vm->get_oid() << endl + << "\t-----------------------" << endl + << *vm << endl; } NebulaLog::log("SCHED",Log::INFO,oss); @@ -541,9 +545,9 @@ void Scheduler::dispatch() if (rc == 0) { - rc = vmpool->dispatch(vm_it->first,hid); + rc = vmpool->dispatch(vm_it->first, hid, vm->is_resched()); - if (rc == 0) + if (rc == 0 && !vm->is_resched()) { dispatched_vms++; } diff --git a/src/scheduler/src/sched/SchedulerTemplate.cc b/src/scheduler/src/sched/SchedulerTemplate.cc index 6e2c72f83a..c6aa61fc7d 100644 --- a/src/scheduler/src/sched/SchedulerTemplate.cc +++ b/src/scheduler/src/sched/SchedulerTemplate.cc @@ -40,6 +40,7 @@ void SchedulerTemplate::set_conf_default() # MAX_DISPATCH # MAX_HOST # DEFAULT_SCHED +# LIVE_RESCHEDS #------------------------------------------------------------------------------- */ // ONED_PORT @@ -71,6 +72,12 @@ void SchedulerTemplate::set_conf_default() attribute = new SingleAttribute("MAX_HOST",value); conf_default.insert(make_pair(attribute->name(),attribute)); + + //LIVE_RESCHEDS + value = "0"; + + attribute = new SingleAttribute("LIVE_RESCHEDS",value); + conf_default.insert(make_pair(attribute->name(),attribute)); //DEFAULT_SCHED map vvalue; diff --git a/src/test/Nebula.cc b/src/test/Nebula.cc index bd9a202997..33dd57c40c 100644 --- a/src/test/Nebula.cc +++ b/src/test/Nebula.cc @@ -166,11 +166,12 @@ void Nebula::start() hook_location = nebula_location + "hooks/"; remotes_location = nebula_location + "var/remotes/"; - if ( nebula_configuration != 0) + /*if ( nebula_configuration != 0) { delete nebula_configuration; - } - + }*/ + nebula_configuration = new OpenNebulaTemplate(etc_location, var_location); + xmlInitParser(); // ----------------------------------------------------------- @@ -243,7 +244,9 @@ void Nebula::start() if (tester->need_image_pool) { - ipool = tester->create_ipool(db, default_image_type); + ipool = tester->create_ipool(db, + default_image_type, + default_device_prefix); } if (tester->need_template_pool) diff --git a/src/test/NebulaTest.cc b/src/test/NebulaTest.cc index 0c1c9f04ae..1527e57982 100644 --- a/src/test/NebulaTest.cc +++ b/src/test/NebulaTest.cc @@ -44,11 +44,12 @@ UserPool* NebulaTest::create_upool(SqlDB* db) } ImagePool* NebulaTest::create_ipool( SqlDB* db, - string default_image_type) + string default_image_type, + string default_device_prefix) { vector restricted_attrs; - return new ImagePool(db, default_image_type, restricted_attrs); + return new ImagePool(db, default_image_type, default_device_prefix, restricted_attrs); } VMTemplatePool* NebulaTest::create_tpool(SqlDB* db) diff --git a/src/tm_mad/common/context b/src/tm_mad/common/context index a37c4b7f07..d419cd60fa 100755 --- a/src/tm_mad/common/context +++ b/src/tm_mad/common/context @@ -23,14 +23,12 @@ # - vmid is the id of the VM # - 0 is the target datastore (system) -while (( "$#" )); do - if [ "$#" == "1" ]; then - DST=$1 - else - SRC="$SRC $1" - fi - shift -done +ARGV=("$@") + +DS_ID="${ARGV[$(($#-1))]}" +VM_ID="${ARGV[$(($#-2))]}" +DST="${ARGV[$(($#-3))]}" +SRC="${ARGV[@]:0:$(($#-3))}" if [ -z "${ONE_LOCATION}" ]; then TMCOMMON=/var/lib/one/remotes/tm/tm_common.sh diff --git a/src/tm_mad/lvm/clone b/src/tm_mad/lvm/clone new file mode 100755 index 0000000000..a4a7ab9e92 --- /dev/null +++ b/src/tm_mad/lvm/clone @@ -0,0 +1,89 @@ +#!/bin/bash + +# -------------------------------------------------------------------------- # +# Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) # +# # +# Licensed 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. # +#--------------------------------------------------------------------------- # + +# clone fe:SOURCE host:remote_system_ds/disk.i size +# - fe is the front-end hostname +# - SOURCE is the path of the disk image in the form DS_BASE_PATH/disk +# - host is the target host to deploy the VM +# - remote_system_ds is the path for the system datastore in the host + +SRC=$1 +DST=$2 +VM_ID=$3 +DS_ID=$4 + +if [ -z "${ONE_LOCATION}" ]; then + TMCOMMON=/var/lib/one/remotes/tm/tm_common.sh +else + TMCOMMON=$ONE_LOCATION/var/remotes/tm/tm_common.sh +fi + +DRIVER_PATH=$(dirname $0) + +source $TMCOMMON +source ${DRIVER_PATH}/../../datastore/lvm/lvm.conf + +#------------------------------------------------------------------------------- +# Set dst path and dir +#------------------------------------------------------------------------------- + +SRC_HOST=`arg_host $SRC` +SRC_PATH=`arg_path $SRC` + +DST_PATH=`arg_path $DST` +DST_HOST=`arg_host $DST` +DST_DIR=`dirname $DST_PATH` + +#------------------------------------------------------------------------------- +# Get SIZE through XPATH +#------------------------------------------------------------------------------- + +DISK_ID=$(echo $DST_PATH|awk -F. '{print $NF}') + +XPATH="${DRIVER_PATH}/../../datastore/xpath.rb --stdin" +XPATH="$XPATH /VM/TEMPLATE/DISK[DISK_ID='$DISK_ID']/SIZE" + +SIZE=$(onevm show -x $VM_ID | $XPATH ) +[ -z "$SIZE" ] && SIZE=$DEFAULT_SIZE + +#------------------------------------------------------------------------------- +# Get other LVM related fields +#------------------------------------------------------------------------------- + +LV_NAME=`echo $SRC_PATH|cut -d. -f2` +VG_NAME=`echo $SRC_PATH|cut -d. -f1` + +TARGET_DEV="/dev/$VG_NAME/$LV_NAME" +LV_SNAPSHOT="$LV_NAME-$VM_ID-$DISK_ID" +LV_SNAPSHOT_DEV="/dev/$VG_NAME/$LV_SNAPSHOT" + +#------------------------------------------------------------------------------- +# Create the snapshot and link it +#------------------------------------------------------------------------------- + +CLONE_CMD=$(cat < +# - host is the target host to deploy the VM +# - remote_system_ds is the path for the system datastore in the host + +DST=$1 +VM_ID=$2 +DS_ID=$3 + +if [ -z "${ONE_LOCATION}" ]; then + TMCOMMON=/var/lib/one/remotes/tm/tm_common.sh +else + TMCOMMON=$ONE_LOCATION/var/remotes/tm/tm_common.sh +fi + +. $TMCOMMON + +#------------------------------------------------------------------------------- +# Return if deleting a disk, we will delete them when removing the +# remote_system_ds directory for the VM (remotely) +#------------------------------------------------------------------------------- +DST_PATH=`arg_path $DST` +DST_HOST=`arg_host $DST` + +# Delete the device if it's a clone (LVM snapshot) +DELETE_CMD=$(cat < #include +#include #include "VirtualMachine.h" #include "VirtualNetworkPool.h" @@ -47,6 +48,7 @@ VirtualMachine::VirtualMachine(int id, last_poll(0), state(INIT), lcm_state(LCM_INIT), + resched(0), stime(time(0)), etime(0), deploy_id(""), @@ -371,15 +373,6 @@ int VirtualMachine::parse_context(string& error_str) context_parsed = new VectorAttribute("CONTEXT"); context_parsed->unmarshall(parsed," @^_^@ "); - - string target = context_parsed->vector_value("TARGET"); - - if ( target.empty() ) - { - error_str = "Missing TARGET attribute in CONTEXT."; - return -1; - } - obj_template->set(context_parsed); } @@ -847,21 +840,93 @@ void VirtualMachine::get_requirements (int& cpu, int& memory, int& disk) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +static void assign_disk_targets(queue >& _queue, + set& used_targets) +{ + int index = 0; + string target; + + pair disk_pair; + + while (_queue.size() > 0 ) + { + disk_pair = _queue.front(); + index = 0; + + do + { + target = disk_pair.first + static_cast(('a'+ index)); + index++; + } + while ( used_targets.count(target) > 0 && index < 26 ); + + disk_pair.second->replace("TARGET", target); + used_targets.insert(target); + + _queue.pop(); + } +} + +/* -------------------------------------------------------------------------- */ + int VirtualMachine::get_disk_images(string& error_str) { - int num_disks, rc; - vector disks; - ImagePool * ipool; - VectorAttribute * disk; - vector acquired_images; + int num_disks, rc; + vector disks; + ImagePool * ipool; + VectorAttribute * disk; + vector acquired_images; - int image_id; - ostringstream oss; + int image_id; + string dev_prefix; + string target; + + queue > os_disk; + queue > cdrom_disks; + queue > datablock_disks; + + set used_targets; + + ostringstream oss; + Image::ImageType img_type; Nebula& nd = Nebula::instance(); ipool = nd.get_ipool(); - num_disks = obj_template->get("DISK",disks); + // ------------------------------------------------------------------------- + // The context is the first of the cdroms + // ------------------------------------------------------------------------- + num_disks = obj_template->get("CONTEXT", disks); + + if ( num_disks > 0 ) + { + disk = dynamic_cast(disks[0]); + + if ( disk != 0 ) + { + target = disk->vector_value("TARGET"); + + if ( !target.empty() ) + { + used_targets.insert(target); + } + else + { + cdrom_disks.push(make_pair(ipool->default_dev_prefix(), disk)); + } + } + } + + // ------------------------------------------------------------------------- + // Set DISK attributes & Targets + // ------------------------------------------------------------------------- + disks.clear(); + num_disks = obj_template->get("DISK", disks); + + if ( num_disks > 20 ) + { + goto error_max_disks; + } for(int i=0; idisk_attribute(disk, i, uid, image_id, error_str); - + rc = ipool->disk_attribute(disk, + i, + img_type, + dev_prefix, + uid, + image_id, + error_str); if (rc == 0 ) { acquired_images.push_back(image_id); + + target = disk->vector_value("TARGET"); + + if ( !target.empty() ) + { + if ( used_targets.insert(target).second == false ) + { + goto error_duplicated_target; + } + } + else + { + switch(img_type) + { + case Image::OS: + // The first OS disk gets the first device (a), + // other OS's will be managed as DATABLOCK's + if ( os_disk.empty() ) + { + os_disk.push( make_pair(dev_prefix, disk) ); + } + else + { + datablock_disks.push( make_pair(dev_prefix, disk) ); + } + break; + + case Image::CDROM: + cdrom_disks.push( make_pair(dev_prefix, disk) ); + break; + + case Image::DATABLOCK: + datablock_disks.push( make_pair(dev_prefix, disk) ); + break; + + default: + break; + } + } } else { @@ -884,8 +993,20 @@ int VirtualMachine::get_disk_images(string& error_str) } } + assign_disk_targets(os_disk, used_targets); + assign_disk_targets(cdrom_disks, used_targets); + assign_disk_targets(datablock_disks, used_targets); + return 0; +error_max_disks: + error_str = "Exceeded the maximum number of disks (20)"; + return -1; + +error_duplicated_target: + oss << "Two disks have defined the same target " << target; + error_str = oss.str(); + error_common: ImageManager * imagem = nd.get_imagem(); @@ -1386,6 +1507,7 @@ string& VirtualMachine::to_xml_extended(string& xml, bool extended) const << "" << last_poll << "" << "" << state << "" << "" << lcm_state << "" + << "" << resched << "" << "" << stime << "" << "" << etime << "" << "" << deploy_id << "" @@ -1452,6 +1574,7 @@ int VirtualMachine::from_xml(const string &xml_str) rc += xpath(last_poll, "/VM/LAST_POLL", 0); rc += xpath(istate, "/VM/STATE", 0); rc += xpath(ilcmstate, "/VM/LCM_STATE", 0); + rc += xpath(resched, "/VM/RESCHED", 0); rc += xpath(stime, "/VM/STIME", 0); rc += xpath(etime, "/VM/ETIME", 0); diff --git a/src/vm/test/SConstruct b/src/vm/test/SConstruct index 98fd9ad244..06f2085cbb 100644 --- a/src/vm/test/SConstruct +++ b/src/vm/test/SConstruct @@ -17,6 +17,13 @@ Import('env') env.Prepend(LIBS=[ + 'nebula_core_test', + 'nebula_lcm', + 'nebula_tm', + 'nebula_vmm', + 'nebula_im', + 'nebula_rm', + 'nebula_dm', 'nebula_um', 'nebula_vm', 'nebula_hm', @@ -26,6 +33,8 @@ env.Prepend(LIBS=[ 'nebula_group', 'nebula_template', 'nebula_pool', + 'nebula_host', + 'nebula_vmtemplate', 'nebula_xml', 'nebula_image', 'nebula_datastore', @@ -39,4 +48,6 @@ env.Prepend(LIBS=[ 'crypto' ]) -env.Program('test','VirtualMachinePoolTest.cc') +nt = env.Object('NebulaTemplateTest.o', '../../nebula/NebulaTemplate.cc') + +env.Program('test',[nt,'VirtualMachinePoolTest.cc']) diff --git a/src/vm/test/VirtualMachinePoolTest.cc b/src/vm/test/VirtualMachinePoolTest.cc index 3a0ac90c90..8f5f7a9ac7 100644 --- a/src/vm/test/VirtualMachinePoolTest.cc +++ b/src/vm/test/VirtualMachinePoolTest.cc @@ -46,12 +46,12 @@ const string templates[] = const string xmls[] = { - "01231the_userusersVM one110000000010000000000000000", + "01231the_userusersVM one1100000000100000000000000000", - "12611the_userusersSecond VM110000000010000000000000000", + "12611the_userusersSecond VM1100000000100000000000000000", "01231the_userusersVM one01000000000000100000000000000000" @@ -60,16 +60,28 @@ const string xmls[] = // This xml dump result has the STIMEs modified to 0000000000 const string xml_dump = - "011the_userusersVM one110000000010000000000000000121the_userusersSecond VM110000000020000000000000000"; + "011the_userusersVM one1100000000100000000000000000121the_userusersSecond VM1100000000200000000000000000"; const string xml_dump_where = - "011the_userusersVM one110000000010000000000000000"; + "011the_userusersVM one1100000000100000000000000000"; const string xml_history_dump = - "001the_userusersVM one110000000010000000000000000101the_userusersSecond VM1100000000200000000000000000A_hostnameA_vm_dir000A_vmm_madA_vnm_mad0000000201the_userusersVM one1100000000200000000000000001C_hostnameC_vm_dir200C_vmm_madC_vnm_mad0000000311the_userusersVM one110000000060000000000000000"; + "001the_userusersVM one1100000000100000000000000000101the_userusersSecond VM11000000002000000000000000000A_hostname000A_vmm_madA_vnm_mad0000000201the_userusersVM one11000000002000000000000000001C_hostname200C_vmm_madC_vnm_mad0000000311the_userusersVM one1100000000600000000000000000"; /* ************************************************************************* */ /* ************************************************************************* */ +#include "NebulaTest.h" + +class NebulaTestVM: public NebulaTest +{ +public: + NebulaTestVM():NebulaTest() + { + NebulaTest::the_tester = this; + + need_vm_pool = true; + } +}; class VirtualMachinePoolFriend : public VirtualMachinePool { @@ -131,19 +143,18 @@ class VirtualMachinePoolTest : public PoolTest CPPUNIT_TEST_SUITE_END (); protected: + NebulaTestVM * tester; + VirtualMachinePool * vmpool; void bootstrap(SqlDB* db) { - VirtualMachinePool::bootstrap(db); + // setUp overwritten }; PoolSQL* create_pool(SqlDB* db) { - // The VM pool needs a vector containing the vm hooks - vector vm_hooks; - vector restricted_attrs; - - return new VirtualMachinePoolFriend(db, vm_hooks, restricted_attrs); + // setUp overwritten + return vmpool; }; int allocate(int index) @@ -181,6 +192,32 @@ public: ~VirtualMachinePoolTest(){xmlCleanupParser();}; + void setUp() + { + create_db(); + + tester = new NebulaTestVM(); + + Nebula& neb = Nebula::instance(); + neb.start(); + + vmpool = neb.get_vmpool(); + pool = vmpool; + }; + + void tearDown() + { + // ----------------------------------------------------------- + // Stop the managers & free resources + // ----------------------------------------------------------- + + //XML Library + xmlCleanupParser(); + + delete_db(); + + delete tester; + }; /* ********************************************************************* */ /* ********************************************************************* */ diff --git a/src/vmm/LibVirtDriverVMware.cc b/src/vmm/LibVirtDriverVMware.cc index 076c864ed8..5161011caf 100644 --- a/src/vmm/LibVirtDriverVMware.cc +++ b/src/vmm/LibVirtDriverVMware.cc @@ -1,3 +1,5 @@ + + /* -------------------------------------------------------------------------- */ /* Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) */ /* */ @@ -64,6 +66,13 @@ int LibVirtDriver::deployment_description_vmware( string script = ""; string model = ""; + const VectorAttribute * graphics; + + string listen = ""; + string port = ""; + string passwd = ""; + string keymap = ""; + const VectorAttribute * raw; string data; @@ -358,6 +367,58 @@ int LibVirtDriver::deployment_description_vmware( attrs.clear(); + // ------------------------------------------------------------------------ + // Graphics + // ------------------------------------------------------------------------ + + if ( vm->get_template_attribute("GRAPHICS",attrs) > 0 ) + { + graphics = dynamic_cast(attrs[0]); + + if ( graphics != 0 ) + { + type = graphics->vector_value("TYPE"); + listen = graphics->vector_value("LISTEN"); + port = graphics->vector_value("PORT"); + passwd = graphics->vector_value("PASSWD"); + keymap = graphics->vector_value("KEYMAP"); + + if ( type == "vnc" || type == "VNC" ) + { + file << "\t\t" << endl; + } + else + { + vm->log("VMM", Log::WARNING, + "Not supported graphics type, ignored."); + } + } + } + + attrs.clear(); + file << "\t" << endl; // ------------------------------------------------------------------------ diff --git a/src/vmm_mad/remotes/kvm/kvmrc b/src/vmm_mad/remotes/kvm/kvmrc index 3c4650a9cd..8f36a9b9a0 100644 --- a/src/vmm_mad/remotes/kvm/kvmrc +++ b/src/vmm_mad/remotes/kvm/kvmrc @@ -19,3 +19,10 @@ export LANG=C export LIBVIRT_URI=qemu:///system export QEMU_PROTOCOL=qemu+ssh + +# Seconds to wait after shutdown until timeout +export SHUTDOWN_TIMEOUT=300 + +# Uncomment this line to force VM cancellation after shutdown timeout +#export FORCE_DESTROY=yes + diff --git a/src/vmm_mad/remotes/kvm/shutdown b/src/vmm_mad/remotes/kvm/shutdown index 86f82002c9..2e6b1099c3 100755 --- a/src/vmm_mad/remotes/kvm/shutdown +++ b/src/vmm_mad/remotes/kvm/shutdown @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/bash # -------------------------------------------------------------------------- # # Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) # @@ -19,45 +19,42 @@ source $(dirname $0)/kvmrc source $(dirname $0)/../../scripts_common.sh -#------------------------------------------------------------------------------ -# Wait the VM to shutdown TIMEOUT (xPOLL_INTERVAL) seconds. -# Set to ~10min -#------------------------------------------------------------------------------ -POLL_INTERVAL=2 -TIMEOUT=300 -HALF_LOOP=$(($TIMEOUT/POLL_INTERVAL)) +count=0 deploy_id=$1 -virsh --connect $LIBVIRT_URI shutdown $deploy_id - -exit_code=$? - -if [ "$exit_code" != "0" ]; then - error_message "Could not shutdown $deploy_id" - exit $exit_code +if [ -z "$SHUTDOWN_TIMEOUT" ]; then + TIMEOUT=120 +else + TIMEOUT=$SHUTDOWN_TIMEOUT fi -count=0 -while [ $(virsh --connect $LIBVIRT_URI --readonly dominfo $deploy_id > /dev/null 2>&1; echo $?) = "0" ] -do - sleep $POLL_INTERVAL - if [ "$count" -gt "$TIMEOUT" ] - then - error_message "Timeout reached and VM $deploy_id is still alive" - echo "Timeout reached" >&2 - exit 1 - fi +HALF_LOOP=$(($TIMEOUT/2)) +function monitor +{ # Issue another shutdown to cover occasional libvirt lack of attention - if [ "$count" -eq "$HALF_LOOP" ] - then - virsh --connect $LIBVIRT_URI shutdown $deploy_id + if [ "$count" -eq "$HALF_LOOP" ] + then + virsh --connect $LIBVIRT_URI shutdown $deploy_id fi - let count=count+$POLL_INTERVAL -done + let count=count+1 + + export count + + virsh --connect $LIBVIRT_URI --readonly dominfo $deploy_id > /dev/null 2>&1 + + [ "x$?" != "x0" ] +} + +exec_and_log "virsh --connect $LIBVIRT_URI shutdown $deploy_id" \ + "Could not shutdown $deploy_id" + +retry $TIMEOUT monitor + +force_shutdown "$deploy_id" \ + "virsh --connect $LIBVIRT_URI destroy $deploy_id" sleep 4 -exit 0 diff --git a/src/vmm_mad/remotes/poll_xen_kvm.rb b/src/vmm_mad/remotes/poll_xen_kvm.rb index 1486d1dfb4..419dce0081 100755 --- a/src/vmm_mad/remotes/poll_xen_kvm.rb +++ b/src/vmm_mad/remotes/poll_xen_kvm.rb @@ -172,7 +172,7 @@ private when *%w{running blocked shutdown dying idle} 'a' when 'paused' - '-' + 'd' when 'crashed' 'e' else @@ -242,7 +242,7 @@ module XEN when *%w{r b s d} 'a' when 'p' - '-' + 'd' when 'c' 'e' else diff --git a/src/vmm_mad/remotes/xen/shutdown b/src/vmm_mad/remotes/xen/shutdown index d7ed0a16c6..69aff84621 100755 --- a/src/vmm_mad/remotes/xen/shutdown +++ b/src/vmm_mad/remotes/xen/shutdown @@ -21,24 +21,23 @@ source $(dirname $0)/../../scripts_common.sh deploy_id=$1 -function gdm { - $XM_LIST | grep "$deploy_id " +if [ -z "$SHUTDOWN_TIMEOUT" ]; then + TIMEOUT=120 +else + TIMEOUT=$SHUTDOWN_TIMEOUT +fi + +function monitor +{ + $XM_LIST "$deploy_id" > /dev/null + + [ "x$?" != "x0" ] } exec_and_log "$XM_SHUTDOWN $deploy_id" \ "Could not shutdown $deploy_id" -OUT=$(gdm) +retry $TIMEOUT monitor -while [ -n "$OUT" -a "$(echo $OUT | awk '{print $5}')" != "---s--" ]; do - sleep 1 - OUT=$(gdm) -done - -OUT=$(gdm) - -if [ -n "$OUT" ]; then - $XM_CANCEL "$deploy_id" -fi -sleep 2 +force_shutdown "$deploy_id" "$XM_CANCEL $deploy_id" diff --git a/src/vmm_mad/remotes/xen/xenrc b/src/vmm_mad/remotes/xen/xenrc index 694d9570c1..96a3dfb024 100644 --- a/src/vmm_mad/remotes/xen/xenrc +++ b/src/vmm_mad/remotes/xen/xenrc @@ -28,4 +28,10 @@ export XM_LIST="sudo $XM_PATH list" export XM_SHUTDOWN="sudo $XM_PATH shutdown" export XM_POLL="sudo /usr/sbin/xentop -bi2" +# Seconds to wait after shutdown until timeout +export SHUTDOWN_TIMEOUT=300 + +# Uncomment this line to force VM cancellation after shutdown timeout +#export FORCE_DESTROY=yes +