diff --git a/include/NebulaTemplate.h b/include/NebulaTemplate.h index c9bbc5e9f1..4254d8544c 100644 --- a/include/NebulaTemplate.h +++ b/include/NebulaTemplate.h @@ -102,6 +102,13 @@ public: Template::get(_name,value); }; + void get(const char *name, bool& value) const + { + string _name(name); + + Template::get(_name,value); + }; + // ----------------------------------------------------------------------- // ----------------------------------------------------------------------- diff --git a/include/PoolObjectSQL.h b/include/PoolObjectSQL.h index 220e66b51a..31428d4577 100644 --- a/include/PoolObjectSQL.h +++ b/include/PoolObjectSQL.h @@ -140,6 +140,11 @@ public: return name; }; + void set_name(const string& _name) + { + name = _name; + }; + int get_uid() const { return uid; diff --git a/include/Quota.h b/include/Quota.h index ac7a74b1cf..0a7122196f 100644 --- a/include/Quota.h +++ b/include/Quota.h @@ -182,6 +182,15 @@ protected: */ void cleanup_quota(const string& qid); + /** + * Creates a string from the given float, using fixed notation. If the + * number has any decimals, they will be truncated to 2. + * + * @param num + * @return + */ + string float_to_str(const float &num); + private: /** * Creates an empty quota based on the given attribute. The attribute va diff --git a/include/RequestManagerAllocate.h b/include/RequestManagerAllocate.h index 4957ded508..7e8f67f9ed 100644 --- a/include/RequestManagerAllocate.h +++ b/include/RequestManagerAllocate.h @@ -109,7 +109,7 @@ public: VirtualMachineAllocate(): RequestManagerAllocate("VirtualMachineAllocate", "Allocates a new virtual machine", - "A:ss", + "A:ssb", true) { Nebula& nd = Nebula::instance(); diff --git a/include/RequestManagerRename.h b/include/RequestManagerRename.h new file mode 100644 index 0000000000..5560cbd03c --- /dev/null +++ b/include/RequestManagerRename.h @@ -0,0 +1,166 @@ +/* -------------------------------------------------------------------------- */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +#ifndef REQUEST_MANAGER_RENAME_H_ +#define REQUEST_MANAGER_RENAME_H_ + +#include "Request.h" +#include "Nebula.h" + +using namespace std; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class RequestManagerRename : public Request +{ +protected: + RequestManagerRename(const string& method_name, + const string& help, + const string& params = "A:sis") + :Request(method_name,params,help) + { + auth_op = AuthRequest::MANAGE; + }; + + virtual ~RequestManagerRename(){}; + + /* -------------------------------------------------------------------- */ + + void request_execute(xmlrpc_c::paramList const& _paramList, + RequestAttributes& att); + + virtual PoolObjectSQL * get(const string& name, int uid, bool lock) = 0; +}; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class VirtualMachineRename : public RequestManagerRename +{ +public: + VirtualMachineRename(): + RequestManagerRename("VirtualMachineRename","Renames a virtual machine") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_vmpool(); + auth_object = PoolObjectSQL::VM; + }; + + ~VirtualMachineRename(){}; + + PoolObjectSQL * get(const string& name, int uid, bool lock) + { + return 0; + }; +}; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class TemplateRename : public RequestManagerRename +{ +public: + TemplateRename(): + RequestManagerRename("TemplateRename", + "Renames a virtual machine template") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_tpool(); + auth_object = PoolObjectSQL::TEMPLATE; + }; + + ~TemplateRename(){}; + + PoolObjectSQL * get(const string& name, int uid, bool lock) + { + return static_cast(pool)->get(name, uid, lock); + }; +}; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + + +class VirtualNetworkRename: public RequestManagerRename +{ +public: + VirtualNetworkRename(): + RequestManagerRename("VirtualNetworkRename","Renames a virtual network") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_vnpool(); + auth_object = PoolObjectSQL::NET; + }; + + ~VirtualNetworkRename(){}; + + PoolObjectSQL * get(const string& name, int uid, bool lock) + { + return static_cast(pool)->get(name, uid, lock); + }; +}; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class ImageRename: public RequestManagerRename +{ +public: + ImageRename(): + RequestManagerRename("ImageRename", "Renames an image") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_ipool(); + auth_object = PoolObjectSQL::IMAGE; + }; + + ~ImageRename(){}; + + PoolObjectSQL * get(const string& name, int uid, bool lock) + { + return static_cast(pool)->get(name, uid, lock); + }; +}; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class DocumentRename : public RequestManagerRename +{ +public: + DocumentRename(): + RequestManagerRename("DocumentRename", "Renames a generic document") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_docpool(); + auth_object = PoolObjectSQL::DOCUMENT; + }; + + ~DocumentRename(){}; + + PoolObjectSQL * get(const string& name, int uid, bool lock) + { + return 0; + }; +}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +#endif diff --git a/include/RequestManagerVMTemplate.h b/include/RequestManagerVMTemplate.h index 95c0a2f200..50d125f7e2 100644 --- a/include/RequestManagerVMTemplate.h +++ b/include/RequestManagerVMTemplate.h @@ -57,7 +57,7 @@ public: VMTemplateInstantiate(): RequestManagerVMTemplate("TemplateInstantiate", "Instantiates a new virtual machine using a template", - "A:sis") + "A:sisb") { auth_op = AuthRequest::USE; }; diff --git a/include/RequestManagerVirtualMachine.h b/include/RequestManagerVirtualMachine.h index 6530741303..ca61931a76 100644 --- a/include/RequestManagerVirtualMachine.h +++ b/include/RequestManagerVirtualMachine.h @@ -62,10 +62,16 @@ protected: string& vnm, string& tm, string& ds_location, - int& ds_id, + int& ds_id, RequestAttributes& att, PoolObjectAuth& host_perms); + bool check_host(int hid, + int cpu, + int mem, + int disk, + string& error); + int add_history(VirtualMachine * vm, int hid, const string& hostname, @@ -106,7 +112,7 @@ public: VirtualMachineDeploy(): RequestManagerVirtualMachine("VirtualMachineDeploy", "Deploys a virtual machine", - "A:sii") + "A:siib") { auth_op = AuthRequest::ADMIN; }; @@ -126,7 +132,7 @@ public: VirtualMachineMigrate(): RequestManagerVirtualMachine("VirtualMachineMigrate", "Migrates a virtual machine", - "A:siib") + "A:siibb") { auth_op = AuthRequest::ADMIN; }; diff --git a/include/Template.h b/include/Template.h index e71432a917..40c9aab2ae 100644 --- a/include/Template.h +++ b/include/Template.h @@ -265,6 +265,19 @@ public: const string& name, float& value) const; + /** + * Gets the value of a Single attributes (bool) with the given name. + * @param name the attribute name. + * @param value the attribute value, a bool, false if the attribute is not + * defined or not Single + * + * @return True if the Single attribute was found and is a valid bool + * value + */ + virtual bool get( + const string& name, + bool& value) const; + friend ostream& operator<<(ostream& os, const Template& t); /** diff --git a/include/VirtualMachinePool.h b/include/VirtualMachinePool.h index e3b75236b8..ea808432d5 100644 --- a/include/VirtualMachinePool.h +++ b/include/VirtualMachinePool.h @@ -37,7 +37,8 @@ public: const string& hook_location, const string& remotes_location, vector& restricted_attrs, - time_t expire_time); + time_t expire_time, + bool on_hold); ~VirtualMachinePool(){}; @@ -255,6 +256,11 @@ private: * Size, in seconds, of the historical monitoring information */ static time_t _monitor_expiration; + + /** + * True or false whether to submit new VM on HOLD or not + */ + static bool _submit_on_hold; }; #endif /*VIRTUAL_MACHINE_POOL_H_*/ diff --git a/install.sh b/install.sh index e316e55b94..ceb1cf4817 100755 --- a/install.sh +++ b/install.sh @@ -183,7 +183,8 @@ else CHOWN_DIRS="$ROOT" fi -SHARE_DIRS="$SHARE_LOCATION/examples" +SHARE_DIRS="$SHARE_LOCATION/examples \ + $SHARE_LOCATION/tgt" ETC_DIRS="$ETC_LOCATION/im_ec2 \ $ETC_LOCATION/vmm_ec2 \ @@ -451,6 +452,7 @@ INSTALL_FILES=( NETWORK_OVSWITCH_FILES:$VAR_LOCATION/remotes/vnm/ovswitch NETWORK_VMWARE_FILES:$VAR_LOCATION/remotes/vnm/vmware EXAMPLE_SHARE_FILES:$SHARE_LOCATION/examples + TGT_SHARE_FILES:$SHARE_LOCATION/tgt INSTALL_NOVNC_SHARE_FILE:$SHARE_LOCATION INSTALL_GEMS_SHARE_FILE:$SHARE_LOCATION HOOK_FT_FILES:$VAR_LOCATION/remotes/hooks/ft @@ -1065,6 +1067,12 @@ EXAMPLE_SHARE_FILES="share/examples/vm.template \ share/examples/private.net \ share/examples/public.net" +#------------------------------------------------------------------------------- +# File required to interact with a tgtd server +#------------------------------------------------------------------------------- + +TGT_SHARE_FILES="share/scripts/tgt/tgt-setup-lun-one" + #------------------------------------------------------------------------------- # HOOK scripts, to be installed under $VAR_LOCATION/remotes/hooks #------------------------------------------------------------------------------- diff --git a/share/etc/oned.conf b/share/etc/oned.conf index 8660300863..de90413f55 100644 --- a/share/etc/oned.conf +++ b/share/etc/oned.conf @@ -38,6 +38,9 @@ # VMID # # DEBUG_LEVEL: 0 = ERROR, 1 = WARNING, 2 = INFO, 3 = DEBUG +# +# VM_SUBMIT_ON_HOLD: Forces VMs to be created on hold state instead of pending. +# Values: YES or NO. #******************************************************************************* #MANAGER_TIMER = 30 @@ -68,6 +71,8 @@ VNC_BASE_PORT = 5900 DEBUG_LEVEL = 3 +#VM_SUBMIT_ON_HOLD = "NO" + #******************************************************************************* # Physical Networks configuration #******************************************************************************* diff --git a/share/scripts/tgt/tgt-setup-lun-one b/share/scripts/tgt/tgt-setup-lun-one new file mode 100755 index 0000000000..faf08949b5 --- /dev/null +++ b/share/scripts/tgt/tgt-setup-lun-one @@ -0,0 +1,279 @@ +#!/bin/bash + +# LUN assignment script +# +# Copyright (C) 2007 Erez Zilber +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation, version 2 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + +usage() +{ + name=$(basename $0); + echo "usage:"; + echo -e "\t$name -n tgt_name -d dev -b bs_name -t transport [initiator_IP1 initiator_IP2 ...]"; + echo "defaults:"; + echo -e "\tbacking store: rdwr"; + echo -e "\ttransport: iscsi"; + echo -e "\tinitiator: ALL"; + echo "examples:"; + echo -e "\t$name -n tgt-1 -d /dev/sdb1 192.168.1.2"; + echo -e "\t$name -n tgt-2 -d /tmp/null -b null -t iser"; + echo -e "\t$name -n tgt-3 -d ~/disk3.bin -b rdwr 192.168.1.2 192.168.1.3"; +} + +verify_params() +{ + if ! [ "$dev" -o "$bs_type" == "null" ]; then + echo "Error: a device is mandatory"; + exit 1; + else + return; + fi + + # Make sure that the device exists + if ! [ -b $dev -o -f $dev -o -c $dev ]; then + echo "Error: $dev is not a device"; + exit 1; + fi + + if ! [ "$tgt_name" ]; then + echo "Error: target name is mandatory"; + exit 1; + fi + + if ! [ "$lld_name" ]; then + echo "Error: lld name empty"; + exit 1; + fi +} + +find_vacant_tgt_id() +{ + tmp_file=`mktemp` + tgtadm --lld $lld_name --op show --mode target | strings > $tmp_file + id_list=$(cat $tmp_file | grep Target | cut -d" " -f2 | sed s/://) + next_vacant_id=1 + for id in $id_list; do + if (($id > $next_vacant_id)); then + break; + else + next_vacant_id=$((next_vacant_id+1)) + fi + done + rm -f $tmp_file + echo $next_vacant_id +} + +find_vacant_lun() +{ + tid=$1 + tgt_found=0 + next_vacant_lun=0 + tmp_file=`mktemp` + + tgtadm --lld $lld_name --op show --mode target | strings | tgt-admin -s | grep 'LUN\|Target' > $tmp_file + retcode=$? + while read line; do + # Check if we finished going over this target + if ((tgt_found == 1 && $(echo $line | grep -c "^Target") == 1)); then + break + fi + + # Check if we found the requested target + if (($(echo $line | grep -c "Target $tid:") == 1)); then + tgt_found=1 + continue + fi + + if ((tgt_found == 1 && $(echo $line | grep -c "LUN:") == 1)); then + curr_lun=$(echo $line | cut -d" " -f2) + if (($curr_lun > $next_vacant_lun)); then + break + else + next_vacant_lun=$((next_vacant_lun+1)) + fi + fi + done < $tmp_file + + rm -f $tmp_file + + if ((tgt_found == 0)); then + echo "Error: could not find a LUN for target $tid, guessing 1 as next vacant LUN" + return 1 + fi + if ((next_vacant_lun == 0)); then + echo "Error: could not find a LUN for target $tid, guessing 1 as next vacant LUN" + return 1 + fi + + return $next_vacant_lun +} + +err_exit() +{ + if ((new_tgt == 0)); then + exit 1 + fi + + echo "Deleting new target, tid=$tid" + tgtadm --lld $lld_name --op delete --mode target --tid $tid + res=$? + + if [ $res -ne 0 ]; then + echo "Error: failed to delete target, tid=$tid" + fi + + exit 1 +} + +check_if_tgt_exists() +{ + tgt_list=$(tgtadm --lld $lld_name --op show --mode target | strings | grep Target | cut -d" " -f3) + + for curr_tgt in $tgt_list; do + if [ $tgt_name = $curr_tgt ]; then + return 1 + fi + done + + return 0 +} + +if [ $# -eq 0 ]; then + usage + exit 1 +fi + +lld_name="iscsi" + +while getopts "d:n:b:t:h:" opt +do + case ${opt} in + d) + dev=$OPTARG;; + n) + tgt_name=$OPTARG;; + b) + bs_type=$OPTARG;; + t) + lld_name=$OPTARG;; + h*) + usage + exit 1 + esac +done + +shift $(($OPTIND - 1)) + +initiators=$* + +verify_params + +# Check if tgtd is running (we should have 2 daemons) +tgtd_count=`pidof tgtd | wc -w` +if [ $tgtd_count -lt 1 ]; then + echo "tgtd is not running" + echo "Exiting..." + exit 1 +fi + +echo "Using transport: $lld_name" + +if ! [[ $tgt_name =~ ^iqn ]]; then + tgt_name="iqn.2001-04.com.$(hostname -s)-$tgt_name" +fi + +# Make sure that a target with the same name doesn't exist +check_if_tgt_exists +if [ $? -eq 1 ]; then + echo "Error: target named $tgt_name already exists" + read -p "Add a new lun to the existing target? (yes/NO): " add_lun + if [ $add_lun != "yes" ]; then + exit 1 + fi + tid=$(tgtadm --lld $lld_name --op show --mode target | strings | grep $tgt_name | cut -d" " -f2) + tid=${tid%:} + new_tgt=0 +else + + i=0 + while [ true ] + do + let i=i+1 + tid=`find_vacant_tgt_id` + #tid=$? + # Create the new target + echo -n "Creating new target (name=$tgt_name, tid=$tid)..." + tgtoutput=`tgtadm --lld $lld_name --op new --mode target --tid $tid -T $tgt_name 2>&1` + res=$? + if [ "$tgtoutput" == "tgtadm: this target already exists" ]; then + echo "Target already exists (this should not happen)... Attempt $i" + elif [ $res -eq 0 ]; then # output is not about duplication and return value is zero, this is the normal condition + break + fi + if [ $i -eq 100 ]; then + echo "Too many attempts, giving up" + break + fi + done + if [ $res -ne 0 ]; then + echo "Error: failed to create target (name=$tgt_name, tid=$tid)" + exit 1 + fi + new_tgt=1 +fi +echo "OK" +find_vacant_lun $tid +lun=$? +echo "LUN ok, $lun" + +# Add a logical unit to the target +echo "Adding a logical unit ($dev) to target, tid=$tid" +if [ $bs_type ]; then + echo "Setting backing store type: $bs_type" + bs_opt="-E $bs_type" +fi +tgtadm --lld $lld_name --op new --mode logicalunit --tid $tid --lun $lun -b $dev $bs_opt +res=$? + +if [ $res -ne 0 ]; then + echo "Error: failed to add a logical unit ($dev) to target, tid=$tid" + err_exit +fi + +# Define which initiators can use this target +if test "$initiators" ; then + # Allow access only for specific initiators + echo "Accepting connections only from $initiators" + for initiator in $initiators; do + tgtadm --lld $lld_name --op bind --mode target --tid $tid -I $initiator + res=$? + + if [ $res -ne 0 ]; then + echo "Error: could not assign initiator $initiator to the target" + fi + done +else + # Allow access for everyone + echo "Accepting connections from all initiators" + tgtadm --lld $lld_name --op bind --mode target --tid $tid -I ALL + res=$? + + if [ $res -ne 0 ]; then + echo "Error: failed to set access for all initiators" + err_exit + fi +fi diff --git a/src/authm_mad/remotes/ldap/ldap_auth.conf b/src/authm_mad/remotes/ldap/ldap_auth.conf index af016f554e..3b97f1e92e 100644 --- a/src/authm_mad/remotes/ldap/ldap_auth.conf +++ b/src/authm_mad/remotes/ldap/ldap_auth.conf @@ -28,6 +28,9 @@ server 1: :host: localhost :port: 389 + # Uncomment this line for tsl conections + #:encryption: :simple_tls + # base hierarchy where to search for users and groups :base: 'dc=domain' diff --git a/src/authm_mad/remotes/ldap/ldap_auth.rb b/src/authm_mad/remotes/ldap/ldap_auth.rb index 4090628fed..7f3293c269 100644 --- a/src/authm_mad/remotes/ldap/ldap_auth.rb +++ b/src/authm_mad/remotes/ldap/ldap_auth.rb @@ -41,6 +41,7 @@ class LdapAuth ops[:host]=@options[:host] if @options[:host] ops[:port]=@options[:port].to_i if @options[:port] + ops[:encryption]=@options[:encryption] if @options[:encryption] @ldap=Net::LDAP.new(ops) end diff --git a/src/cli/command_parser.rb b/src/cli/command_parser.rb index 41bcce9b78..9094183cd4 100644 --- a/src/cli/command_parser.rb +++ b/src/cli/command_parser.rb @@ -498,15 +498,9 @@ module CommandParser else puts "one parameter to run" end - puts - puts "Usage:" - if @main - print " #{@usage}\n" - else - print " #{name} " - print_command(@commands[name]) - end + print_command_help(name) + exit -1 else id=0 diff --git a/src/cli/one_helper/onevm_helper.rb b/src/cli/one_helper/onevm_helper.rb index e6bafadab4..e540239f9f 100644 --- a/src/cli/one_helper/onevm_helper.rb +++ b/src/cli/one_helper/onevm_helper.rb @@ -51,6 +51,12 @@ class OneVMHelper < OpenNebulaHelper::OneHelper } } + HOLD = { + :name => "hold", + :large => "--hold", + :description => "Creates the new VM on hold state instead of pending" + } + def self.rname "VM" end diff --git a/src/cli/oneimage b/src/cli/oneimage index e57b1dd413..4a78d3b33e 100755 --- a/src/cli/oneimage +++ b/src/cli/oneimage @@ -304,6 +304,16 @@ cmd=CommandParser::CmdParser.new(ARGV) do end end + rename_desc = <<-EOT.unindent + Renames the Image + EOT + + command :rename, rename_desc, :imageid, :name do + helper.perform_action(args[0],options,"renamed") do |o| + o.rename(args[1]) + end + end + list_desc = <<-EOT.unindent Lists Images in the pool EOT diff --git a/src/cli/onetemplate b/src/cli/onetemplate index 396add5082..b1cc925e06 100755 --- a/src/cli/onetemplate +++ b/src/cli/onetemplate @@ -29,6 +29,7 @@ $: << RUBY_LIB_LOCATION+"/cli" require 'command_parser' require 'one_helper/onetemplate_helper' +require 'one_helper/onevm_helper' cmd=CommandParser::CmdParser.new(ARGV) do usage "`onetemplate` [] []" @@ -52,7 +53,8 @@ cmd=CommandParser::CmdParser.new(ARGV) do instantiate_options = [ OneTemplateHelper::VM_NAME, - OneTemplateHelper::MULTIPLE + OneTemplateHelper::MULTIPLE, + OneVMHelper::HOLD ] ######################################################################## @@ -179,7 +181,10 @@ cmd=CommandParser::CmdParser.new(ARGV) do exit_code=helper.perform_action(args[0],options,"instantiated") do |t| name = options[:name] name = name.gsub("%i",i.to_s) if name - res = t.instantiate(name) + + on_hold = options[:hold] != nil + + res = t.instantiate(name, on_hold) if !OpenNebula.is_error?(res) puts "VM ID: #{res}" @@ -265,6 +270,16 @@ cmd=CommandParser::CmdParser.new(ARGV) do Lists Templates in the pool EOT + rename_desc = <<-EOT.unindent + Renames the Template + EOT + + command :rename, rename_desc, :templateid, :name do + helper.perform_action(args[0],options,"renamed") do |o| + o.rename(args[1]) + end + end + command :list, list_desc, [:filterflag, nil], :options=>list_options do helper.list_pool(options, false, args[0]) end diff --git a/src/cli/onevm b/src/cli/onevm index 0e1f3c15de..04fd4a414f 100755 --- a/src/cli/onevm +++ b/src/cli/onevm @@ -56,6 +56,13 @@ cmd=CommandParser::CmdParser.new(ARGV) do :description => "Device where the image will be attached" } + ENFORCE={ + :name => "enforce", + :short => "-e", + :large => "--enforce", + :description => "Enforce that the host capacity is not exceeded" + } + ######################################################################## # Global Options ######################################################################## @@ -118,7 +125,8 @@ cmd=CommandParser::CmdParser.new(ARGV) do EOT command :create, create_desc, [:file, nil], :options => - [OneVMHelper::MULTIPLE]+OpenNebulaHelper::TEMPLATE_OPTIONS_VM do + [OneVMHelper::MULTIPLE, OneVMHelper::HOLD]+ + OpenNebulaHelper::TEMPLATE_OPTIONS_VM do number = options[:multiple] || 1 exit_code = nil @@ -153,9 +161,11 @@ cmd=CommandParser::CmdParser.new(ARGV) do exit 0 end + on_hold = options[:hold] != nil + number.times do exit_code = helper.create_resource(options) do |vm| - error = vm.allocate(template) + error = vm.allocate(template, on_hold) end break if exit_code == -1 @@ -287,12 +297,16 @@ cmd=CommandParser::CmdParser.new(ARGV) do States: PENDING EOT - command :deploy, deploy_desc, [:range,:vmid_list], :hostid do + command :deploy, deploy_desc, [:range,:vmid_list], :hostid, :options=>[ENFORCE] do host_id = args[1] verbose = "deploying in host #{host_id}" helper.perform_actions(args[0],options,verbose) do |vm| - vm.deploy(host_id) + if !options[:enforce].nil? + vm.deploy(host_id, options[:enforce]) + else + vm.deploy(host_id) + end end end @@ -302,12 +316,16 @@ cmd=CommandParser::CmdParser.new(ARGV) do States: RUNNING EOT - command :livemigrate, livemigrate_desc, [:range,:vmid_list], :hostid do + command :livemigrate, livemigrate_desc, [:range,:vmid_list], :hostid, :options=>[ENFORCE] do host_id = args[1] verbose = "live migrating to #{host_id}" helper.perform_actions(args[0],options,verbose) do |vm| - vm.live_migrate(host_id) + if !options[:enforce].nil? + vm.live_migrate(host_id, options[:enforce]) + else + vm.live_migrate(host_id) + end end end @@ -317,12 +335,16 @@ cmd=CommandParser::CmdParser.new(ARGV) do States: RUNNING EOT - command :migrate, migrate_desc, [:range,:vmid_list], :hostid do + command :migrate, migrate_desc, [:range,:vmid_list], :hostid, :options=>[ENFORCE] do host_id = args[1] verbose = "migrating to #{host_id}" helper.perform_actions(args[0],options,verbose) do |vm| - vm.migrate(host_id) + if !options[:enforce].nil? + vm.migrate(host_id, options[:enforce]) + else + vm.migrate(host_id) + end end end @@ -515,6 +537,16 @@ cmd=CommandParser::CmdParser.new(ARGV) do Lists VMs in the pool EOT + rename_desc = <<-EOT.unindent + Renames the VM + EOT + + command :rename, rename_desc, :vmid, :name do + helper.perform_action(args[0],options,"renamed") do |o| + o.rename(args[1]) + end + end + command :list, list_desc, [:filterflag, nil], :options=>CLIHelper::OPTIONS+OpenNebulaHelper::OPTIONS+ [OpenNebulaHelper::DESCRIBE] do diff --git a/src/cli/onevnet b/src/cli/onevnet index 12638fc2a8..d931f3ce0b 100755 --- a/src/cli/onevnet +++ b/src/cli/onevnet @@ -228,4 +228,14 @@ cmd=CommandParser::CmdParser.new(ARGV) do vnet.update(str) end end + + rename_desc = <<-EOT.unindent + Renames the Virtual Network + EOT + + command :rename, rename_desc, :vnetid, :name do + helper.perform_action(args[0],options,"renamed") do |o| + o.rename(args[1]) + end + end end diff --git a/src/datastore_mad/remotes/iscsi/clone b/src/datastore_mad/remotes/iscsi/clone index f60dd02fa8..e0055a085b 100755 --- a/src/datastore_mad/remotes/iscsi/clone +++ b/src/datastore_mad/remotes/iscsi/clone @@ -64,6 +64,9 @@ BASE_IQN="${XPATH_ELEMENTS[6]:-$BASE_IQN}" SRC="${XPATH_ELEMENTS[7]}" SIZE="${XPATH_ELEMENTS[8]}" +# Check if 'TGTSETUPLUN' is installed +tgt_setup_lun_install "$DST_HOST" "$BASE_PATH" + set_up_datastore "$BASE_PATH" "$RESTRICTED_DIRS" "$SAFE_DIRS" "$UMASK" LV_NAME="lv-one-${ID}" @@ -76,13 +79,9 @@ DEV_SRC="/dev/$VG_NAME/$LV_SRC" CLONE_CMD=$(cat <&1 | \ + $GREP -q "command not found" + if [ "$?" = "0" ]; then + error_message "$TGTSETUPLUN is not installed in $DST_HOST." + exit 127 + else + touch "$CHECK_FILE" + fi + fi +} + +function tgt_setup_lun { + IQN="$1" + DEV="$2" + echo "$TGTSETUPLUN -d $DEV -n $IQN 1>&2" +} + function iqn_get_host { IQN="$1" TARGET=`echo "$IQN"|$CUT -d: -f2` @@ -426,10 +451,10 @@ function vmfs_set_up { if [ "$USE_SSH" != "yes" ]; then USERNAME=`echo $(cat $VMWARERC |grep ":username:"|cut -d":" -f 3|tr -d '"')` PASSWORD=`echo $(cat $VMWARERC |grep ":password:"|cut -d":" -f 3|tr -d '"')` - if [ -z $PASSWORD ]; then - VI_PARAMS="--server $DST_HOST --username $USERNAME --password \"\"" - else - VI_PARAMS="--server $DST_HOST --username $USERNAME --password $PASSWORD" + if [ -z $PASSWORD ]; then + VI_PARAMS="--server $DST_HOST --username $USERNAME --password \"\"" + else + VI_PARAMS="--server $DST_HOST --username $USERNAME --password $PASSWORD" fi fi } diff --git a/src/nebula/Nebula.cc b/src/nebula/Nebula.cc index de2e0645cd..29654dc696 100644 --- a/src/nebula/Nebula.cc +++ b/src/nebula/Nebula.cc @@ -517,6 +517,8 @@ void Nebula::start() time_t vm_expiration; time_t host_expiration; + bool vm_submit_on_hold; + vector vm_hooks; vector host_hooks; vector vnet_hooks; @@ -543,12 +545,15 @@ void Nebula::start() nebula_configuration->get("VM_MONITORING_EXPIRATION_TIME",vm_expiration); nebula_configuration->get("HOST_MONITORING_EXPIRATION_TIME",host_expiration); + nebula_configuration->get("VM_SUBMIT_ON_HOLD",vm_submit_on_hold); + vmpool = new VirtualMachinePool(db, vm_hooks, hook_location, remotes_location, vm_restricted_attrs, - vm_expiration); + vm_expiration, + vm_submit_on_hold); hpool = new HostPool(db, host_hooks, hook_location, diff --git a/src/nebula/NebulaTemplate.cc b/src/nebula/NebulaTemplate.cc index 7a86acdda2..578d359167 100644 --- a/src/nebula/NebulaTemplate.cc +++ b/src/nebula/NebulaTemplate.cc @@ -98,6 +98,7 @@ void OpenNebulaTemplate::set_conf_default() # DB # VNC_BASE_PORT # SCRIPTS_REMOTE_DIR +# VM_SUBMIT_ON_HOLD #******************************************************************************* */ // MONITOR_INTERVAL @@ -167,6 +168,12 @@ void OpenNebulaTemplate::set_conf_default() attribute = new SingleAttribute("SCRIPTS_REMOTE_DIR",value); conf_default.insert(make_pair(attribute->name(),attribute)); + // VM_SUBMIT_ON_HOLD + value = "NO"; + + attribute = new SingleAttribute("VM_SUBMIT_ON_HOLD",value); + conf_default.insert(make_pair(attribute->name(),attribute)); + /* #******************************************************************************* # Physical Networks configuration diff --git a/src/oca/java/src/org/opennebula/client/Client.java b/src/oca/java/src/org/opennebula/client/Client.java index 2fff759a34..7d4c87ad83 100644 --- a/src/oca/java/src/org/opennebula/client/Client.java +++ b/src/oca/java/src/org/opennebula/client/Client.java @@ -129,16 +129,6 @@ public class Client{ return call("system.version"); } - /** - * Calls OpenNebula and retrieves oned configuration - * - * @return The server's xml-rpc response encapsulated - */ - public OneResponse get_config() - { - return call("system.config"); - } - //-------------------------------------------------------------------------- // PRIVATE ATTRIBUTES AND METHODS //-------------------------------------------------------------------------- diff --git a/src/oca/java/src/org/opennebula/client/OneSystem.java b/src/oca/java/src/org/opennebula/client/OneSystem.java index d40aa83bae..88c61edf19 100644 --- a/src/oca/java/src/org/opennebula/client/OneSystem.java +++ b/src/oca/java/src/org/opennebula/client/OneSystem.java @@ -32,12 +32,84 @@ public class OneSystem private static final String GROUP_QUOTA_INFO = "groupquota.info"; private static final String GROUP_QUOTA_UPDATE = "groupquota.update"; + public static final String VERSION = "3.9.0"; public OneSystem(Client client) { this.client = client; } + /** + * Calls OpenNebula and retrieves the oned version + * + * @return The server's xml-rpc response encapsulated + */ + public OneResponse getOnedVersion() + { + return client.call("system.version"); + } + + /** + * Returns whether of not the oned version is the same as the OCA version + * + * @return true if oned is the same version + */ + public boolean compatibleVersion() + { + OneResponse r = getOnedVersion(); + + if (r.isError()) + { + return false; + } + + String[] ocaVersion = VERSION.split("\\.", 3); + String[] onedVersion = r.getMessage().split("\\.", 3); + + return ocaVersion.length == onedVersion.length && + ocaVersion[0].equals(onedVersion[0]) && + ocaVersion[1].equals(onedVersion[1]); + } + + /** + * Calls OpenNebula and retrieves oned configuration + * + * @return The server's xml-rpc response encapsulated + */ + public OneResponse getConfiguration() + { + return client.call("system.config"); + } + + /** + * Calls OpenNebula and retrieves oned configuration + * + * @return The xml root node in case of success, null otherwise + */ + public Node getConfigurationXML() + { + OneResponse r = getConfiguration(); + Node xml = null; + + if (r.isError()) + { + return null; + } + + try + { + DocumentBuilder builder = + DocumentBuilderFactory.newInstance().newDocumentBuilder(); + Document doc = builder.parse( + new ByteArrayInputStream(r.getMessage().getBytes())); + + xml = doc.getDocumentElement(); + } + catch (Exception e) {} + + return xml; + } + /** * Gets the default user quota limits * diff --git a/src/oca/java/src/org/opennebula/client/document/Document.java b/src/oca/java/src/org/opennebula/client/document/Document.java index 281e9617b6..7f287a73f1 100644 --- a/src/oca/java/src/org/opennebula/client/document/Document.java +++ b/src/oca/java/src/org/opennebula/client/document/Document.java @@ -65,6 +65,7 @@ public abstract class Document extends PoolElement private static final String CHOWN = METHOD_PREFIX + "chown"; private static final String CHMOD = METHOD_PREFIX + "chmod"; private static final String CLONE = METHOD_PREFIX + "clone"; + private static final String RENAME = METHOD_PREFIX + "rename"; /** * Creates a new Document representation. @@ -215,6 +216,17 @@ public abstract class Document extends PoolElement return client.call(CLONE, id, name); } + /** + * Renames this document + * + * @param name New name for the document. + * @return If an error occurs the error message contains the reason. + */ + public OneResponse rename(String name) + { + return client.call(RENAME, id, name); + } + // ================================= // Helpers // ================================= diff --git a/src/oca/java/src/org/opennebula/client/image/Image.java b/src/oca/java/src/org/opennebula/client/image/Image.java index 62d8185790..700371bd2a 100644 --- a/src/oca/java/src/org/opennebula/client/image/Image.java +++ b/src/oca/java/src/org/opennebula/client/image/Image.java @@ -38,6 +38,7 @@ public class Image extends PoolElement private static final String CHMOD = METHOD_PREFIX + "chmod"; private static final String CHTYPE = METHOD_PREFIX + "chtype"; private static final String CLONE = METHOD_PREFIX + "clone"; + private static final String RENAME = METHOD_PREFIX + "rename"; private static final String[] IMAGE_STATES = {"INIT", "READY", "USED", "DISABLED", "LOCKED", @@ -265,6 +266,19 @@ public class Image extends PoolElement return client.call(CLONE, id, name); } + /** + * Renames this Image + * + * @param client XML-RPC Client. + * @param id The Image id of the target Image. + * @param name New name for the Image. + * @return If an error occurs the error message contains the reason. + */ + public static OneResponse rename(Client client, int id, String name) + { + return client.call(RENAME, id, name); + } + // ================================= // Instanced object XML-RPC methods // ================================= @@ -498,6 +512,17 @@ public class Image extends PoolElement return clone(client, id, name); } + /** + * Renames this Image + * + * @param name New name for the Image. + * @return If an error occurs the error message contains the reason. + */ + public OneResponse rename(String name) + { + return rename(client, id, name); + } + // ================================= // Helpers // ================================= diff --git a/src/oca/java/src/org/opennebula/client/template/Template.java b/src/oca/java/src/org/opennebula/client/template/Template.java index dd48c96254..c8064436cc 100644 --- a/src/oca/java/src/org/opennebula/client/template/Template.java +++ b/src/oca/java/src/org/opennebula/client/template/Template.java @@ -36,6 +36,7 @@ public class Template extends PoolElement private static final String CHMOD = METHOD_PREFIX + "chmod"; private static final String INSTANTIATE = METHOD_PREFIX + "instantiate"; private static final String CLONE = METHOD_PREFIX + "clone"; + private static final String RENAME = METHOD_PREFIX + "rename"; /** * Creates a new Template representation. @@ -199,11 +200,13 @@ public class Template extends PoolElement * @param client XML-RPC Client. * @param id The template id of the target template. * @param name A string containing the name of the VM instance, can be empty. + * @param onHold False to create this VM in pending state, true on hold * @return If successful the message contains the VM Instance ID. */ - public static OneResponse instantiate(Client client, int id, String name) + public static OneResponse instantiate(Client client, int id, String name, + boolean onHold) { - return client.call(INSTANTIATE, id, name); + return client.call(INSTANTIATE, id, name, onHold); } /** @@ -219,6 +222,19 @@ public class Template extends PoolElement return client.call(CLONE, id, name); } + /** + * Renames this Template + * + * @param client XML-RPC Client. + * @param id The Template id of the target Template. + * @param name New name for the Template. + * @return If an error occurs the error message contains the reason. + */ + public static OneResponse rename(Client client, int id, String name) + { + return client.call(RENAME, id, name); + } + // ================================= // Instanced object XML-RPC methods // ================================= @@ -368,6 +384,18 @@ public class Template extends PoolElement return chmod(client, id, octet); } + /** + * Creates a VM instance from a Template + * + * @param name A string containing the name of the VM instance, can be empty. + * @param onHold False to create this VM in pending state, true on hold + * @return If successful the message contains the VM Instance ID. + */ + public OneResponse instantiate(String name, boolean onHold) + { + return instantiate(client, id, name, onHold); + } + /** * Creates a VM instance from a Template * @@ -376,7 +404,7 @@ public class Template extends PoolElement */ public OneResponse instantiate(String name) { - return instantiate(client, id, name); + return instantiate(client, id, name, false); } /** @@ -386,7 +414,7 @@ public class Template extends PoolElement */ public OneResponse instantiate() { - return instantiate(client, id, ""); + return instantiate(client, id, "", false); } /** @@ -400,6 +428,17 @@ public class Template extends PoolElement return clone(client, id, name); } + /** + * Renames this Template + * + * @param name New name for the Template. + * @return If an error occurs the error message contains the reason. + */ + public OneResponse rename(String name) + { + return rename(client, id, name); + } + // ================================= // Helpers // ================================= 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 d402c835d2..51f3779513 100644 --- a/src/oca/java/src/org/opennebula/client/vm/VirtualMachine.java +++ b/src/oca/java/src/org/opennebula/client/vm/VirtualMachine.java @@ -39,6 +39,7 @@ public class VirtualMachine extends PoolElement{ private static final String MONITORING = METHOD_PREFIX + "monitoring"; private static final String ATTACH = METHOD_PREFIX + "attach"; private static final String DETACH = METHOD_PREFIX + "detach"; + private static final String RENAME = METHOD_PREFIX + "rename"; private static final String[] VM_STATES = { @@ -149,7 +150,22 @@ public class VirtualMachine extends PoolElement{ */ public static OneResponse allocate(Client client, String description) { - return client.call(ALLOCATE, description); + return allocate(client, description, false); + } + + /** + * Allocates a new VM in OpenNebula. + * + * @param client XML-RPC Client. + * @param description A string containing the template of the vm. + * @param onHold False to create this VM in pending state, true on hold + * @return If successful the message contains the associated + * id generated for this VM. + */ + public static OneResponse allocate(Client client, String description, + boolean onHold) + { + return client.call(ALLOCATE, description, onHold); } /** @@ -273,6 +289,19 @@ public class VirtualMachine extends PoolElement{ return client.call(DETACH, id, diskId); } + /** + * Renames this VM + * + * @param client XML-RPC Client. + * @param id The VM id of the target VM. + * @param name New name for the VM. + * @return If an error occurs the error message contains the reason. + */ + public static OneResponse rename(Client client, int id, String name) + { + return client.call(RENAME, id, name); + } + // ================================= // Instanced object XML-RPC methods // ================================= @@ -290,6 +319,21 @@ public class VirtualMachine extends PoolElement{ return response; } + /** + * Initiates the instance of the VM on the target host. + * + * @param hostId The host id (hid) of the target host where + * the VM will be instantiated. + * @param enforce If it is set to true, the host capacity + * will be checked, and the deployment will fail if the host is + * overcommited. Defaults to false + * @return If an error occurs the error message contains the reason. + */ + public OneResponse deploy(int hostId, boolean enforce) + { + return client.call(DEPLOY, id, hostId, enforce); + } + /** * Initiates the instance of the VM on the target host. * @@ -299,7 +343,7 @@ public class VirtualMachine extends PoolElement{ */ public OneResponse deploy(int hostId) { - return client.call(DEPLOY, id, hostId); + return deploy(hostId, false); } /** @@ -337,11 +381,14 @@ public class VirtualMachine extends PoolElement{ * the vm. * @param live If true we are indicating that we want livemigration, * otherwise false. + * @param enforce If it is set to true, the host capacity + * will be checked, and the deployment will fail if the host is + * overcommited. Defaults to false * @return If an error occurs the error message contains the reason. */ - public OneResponse migrate(int hostId, boolean live) + public OneResponse migrate(int hostId, boolean live, boolean enforce) { - return client.call(MIGRATE, id, hostId, live); + return client.call(MIGRATE, id, hostId, live, enforce); } /** @@ -486,6 +533,17 @@ public class VirtualMachine extends PoolElement{ return detachdisk(client, id, diskId); } + /** + * Renames this VM + * + * @param name New name for the VM. + * @return If an error occurs the error message contains the reason. + */ + public OneResponse rename(String name) + { + return rename(client, id, name); + } + // ================================= // Helpers // ================================= @@ -628,6 +686,24 @@ public class VirtualMachine extends PoolElement{ return action("unresched"); } + /** + * Migrates the virtual machine to the target host (hid). + *
+ * It does the same as {@link VirtualMachine#migrate(int, boolean)} + * with live set to false. + * + * @param hostId The target host id (hid) where we want to migrate + * the vm. + * @param enforce If it is set to true, the host capacity + * will be checked, and the deployment will fail if the host is + * overcommited. Defaults to false + * @return If an error occurs the error message contains the reason. + */ + public OneResponse migrate(int hostId, boolean enforce) + { + return migrate(hostId, false, enforce); + } + /** * Migrates the virtual machine to the target host (hid). *
@@ -643,6 +719,25 @@ public class VirtualMachine extends PoolElement{ return migrate(hostId, false); } + /** + * Performs a live migration of the virtual machine to the + * target host (hid). + *
+ * It does the same as {@link VirtualMachine#migrate(int, boolean)} + * with live set to true. + * + * @param hostId The target host id (hid) where we want to migrate + * the vm. + * @param enforce If it is set to true, the host capacity + * will be checked, and the deployment will fail if the host is + * overcommited. Defaults to false + * @return If an error occurs the error message contains the reason. + */ + public OneResponse liveMigrate(int hostId, boolean enforce) + { + return migrate(hostId, true, enforce); + } + /** * Performs a live migration of the virtual machine to the * target host (hid). @@ -656,7 +751,7 @@ public class VirtualMachine extends PoolElement{ */ public OneResponse liveMigrate(int hostId) { - return migrate(hostId, true); + return liveMigrate(hostId, false); } public int state() diff --git a/src/oca/java/src/org/opennebula/client/vnet/VirtualNetwork.java b/src/oca/java/src/org/opennebula/client/vnet/VirtualNetwork.java index 112d4adec5..fd65e5584c 100644 --- a/src/oca/java/src/org/opennebula/client/vnet/VirtualNetwork.java +++ b/src/oca/java/src/org/opennebula/client/vnet/VirtualNetwork.java @@ -38,6 +38,7 @@ public class VirtualNetwork extends PoolElement{ private static final String UPDATE = METHOD_PREFIX + "update"; private static final String HOLD = METHOD_PREFIX + "hold"; private static final String RELEASE = METHOD_PREFIX + "release"; + private static final String RENAME = METHOD_PREFIX + "rename"; /** * Creates a new virtual network representation. @@ -263,7 +264,7 @@ public class VirtualNetwork extends PoolElement{ * Replaces the VirtualNetwork template contents. * * @param client XML-RPC Client. - * @param id The user id of the target vnet we want to modify. + * @param id The vnet id of the target vnet we want to modify. * @param new_template New template contents. * @return If successful the message contains the vnet id. */ @@ -272,6 +273,19 @@ public class VirtualNetwork extends PoolElement{ return client.call(UPDATE, id, new_template); } + /** + * Renames this VirtualNetwork + * + * @param client XML-RPC Client. + * @param id The VirtualNetwork id of the target VirtualNetwork. + * @param name New name for the VirtualNetwork. + * @return If an error occurs the error message contains the reason. + */ + public static OneResponse rename(Client client, int id, String name) + { + return client.call(RENAME, id, name); + } + // ================================= // Instanced object XML-RPC methods // ================================= @@ -491,6 +505,17 @@ public class VirtualNetwork extends PoolElement{ return update(client, id, new_template); } + /** + * Renames this VirtualNetwork + * + * @param name New name for the VirtualNetwork. + * @return If an error occurs the error message contains the reason. + */ + public OneResponse rename(String name) + { + return rename(client, id, name); + } + // ================================= // Helpers // ================================= diff --git a/src/oca/java/test/SessionTest.java b/src/oca/java/test/SessionTest.java index 2bb971162b..d6b94c6e2b 100644 --- a/src/oca/java/test/SessionTest.java +++ b/src/oca/java/test/SessionTest.java @@ -1,12 +1,12 @@ /******************************************************************************* * 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. @@ -17,6 +17,7 @@ import static org.junit.Assert.*; import org.junit.Test; import org.opennebula.client.*; +import org.w3c.dom.Node; public class SessionTest { @@ -51,7 +52,7 @@ public class SessionTest { } assertNull("Client should complain about misspelled url", oneClient); - } + } @Test public void version() @@ -63,11 +64,24 @@ public class SessionTest { } catch (Exception e) { - System.out.println(e.getMessage()); + assertTrue( e.getMessage(), false ); } - OneResponse res = oneClient.get_version(); + OneSystem system = new OneSystem(oneClient); + OneResponse res = system.getOnedVersion(); assertTrue( res.getErrorMessage(), !res.isError() ); + + res = system.getConfiguration(); + assertTrue( res.getErrorMessage(), !res.isError() ); + + Node config = system.getConfigurationXML(); + assertTrue( "XML configuration is null", config != null ); + + boolean compatible = system.compatibleVersion(); + assertTrue( + "Incompatible version reported, " + + OneSystem.VERSION + ", " + system.getOnedVersion().getMessage(), + compatible ); } } diff --git a/src/oca/ruby/OpenNebula.rb b/src/oca/ruby/OpenNebula.rb index a2e7f4f8ca..9e60d0be8f 100644 --- a/src/oca/ruby/OpenNebula.rb +++ b/src/oca/ruby/OpenNebula.rb @@ -172,9 +172,5 @@ module OpenNebula def get_version() call("system.version") end - - def get_config() - call("system.config") - end end end diff --git a/src/oca/ruby/OpenNebula/Document.rb b/src/oca/ruby/OpenNebula/Document.rb index 494ebcf3dd..bcb186c8e5 100644 --- a/src/oca/ruby/OpenNebula/Document.rb +++ b/src/oca/ruby/OpenNebula/Document.rb @@ -44,6 +44,7 @@ module OpenNebula :chown => "document.chown", :chmod => "document.chmod", :clone => "document.clone", + :rename => "document.rename" } # Creates a Document Object description with just its identifier @@ -185,6 +186,16 @@ module OpenNebula return rc end + # Renames this Document + # + # @param name [String] New name for the Document. + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def rename(name) + return call(DOCUMENT_METHODS[:rename], @pe_id, name) + end + ####################################################################### # Helpers to get Document information ####################################################################### diff --git a/src/oca/ruby/OpenNebula/Image.rb b/src/oca/ruby/OpenNebula/Image.rb index e8224871f8..53a2f8aea7 100644 --- a/src/oca/ruby/OpenNebula/Image.rb +++ b/src/oca/ruby/OpenNebula/Image.rb @@ -35,7 +35,8 @@ module OpenNebula :chown => "image.chown", :chmod => "image.chmod", :chtype => "image.chtype", - :clone => "image.clone" + :clone => "image.clone", + :rename => "image.rename" } IMAGE_STATES=%w{INIT READY USED DISABLED LOCKED ERROR CLONE DELETE USED_PERS} @@ -205,6 +206,16 @@ module OpenNebula return rc end + # Renames this Image + # + # @param name [String] New name for the Image. + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def rename(name) + return call(IMAGE_METHODS[:rename], @pe_id, name) + end + ####################################################################### # Helpers to get Image information ####################################################################### diff --git a/src/oca/ruby/OpenNebula/System.rb b/src/oca/ruby/OpenNebula/System.rb index d7e0b1aa78..9092e0be85 100644 --- a/src/oca/ruby/OpenNebula/System.rb +++ b/src/oca/ruby/OpenNebula/System.rb @@ -27,7 +27,9 @@ module OpenNebula :userquotainfo => "userquota.info", :userquotaupdate => "userquota.update", :groupquotainfo => "groupquota.info", - :groupquotaupdate => "groupquota.update" + :groupquotaupdate => "groupquota.update", + :version => "system.version", + :config => "system.config" } ####################################################################### @@ -44,6 +46,46 @@ module OpenNebula # XML-RPC Methods ####################################################################### + # Gets the oned version + # + # @return [String, OpenNebula::Error] the oned version in case + # of success, Error otherwise + def get_oned_version() + return @client.call("system.version") + end + + # Returns whether of not the oned version is the same as the OCA version + # + # @return [true, false, OpenNebula::Error] true if oned is the same + # version + def compatible_version() + no_revision = VERSION[/^\d+\.\d+\./] + oned_v = get_oned_version + + if OpenNebula.is_error?(oned_v) + return oned_v + end + + return (oned_v =~ /#{no_revision}/) != nil + end + + # Gets the oned configuration + # + # @return [XMLElement, OpenNebula::Error] the oned configuration in case + # of success, Error otherwise + def get_configuration() + rc = @client.call(SYSTEM_METHODS[:config]) + + if OpenNebula.is_error?(rc) + return rc + end + + config = XMLElement.new + config.initialize_xml(rc, 'TEMPLATE') + + return config + end + # Gets the default user quota limits # # @return [XMLElement, OpenNebula::Error] the default user quota in case diff --git a/src/oca/ruby/OpenNebula/Template.rb b/src/oca/ruby/OpenNebula/Template.rb index aa209d3f3d..cbafdfe2d4 100644 --- a/src/oca/ruby/OpenNebula/Template.rb +++ b/src/oca/ruby/OpenNebula/Template.rb @@ -32,7 +32,8 @@ module OpenNebula :delete => "template.delete", :chown => "template.chown", :chmod => "template.chmod", - :clone => "template.clone" + :clone => "template.clone", + :rename => "template.rename" } # Creates a Template description with just its identifier @@ -85,13 +86,18 @@ module OpenNebula # Creates a VM instance from a Template # - # +name+ A string containing the name of the VM instance. - # [return] The new VM Instance ID, or an Error object - def instantiate(name="") + # @param name [String] Name for the VM instance. If it is an empty + # string OpenNebula will set a default name + # @param hold [true,false] false to create the VM in pending state, + # true to create it on hold + # + # @return [Integer, OpenNebula::Error] The new VM id, Error + # otherwise + def instantiate(name="", hold=false) return Error.new('ID not defined') if !@pe_id name ||= "" - rc = @client.call(TEMPLATE_METHODS[:instantiate], @pe_id, name) + rc = @client.call(TEMPLATE_METHODS[:instantiate], @pe_id, name, hold) return rc end @@ -157,6 +163,16 @@ module OpenNebula return rc end + # Renames this Template + # + # @param name [String] New name for the Template. + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def rename(name) + return call(TEMPLATE_METHODS[:rename], @pe_id, name) + end + ####################################################################### # Helpers to get Template information ####################################################################### diff --git a/src/oca/ruby/OpenNebula/VirtualMachine.rb b/src/oca/ruby/OpenNebula/VirtualMachine.rb index 5e7c061c8b..4ac7b6d745 100644 --- a/src/oca/ruby/OpenNebula/VirtualMachine.rb +++ b/src/oca/ruby/OpenNebula/VirtualMachine.rb @@ -35,7 +35,8 @@ module OpenNebula :chmod => "vm.chmod", :monitoring => "vm.monitoring", :attach => "vm.attach", - :detach => "vm.detach" + :detach => "vm.detach", + :rename => "vm.rename" } VM_STATE=%w{INIT PENDING HOLD ACTIVE STOPPED SUSPENDED DONE FAILED @@ -133,22 +134,29 @@ module OpenNebula # Allocates a new VirtualMachine in OpenNebula # - # +description+ A string containing the template of the VirtualMachine. - def allocate(description) - super(VM_METHODS[:allocate],description) + # @param description [String] A string containing the template of + # the VirtualMachine. + # @param hold [true,false] false to create the VM in pending state, + # true to create it on hold + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def allocate(description, hold=false) + super(VM_METHODS[:allocate], description, hold) end # Initiates the instance of the VM on the target host. # - # +host_id+ The host id (hid) of the target host where - # the VM will be instantiated. - def deploy(host_id) - return Error.new('ID not defined') if !@pe_id - - rc = @client.call(VM_METHODS[:deploy], @pe_id, host_id.to_i) - rc = nil if !OpenNebula.is_error?(rc) - - return rc + # @param host_id [Interger] The host id (hid) of the target host where + # the VM will be instantiated. + # @param enforce [true|false] If it is set to true, the host capacity + # will be checked, and the deployment will fail if the host is + # overcommited. Defaults to false + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def deploy(host_id, enforce=false) + return call(VM_METHODS[:deploy], @pe_id, host_id.to_i, enforce) end # Shutdowns an already deployed VM @@ -247,23 +255,31 @@ module OpenNebula 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 - - rc = @client.call(VM_METHODS[:migrate], @pe_id, host_id.to_i, false) - rc = nil if !OpenNebula.is_error?(rc) - - return rc + # + # @param host_id [Interger] The host id (hid) of the target host where + # the VM will be migrated. + # @param enforce [true|false] If it is set to true, the host capacity + # will be checked, and the deployment will fail if the host is + # overcommited. Defaults to false + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def migrate(host_id, enforce=false) + return call(VM_METHODS[:migrate], @pe_id, host_id.to_i, false, enforce) end # Migrates a running VM to another host without downtime - def live_migrate(host_id) - return Error.new('ID not defined') if !@pe_id - - rc = @client.call(VM_METHODS[:migrate], @pe_id, host_id.to_i, true) - rc = nil if !OpenNebula.is_error?(rc) - - return rc + # + # @param host_id [Interger] The host id (hid) of the target host where + # the VM will be migrated. + # @param enforce [true|false] If it is set to true, the host capacity + # will be checked, and the deployment will fail if the host is + # overcommited. Defaults to false + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def live_migrate(host_id, enforce=false) + return call(VM_METHODS[:migrate], @pe_id, host_id.to_i, true, enforce) end # Set the specified vm's disk to be saved in a new image @@ -352,6 +368,16 @@ module OpenNebula return @client.call(VM_METHODS[:monitoring], @pe_id) end + # Renames this VM + # + # @param name [String] New name for the VM. + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def rename(name) + return call(VM_METHODS[:rename], @pe_id, name) + end + ####################################################################### # Helpers to get VirtualMachine information ####################################################################### diff --git a/src/oca/ruby/OpenNebula/VirtualNetwork.rb b/src/oca/ruby/OpenNebula/VirtualNetwork.rb index bb5c0933b3..b6964b4d0e 100644 --- a/src/oca/ruby/OpenNebula/VirtualNetwork.rb +++ b/src/oca/ruby/OpenNebula/VirtualNetwork.rb @@ -34,7 +34,8 @@ module OpenNebula :chmod => "vn.chmod", :update => "vn.update", :hold => "vn.hold", - :release => "vn.release" + :release => "vn.release", + :rename => "vn.rename" } VN_TYPES=%w{RANGED FIXED} @@ -191,6 +192,16 @@ module OpenNebula super(VN_METHODS[:chmod], owner_u, owner_m, owner_a, group_u, group_m, group_a, other_u, other_m, other_a) end + + # Renames this virtual network + # + # @param name [String] New name for the virtual network. + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def rename(name) + return call(VN_METHODS[:rename], @pe_id, name) + end ####################################################################### # Helpers to get VirtualNetwork information diff --git a/src/pool/PoolSQL.cc b/src/pool/PoolSQL.cc index 2acc5a662d..6a31a2992d 100644 --- a/src/pool/PoolSQL.cc +++ b/src/pool/PoolSQL.cc @@ -364,6 +364,7 @@ void PoolSQL::update_cache_index(string& old_name, int new_uid) { map::iterator index; + PoolObjectSQL * the_object; lock(); @@ -380,11 +381,13 @@ void PoolSQL::update_cache_index(string& old_name, if ( index != name_pool.end() ) { + the_object = index->second; + name_pool.erase(old_key); if ( name_pool.find(new_key) == name_pool.end()) { - name_pool.insert(make_pair(new_key, index->second)); + name_pool.insert(make_pair(new_key, the_object)); } } diff --git a/src/rm/RequestManager.cc b/src/rm/RequestManager.cc index 1ba7f4b8bf..004c3e2d82 100644 --- a/src/rm/RequestManager.cc +++ b/src/rm/RequestManager.cc @@ -26,6 +26,7 @@ #include "RequestManagerChown.h" #include "RequestManagerChmod.h" #include "RequestManagerClone.h" +#include "RequestManagerRename.h" #include "RequestManagerVirtualNetwork.h" #include "RequestManagerVirtualMachine.h" @@ -374,6 +375,13 @@ void RequestManager::register_xml_methods() xmlrpc_c::methodPtr group_get_default_quota(new GroupQuotaInfo()); xmlrpc_c::methodPtr group_set_default_quota(new GroupQuotaUpdate()); + // Rename Methods + xmlrpc_c::methodPtr vm_rename(new VirtualMachineRename()); + xmlrpc_c::methodPtr template_rename(new TemplateRename()); + xmlrpc_c::methodPtr vn_rename(new VirtualNetworkRename()); + xmlrpc_c::methodPtr image_rename(new ImageRename()); + xmlrpc_c::methodPtr doc_rename(new DocumentRename()); + /* VM related methods */ RequestManagerRegistry.addMethod("one.vm.deploy", vm_deploy); RequestManagerRegistry.addMethod("one.vm.action", vm_action); @@ -386,6 +394,7 @@ void RequestManager::register_xml_methods() RequestManagerRegistry.addMethod("one.vm.monitoring", vm_monitoring); RequestManagerRegistry.addMethod("one.vm.attach", vm_attach); RequestManagerRegistry.addMethod("one.vm.detach", vm_detach); + RequestManagerRegistry.addMethod("one.vm.rename", vm_rename); RequestManagerRegistry.addMethod("one.vmpool.info", vm_pool_info); RequestManagerRegistry.addMethod("one.vmpool.accounting", vm_pool_acct); @@ -400,6 +409,7 @@ void RequestManager::register_xml_methods() RequestManagerRegistry.addMethod("one.template.chown", template_chown); RequestManagerRegistry.addMethod("one.template.chmod", template_chmod); RequestManagerRegistry.addMethod("one.template.clone", template_clone); + RequestManagerRegistry.addMethod("one.template.rename", template_rename); RequestManagerRegistry.addMethod("one.templatepool.info",template_pool_info); @@ -436,6 +446,7 @@ void RequestManager::register_xml_methods() RequestManagerRegistry.addMethod("one.vn.info", vn_info); RequestManagerRegistry.addMethod("one.vn.chown", vn_chown); RequestManagerRegistry.addMethod("one.vn.chmod", vn_chmod); + RequestManagerRegistry.addMethod("one.vn.rename", vn_rename); RequestManagerRegistry.addMethod("one.vnpool.info", vnpool_info); @@ -465,6 +476,7 @@ void RequestManager::register_xml_methods() RequestManagerRegistry.addMethod("one.image.chmod", image_chmod); RequestManagerRegistry.addMethod("one.image.chtype", image_chtype); RequestManagerRegistry.addMethod("one.image.clone", image_clone); + RequestManagerRegistry.addMethod("one.image.rename", image_rename); RequestManagerRegistry.addMethod("one.imagepool.info", imagepool_info); @@ -506,6 +518,7 @@ void RequestManager::register_xml_methods() RequestManagerRegistry.addMethod("one.document.chown", doc_chown); RequestManagerRegistry.addMethod("one.document.chmod", doc_chmod); RequestManagerRegistry.addMethod("one.document.clone", doc_clone); + RequestManagerRegistry.addMethod("one.document.rename", doc_rename); RequestManagerRegistry.addMethod("one.documentpool.info",docpool_info); diff --git a/src/rm/RequestManagerAllocate.cc b/src/rm/RequestManagerAllocate.cc index 84dcd007c0..b5e2ce4878 100644 --- a/src/rm/RequestManagerAllocate.cc +++ b/src/rm/RequestManagerAllocate.cc @@ -238,13 +238,20 @@ int VirtualMachineAllocate::pool_allocate(xmlrpc_c::paramList const& paramList, string& error_str, RequestAttributes& att) { + bool on_hold = false; + + if ( paramList.size() > 2 ) + { + on_hold = xmlrpc_c::value_boolean(paramList.getBoolean(2)); + } + VirtualMachineTemplate * ttmpl= static_cast(tmpl); VirtualMachinePool * vmpool = static_cast(pool); Template tmpl_back(*tmpl); int rc = vmpool->allocate(att.uid, att.gid, att.uname, att.gname, ttmpl, &id, - error_str, false); + error_str, on_hold); if ( rc < 0 ) { diff --git a/src/rm/RequestManagerRename.cc b/src/rm/RequestManagerRename.cc new file mode 100644 index 0000000000..ff9dabab62 --- /dev/null +++ b/src/rm/RequestManagerRename.cc @@ -0,0 +1,113 @@ +/* -------------------------------------------------------------------------- */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +#include "RequestManagerRename.h" +#include "PoolObjectSQL.h" + +#include "NebulaLog.h" +#include "Nebula.h" + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void RequestManagerRename::request_execute(xmlrpc_c::paramList const& paramList, + RequestAttributes& att) +{ + int oid = xmlrpc_c::value_int(paramList.getInt(1)); + string new_name = xmlrpc_c::value_string(paramList.getString(2)); + + int rc; + string old_name; + + PoolObjectAuth operms; + PoolObjectSQL * object; + + rc = get_info(pool, oid, auth_object, att, operms, old_name); + + if ( rc == -1 ) + { + return; + } + + if (old_name == new_name) + { + success_response(oid, att); + return; + } + + // ------------- Set authorization request for non-oneadmin's -------------- + + if ( att.uid != 0 ) + { + AuthRequest ar(att.uid, att.gid); + + ar.add_auth(auth_op, operms); // MANAGE OBJECT + + if (UserPool::authorize(ar) == -1) + { + failure_response(AUTHORIZATION, + authorization_error(ar.message, att), + att); + + return; + } + } + + // --------------- Check name uniqueness ----------------------------------- + + object = get(new_name, operms.uid, true); + + if ( object != 0 ) + { + ostringstream oss; + int id = object->get_oid(); + + object->unlock(); + + oss << PoolObjectSQL::type_to_str(auth_object) + << " cannot be renamed to " << new_name + << " because it collides with " + << PoolObjectSQL::type_to_str(auth_object) << " " + << id; + + failure_response(INTERNAL, request_error(oss.str(), ""), att); + return; + } + + // --------------- Update the object --------------------------------------- + + object = pool->get(oid, true); + + if ( object == 0 ) + { + failure_response(NO_EXISTS, + get_error(object_name(auth_object), oid), + att); + } + + object->set_name(new_name); + + pool->update(object); + + object->unlock(); + + pool->update_cache_index(old_name, operms.uid, new_name, operms.uid); + + success_response(oid, att); + + return; +} + diff --git a/src/rm/RequestManagerVMTemplate.cc b/src/rm/RequestManagerVMTemplate.cc index 043230638d..d4af5ef766 100644 --- a/src/rm/RequestManagerVMTemplate.cc +++ b/src/rm/RequestManagerVMTemplate.cc @@ -27,6 +27,13 @@ void VMTemplateInstantiate::request_execute(xmlrpc_c::paramList const& paramList int id = xmlrpc_c::value_int(paramList.getInt(1)); string name = xmlrpc_c::value_string(paramList.getString(2)); + bool on_hold = false; + + if ( paramList.size() > 3 ) + { + on_hold = xmlrpc_c::value_boolean(paramList.getBoolean(3)); + } + int rc, vid; PoolObjectAuth perms; @@ -109,7 +116,7 @@ void VMTemplateInstantiate::request_execute(xmlrpc_c::paramList const& paramList Template tmpl_back(*tmpl); rc = vmpool->allocate(att.uid, att.gid, att.uname, att.gname, tmpl, &vid, - error_str, false); + error_str, on_hold); if ( rc < 0 ) { diff --git a/src/rm/RequestManagerVirtualMachine.cc b/src/rm/RequestManagerVirtualMachine.cc index 016354557d..644dfce4cd 100644 --- a/src/rm/RequestManagerVirtualMachine.cc +++ b/src/rm/RequestManagerVirtualMachine.cc @@ -200,6 +200,46 @@ int RequestManagerVirtualMachine::get_host_information(int hid, /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +bool RequestManagerVirtualMachine::check_host(int hid, + int cpu, + int mem, + int disk, + string& error) +{ + Nebula& nd = Nebula::instance(); + HostPool * hpool = nd.get_hpool(); + + Host * host; + bool test; + + host = hpool->get(hid, true); + + if (host == 0) + { + error = "Host no longer exists"; + return false; + } + + test = host->test_capacity(cpu, mem, disk); + + if (!test) + { + ostringstream oss; + + oss << object_name(PoolObjectSQL::HOST) + << " " << hid << " does not have enough capacity."; + + error = oss.str(); + } + + host->unlock(); + + return test; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + VirtualMachine * RequestManagerVirtualMachine::get_vm(int id, RequestAttributes& att) { @@ -387,31 +427,43 @@ void VirtualMachineDeploy::request_execute(xmlrpc_c::paramList const& paramList, string ds_location; int ds_id; - int id = xmlrpc_c::value_int(paramList.getInt(1)); - int hid = xmlrpc_c::value_int(paramList.getInt(2)); + int id = xmlrpc_c::value_int(paramList.getInt(1)); + int hid = xmlrpc_c::value_int(paramList.getInt(2)); + bool enforce = false; + + if ( paramList.size() != 3 ) + { + enforce = xmlrpc_c::value_boolean(paramList.getBoolean(3)); + } bool auth = false; - if (get_host_information( - hid, hostname, vmm_mad, vnm_mad, tm_mad, ds_location, ds_id, att, - host_perms) != 0) + if (get_host_information(hid, + hostname, + vmm_mad, + vnm_mad, + tm_mad, + ds_location, + ds_id, + att, + host_perms) != 0) { return; } auth = vm_authorization(id, 0, 0, att, &host_perms, 0, auth_op); - if ( auth == false ) + if (auth == false) { return; } - if ( (vm = get_vm(id, att)) == 0 ) + if ((vm = get_vm(id, att)) == 0) { return; } - if ( vm->get_state() != VirtualMachine::PENDING ) + if (vm->get_state() != VirtualMachine::PENDING) { failure_response(ACTION, request_error("Wrong state to perform action",""), @@ -421,8 +473,36 @@ void VirtualMachineDeploy::request_execute(xmlrpc_c::paramList const& paramList, return; } - if ( add_history( - vm,hid,hostname,vmm_mad,vnm_mad,tm_mad,ds_location,ds_id,att) != 0) + if (enforce) + { + int cpu, mem, disk; + string error; + + vm->get_requirements(cpu, mem, disk); + + vm->unlock(); + + if (check_host(hid, cpu, mem, disk, error) == false) + { + failure_response(ACTION, request_error(error,""), att); + return; + } + + if ((vm = get_vm(id, att)) == 0) + { + return; + } + } + + if (add_history(vm, + hid, + hostname, + vmm_mad, + vnm_mad, + tm_mad, + ds_location, + ds_id, + att) != 0) { vm->unlock(); return; @@ -459,27 +539,39 @@ void VirtualMachineMigrate::request_execute(xmlrpc_c::paramList const& paramList string aux_st; int current_hid; - int id = xmlrpc_c::value_int(paramList.getInt(1)); - int hid = xmlrpc_c::value_int(paramList.getInt(2)); - bool live = xmlrpc_c::value_boolean(paramList.getBoolean(3)); + int id = xmlrpc_c::value_int(paramList.getInt(1)); + int hid = xmlrpc_c::value_int(paramList.getInt(2)); + bool live = xmlrpc_c::value_boolean(paramList.getBoolean(3)); + bool enforce = false; + + if ( paramList.size() != 4 ) + { + enforce = xmlrpc_c::value_boolean(paramList.getBoolean(4)); + } bool auth = false; - if (get_host_information( - hid, hostname, vmm_mad, vnm_mad, tm_mad, ds_location, ds_id, att, - host_perms) != 0) + if (get_host_information(hid, + hostname, + vmm_mad, + vnm_mad, + tm_mad, + ds_location, + ds_id, + att, + host_perms) != 0) { return; } auth = vm_authorization(id, 0, 0, att, &host_perms, 0, auth_op); - if ( auth == false ) + if (auth == false) { return; } - if ( (vm = get_vm(id, att)) == 0 ) + if ((vm = get_vm(id, att)) == 0) { return; } @@ -498,11 +590,35 @@ void VirtualMachineMigrate::request_execute(xmlrpc_c::paramList const& paramList current_hid = vm->get_hid(); - vm->unlock(); + if (enforce) + { + int cpu, mem, disk; + string error; - if (get_host_information( - current_hid, aux_st, aux_st, aux_st, aux_st, aux_st, current_ds_id, - att, aux_perms) != 0) + vm->get_requirements(cpu, mem, disk); + + vm->unlock(); + + if (check_host(hid, cpu, mem, disk, error) == false) + { + failure_response(ACTION, request_error(error,""), att); + return; + } + } + else + { + vm->unlock(); + } + + if (get_host_information(current_hid, + aux_st, + aux_st, + aux_st, + aux_st, + aux_st, + current_ds_id, + att, + aux_perms) != 0) { return; } @@ -529,14 +645,21 @@ void VirtualMachineMigrate::request_execute(xmlrpc_c::paramList const& paramList return; } - if ( add_history(vm, hid, hostname, vmm_mad, vnm_mad, tm_mad, ds_location, - ds_id, att) != 0) + if (add_history(vm, + hid, + hostname, + vmm_mad, + vnm_mad, + tm_mad, + ds_location, + ds_id, + att) != 0) { vm->unlock(); return; } - if ( live == true ) + if (live == true) { dm->live_migrate(vm); } diff --git a/src/rm/SConstruct b/src/rm/SConstruct index 4420593001..a4e9bea234 100644 --- a/src/rm/SConstruct +++ b/src/rm/SConstruct @@ -41,7 +41,8 @@ source_files=[ 'RequestManagerChmod.cc', 'RequestManagerCluster.cc', 'RequestManagerClone.cc', - 'RequestManagerSystem.cc' + 'RequestManagerSystem.cc', + 'RequestManagerRename.cc' ] # Build library diff --git a/src/scheduler/src/pool/VirtualMachinePoolXML.cc b/src/scheduler/src/pool/VirtualMachinePoolXML.cc index 1b4852cb69..244d6afd57 100644 --- a/src/scheduler/src/pool/VirtualMachinePoolXML.cc +++ b/src/scheduler/src/pool/VirtualMachinePoolXML.cc @@ -112,27 +112,28 @@ int VirtualMachinePoolXML::dispatch(int vid, int hid, bool resched) const try { - //TODO Get live migration from config file if (resched == true) { client->call(client->get_endpoint(), // serverUrl "one.vm.migrate", // methodName - "siib", // arguments format + "siibb", // 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) + live_resched, // argument 3 (LIVE) + false); // argument 4 (ENFORCE) } else { client->call(client->get_endpoint(), // serverUrl "one.vm.deploy", // methodName - "sii", // arguments format + "siib", // arguments format &deploy_result, // resultP client->get_oneauth().c_str(), // argument 0 (AUTH) vid, // argument 1 (VM) - hid); // argument 2 (HOST) + hid, // argument 2 (HOST) + false); // argument 3 (ENFORCE) } } catch (exception const& e) diff --git a/src/sunstone/models/OpenNebulaJSON/VirtualNetworkJSON.rb b/src/sunstone/models/OpenNebulaJSON/VirtualNetworkJSON.rb index 74a67df77f..bcaad16d56 100644 --- a/src/sunstone/models/OpenNebulaJSON/VirtualNetworkJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/VirtualNetworkJSON.rb @@ -51,6 +51,7 @@ module OpenNebulaJSON when "chmod" then self.chmod_octet(action_hash['params']) when "hold" then self.hold(action_hash['params']) when "release" then self.release(action_hash['params']) + when "rename" then self.rename(action_hash['params']) else error_msg = "#{action_hash['perform']} action not " << " available for this resource" @@ -85,5 +86,9 @@ module OpenNebulaJSON def release(params=Hash.new) super(params['ip']) end + + def rename(params=Hash.new) + super(params['name']) + end end end diff --git a/src/sunstone/public/js/opennebula.js b/src/sunstone/public/js/opennebula.js index 6f1761d2fa..d27ac9e23d 100644 --- a/src/sunstone/public/js/opennebula.js +++ b/src/sunstone/public/js/opennebula.js @@ -589,6 +589,13 @@ var OpenNebula = { }, "fetch_template" : function(params){ OpenNebula.Action.show(params,OpenNebula.Network.resource,"template"); + }, + "rename" : function(params){ + var action_obj = params.data.extra_param; + OpenNebula.Action.simple_action(params, + OpenNebula.Network.resource, + "rename", + action_obj); } }, diff --git a/src/sunstone/public/js/plugins/clusters-tab.js b/src/sunstone/public/js/plugins/clusters-tab.js index c276fc02df..d7af4c0d51 100644 --- a/src/sunstone/public/js/plugins/clusters-tab.js +++ b/src/sunstone/public/js/plugins/clusters-tab.js @@ -14,7 +14,830 @@ /* limitations under the License. */ /* -------------------------------------------------------------------------- */ -/*Cluster tab plugin*/ +/* ---------------- Cluster tab plugin ---------------- */ + +/* ------------ Cluster creation dialog ------------ */ + +var host_datatable_table_tmpl='\ + \ + ' + tr("All") + '\ + ' + tr("ID") + '\ + ' + tr("Name") + '\ + ' + tr("Cluster") + '\ + ' + tr("Running VMs") + '\ + ' + tr("Real CPU") + '\ + ' + tr("Allocated CPU") + '\ + ' + tr("Real MEM") + '\ + ' + tr("Allocated MEM") + '\ + ' + tr("Status") + '\ + ' + tr("IM MAD") + '\ + ' + tr("VM MAD") + '\ + ' + tr("Last monitored on") + '\ + \ + \ + \ + ' + +var vnet_datatable_table_tmpl='\ + \ + '+tr("All")+'\ + '+tr("ID")+'\ + '+tr("Owner")+'\ + '+tr("Group")+'\ + '+tr("Name")+'\ + '+tr("Cluster")+'\ + '+tr("Type")+'\ + '+tr("Bridge")+'\ + '+tr("Total Leases")+'\ + \ + \ + \ + ' + +var datastore_datatable_table_tmpl='\ + \ + ' + tr("All") + '\ + '+tr("ID")+'\ + '+tr("Owner")+'\ + '+tr("Group")+'\ + '+tr("Name")+'\ + '+tr("Cluster")+'\ + '+tr("Basepath")+'\ + '+tr("TM MAD")+'\ + '+tr("DS MAD")+'\ + '+tr("System")+'\ + \ + \ + \ + ' + + +var create_cluster_tmpl ='
\ +
\ + \ +
\ + \ +
\ +
\ +
\ +

' + + tr("Select Hosts for this Cluster") + + '

\ +
\ + ' + host_datatable_table_tmpl + '
\ +
\ +
\ +
\ + \ +
\ +
\ +
\ +
\ +
\ +

' + + tr("Select Virtual Networks for this Cluster") + + '

\ +
\ + ' + vnet_datatable_table_tmpl + '
\ +
\ +
\ +
\ + \ +
\ +
\ + \ +
\ +
\ +
\ +
\ +
\ +

' + + tr("Select Datastores for this Cluster") + + '

\ +
\ + ' + datastore_datatable_table_tmpl + '
\ +
\ +
\ +
\ + \ +
\ +
\ +
\ +
\ + \ + \ + \ +
\ +
\ +
'; + +// Common utils for datatatables + // Holds the selected items +var selected_hosts_list = {}; +var selected_vnets_list = {}; +var selected_datastore_list = {}; + +var host_row_hash = {}; +var vnet_row_hash = {}; +var datastore_row_hash = {}; + +// Prepares the cluster creation dialog +function setupCreateClusterDialog(datatable_filter){ + + $create_cluster_dialog = $('div#create_cluster_dialog'); + var dialog = $create_cluster_dialog; + + dialog.html(create_cluster_tmpl); + var height = Math.floor($(window).height()*0.8); //set height to a percentage of the window + dialog.dialog({ + autoOpen: false, + modal: true, + height: height, + width: 'auto' + }); + + //Enable tabs + $('#cluster_create_tabs',dialog).tabs({}); + + // ------- Create the dialog datatables ------------ + dataTable_cluster_hosts = $("#datatable_cluster_hosts", dialog).dataTable({ + "bJQueryUI": true, + "bSortClasses": false, + "sDom" : '<"H"lfrC>t<"F"ip>', + "oColVis": { //exclude checkbox column + "aiExclude": [ 0 ] + }, + "bAutoWidth":false, + "sPaginationType": "full_numbers", + "aoColumnDefs": [ + { "bSortable": false, "aTargets": ["check"] }, + { "sWidth": "60px", "aTargets": [0,4] }, + { "sWidth": "35px", "aTargets": [1] }, + { "sWidth": "100px", "aTargets": [9,3,10,11,12] }, + { "sWidth": "150", "aTargets": [5,6,7,8] }, + { "bVisible": false, "aTargets": [0,5,6,7,8,10,11,12]} // 3 = cluster + ], + "oLanguage": (datatable_lang != "") ? + { + sUrl: "locale/"+lang+"/"+datatable_lang + } : "" + }); + + //preload it + dataTable_cluster_hosts.fnClearTable(); + + dataTable_cluster_hosts.fnFilter( datatable_filter, 3, true); // Only show no assigned resources + addElement([ + spinner, + '','','','','','','','','','','',''],dataTable_cluster_hosts); + + dataTable_cluster_vnets = $("#datatable_cluster_vnets", dialog).dataTable({ + "bJQueryUI": true, + "bSortClasses": false, + "bAutoWidth":false, + "sDom" : '<"H"lfrC>t<"F"ip>', + "oColVis": { + "aiExclude": [ 0 ] + }, + "sPaginationType": "full_numbers", + "aoColumnDefs": [ + { "bSortable": false, "aTargets": ["check"] }, + { "sWidth": "60px", "aTargets": [0,6,7,8] }, + { "sWidth": "35px", "aTargets": [1] }, + { "sWidth": "100px", "aTargets": [2,3,5] }, + { "bVisible": false, "aTargets": [0,7]} // 5 = cluster + ], + "oLanguage": (datatable_lang != "") ? + { + sUrl: "locale/"+lang+"/"+datatable_lang + } : "" + }); + + + //preload it + dataTable_cluster_vnets.fnClearTable(); + dataTable_cluster_vnets.fnFilter( datatable_filter, 5, true); // Only show no assigned resources + addElement([ + spinner, + '','','','','','','','','','','',''],dataTable_cluster_vnets); + + dataTable_cluster_datastores = $("#datatable_cluster_datastores", dialog).dataTable({ + "bJQueryUI": true, + "bSortClasses": false, + "sDom" : '<"H"lfrC>t<"F"ip>', + "oColVis": { + "aiExclude": [ 0 ] + }, + "sPaginationType": "full_numbers", + "bAutoWidth":false, + "aoColumnDefs": [ + { "bSortable": false, "aTargets": ["check"] }, + { "sWidth": "60px", "aTargets": [0] }, + { "sWidth": "35px", "aTargets": [1,9] }, + { "sWidth": "100px", "aTargets": [2,3,5,7,8] }, + { "bVisible": false, "aTargets": [0,6,7,8,9] } // 5 = cluster + ], + "oLanguage": (datatable_lang != "") ? + { + sUrl: "locale/"+lang+"/"+datatable_lang + } : "" + }); + + + //preload it + dataTable_cluster_datastores.fnClearTable(); + dataTable_cluster_datastores.fnFilter( datatable_filter, 5, true); // Only show no assigned resources + addElement([ + spinner, + '','','','','','','','','','','',''],dataTable_cluster_datastores); + + // ------- End of create the dialog datatables ------------ + + // Add listener to row select action + // Marks it in another background color + // Adds or removes the element from the list + $('#datatable_cluster_hosts', dialog).delegate("tr", "click", function(e){ + if ($(e.target).is('input') || + $(e.target).is('select') || + $(e.target).is('option')) return true; + + var aData = dataTable_cluster_hosts.fnGetData(this); + var host_id = aData[1]; + var name = aData[2]; + + if(!$("td:first", this).hasClass('markrow')) + { + selected_hosts_list[host_id]=1; + host_row_hash[host_id]=this; + $(this).children().each(function(){$(this).addClass('markrow');}); + $('div#selected_hosts_div', dialog).append(''+name+''); + } + else + { + delete selected_hosts_list[host_id]; + $(this).children().each(function(){$(this).removeClass('markrow');}); + $('div#selected_hosts_div span#tag_hosts_'+host_id, dialog).remove(); + } + + return false; + }); + + + $('#datatable_cluster_vnets', dialog).delegate("tr", "click", function(e){ + if ($(e.target).is('input') || + $(e.target).is('select') || + $(e.target).is('option')) return true; + + var aData = dataTable_cluster_vnets.fnGetData(this); + var vnet_id = aData[1]; + var name = aData[4]; + + if(!$("td:first", this).hasClass('markrow')) + { + selected_vnets_list[vnet_id]=1; + vnet_row_hash[vnet_id]=this; + $(this).children().each(function(){$(this).addClass('markrow');}); + $('div#selected_vnets_div', dialog).append(''+name+''); + } + else + { + delete selected_vnets_list[vnet_id]; + $(this).children().each(function(){$(this).removeClass('markrow');}); + $('div#selected_vnets_div span#tag_vnets_'+vnet_id, dialog).remove(); + } + + return false; + }); + + + $('#datatable_cluster_datastores', dialog).delegate("tr", "click", function(e){ + if ($(e.target).is('input') || + $(e.target).is('select') || + $(e.target).is('option')) return true; + + var aData = dataTable_cluster_datastores.fnGetData(this); + var ds_id = aData[1]; + var name = aData[4]; + + if(!$("td:first", this).hasClass('markrow')) + { + selected_datastore_list[ds_id]=1; + datastore_row_hash[ds_id]=this; + $(this).children().each(function(){$(this).addClass('markrow');}); + $('div#selected_datastores_div', dialog).append(''+name+''); + } + else + { + delete selected_datastore_list[ds_id]; + $(this).children().each(function(){$(this).removeClass('markrow');}); + $('div#selected_datastores_div span#tag_datastores_'+ds_id, dialog).remove(); + } + + return false; + }); + + // Add tag listeners + $( "#cluster_create_tabs span.ui-icon-close",$create_cluster_dialog).die(); + $( "#cluster_create_tabs span.ui-icon-close" ).live( "click", function() { + // Remove the tag + $(this).parent().remove(); + + // Unselect row + var id = $(this).parent().attr("ID"); + + if (id.match(/host/g)) + { + var host_id=id.substring(10,id.length); + delete selected_hosts_list[host_id]; + $("td:first", host_row_hash[host_id]).parent().children().each(function(){$(this).removeClass('markrow');}); + } + else if (id.match(/vnet/g)) + { + var vnet_id=id.substring(10,id.length); + delete selected_vnets_list[vnet_id]; + $("td:first", vnet_row_hash[vnet_id]).parent().children().each(function(){$(this).removeClass('markrow');}); + } + else if (id.match(/datastore/g)) + { + var datastore_id=id.substring(15,id.length); + delete selected_datastore_list[datastore_id]; + $("td:first", datastore_row_hash[datastore_id]).parent().children().each(function(){$(this).removeClass('markrow');}); + } + }); + + // Enhance buttons + $('button',dialog).button(); + + $("#refresh_host_table_button_class", dialog).click( function(){ + Sunstone.runAction("ClusterHost.list"); + } + ); + + $("#refresh_vnet_table_button_class", dialog).click( function(){ + Sunstone.runAction("ClusterVN.list"); + } + ); + + $("#refresh_datastore_table_button_class", dialog).click( function(){ + Sunstone.runAction("ClusterDS.list"); + } + ); + + $("#tf_btn_hosts_next", dialog).click( function() + { + $("#cluster_create_tabs", dialog).tabs( "select", "tab-vnets" ); + } + ); + + $("#tf_btn_vnets_back", dialog).click( function() + { + $("#cluster_create_tabs", dialog).tabs( "select", "tab-hosts" ); + } + ); + + $("#tf_btn_vnets_next", dialog).click( function() + { + $("#cluster_create_tabs", dialog).tabs( "select", "tab-datastores" ); + } + ); + + $("#tf_btn_datastores_back", dialog).click( function() + { + $("#cluster_create_tabs", dialog).tabs( "select", "tab-vnets" ); + } + ); + + $("#cluster_create_tabs", dialog).tabs( "select", "tab-hosts" ); + + // Handle the Create button + $('#create_cluster_submit').click(function(){ + + + if (!($('input#name',dialog).val().length)){ + notifyError(tr("Cluster name missing!")); + return false; + } + + var cluster_json = { + "cluster": { + "name": $('#name',dialog).val(), + "hosts": selected_hosts_list, + "vnets": selected_vnets_list, + "datastores": selected_datastore_list + } + }; + + // Create the OpenNebula.Cluster. + // If it is successfull we refresh the list. + Sunstone.runAction("Cluster.create",cluster_json); + + $create_cluster_dialog.dialog('close'); + return false; + }); +} + +function reset_counters(){ + selected_hosts_list = {}; + selected_vnets_list = {}; + selected_datastore_list = {}; + + + host_row_hash = {}; + vnet_row_hash = {}; + datastore_row_hash = {}; +} + +// Open creation dialogs +function popUpCreateClusterDialog(){ + if ($create_cluster_dialog) + { + $create_cluster_dialog.remove(); + dialogs_context.append('
'); + } + + reset_counters; + + setupCreateClusterDialog("-"); + + // Activate create button + $('#create_cluster_submit',$create_cluster_dialog).show(); + $('#update_cluster_submit',$create_cluster_dialog).hide(); + + Sunstone.runAction("ClusterHost.list"); + Sunstone.runAction("ClusterVN.list"); + Sunstone.runAction("ClusterDS.list"); + $create_cluster_dialog.dialog('open'); + return false; +} + +// Open update dialog +function popUpUpdateClusterDialog(){ + + var dialog = $create_cluster_dialog; + + if (dialog) + { + dialog.remove(); + dialogs_context.append('
'); + } + + reset_counters; + + var selected_nodes = getSelectedNodes(dataTable_clusters); + + if ( selected_nodes.length != 1 ) + { + alert("Please select one (and just one) cluster to update."); + return false; + } + + // Get proper cluster_id + var cluster_id = ""+selected_nodes[0]; + var cluster_name = ""; + + var node = $('tbody input.check_item:checked',dataTable_clusters); + + $.each(node,function(){ + cluster_name = $('td', $(this).closest("tr"))[2].innerHTML; + + }); + + var filter_expr = "-|"+cluster_name; + + setupCreateClusterDialog(filter_expr); + + Sunstone.runAction("ClusterHost.list"); + Sunstone.runAction("ClusterVN.list"); + Sunstone.runAction("ClusterDS.list"); + $create_cluster_dialog.dialog('open'); + + $('#create_cluster_dialog').attr('title','Update Cluster'); + + Sunstone.runAction("Cluster.show_to_update", cluster_id); + + return false; + +} + +// Fill update dialog with loaded properties +function fillPopPup(request,response){ + var dialog = $create_cluster_dialog; + + // Harvest variables + var name = response.CLUSTER.NAME; + var host_ids = response.CLUSTER.HOSTS.ID; + var vnet_ids = response.CLUSTER.VNETS.ID; + var ds_ids = response.CLUSTER.DATASTORES.ID; + + if (typeof host_ids == 'string') + { + host_ids = [host_ids]; + } + + if (typeof vnet_ids == 'string') + { + vnet_ids = [vnet_ids]; + } + + if (typeof ds_ids == 'string') + { + ds_ids = [ds_ids]; + } + + // Activate update button + $('#create_cluster_submit',dialog).hide(); + $('#update_cluster_submit',dialog).show(); + + // Fill in the name + $('#name',dialog).val(name); + $('#name',dialog).attr("disabled", "disabled"); + + // Select hosts belonging to the cluster + if (host_ids) + { + for (var i = 0; i < host_ids.length; i++) + { + var rows = $("#datatable_cluster_hosts").dataTable().fnGetNodes(); + + for(var j=0;j'+host_name+''); + } + } + } + } + } + + if (vnet_ids) + { + // Select vnets belonging to the cluster + for (var i = 0; i < vnet_ids.length; i++) + { + var rows = $("#datatable_cluster_vnets").dataTable().fnGetNodes(); + + for(var j=0;j'+vnet_name+''); + } + } + } + } + } + + if (ds_ids) + { + // Select datastores belonging to the cluster + for (var i = 0; i < ds_ids.length; i++) + { + var rows = $("#datatable_cluster_datastores").dataTable().fnGetNodes(); + + for(var j=0;j'+datastore_name+''); + } + } + } + } + } + + // Clone already existing resources (to keep track) + original_hosts_list = $.extend({}, selected_hosts_list); + original_vnets_list = $.extend({}, selected_vnets_list); + original_datastores_list = $.extend({}, selected_datastore_list); + cluster_to_update_id = response.CLUSTER.ID; + + // Define update button + $('#update_cluster_submit').click(function(){ + + // find out which ones are in and out + for (var host_id in selected_hosts_list) + { + if (!original_hosts_list[host_id]) + { + Sunstone.runAction("Cluster.addhost",cluster_to_update_id,host_id); + } + } + + for (var host_id in original_hosts_list) + { + if (!selected_hosts_list[host_id]) + { + Sunstone.runAction("Cluster.delhost",cluster_to_update_id,host_id); + } + } + + for (var vnet_id in selected_vnets_list) + { + if (!original_vnets_list[vnet_id]) + { + Sunstone.runAction("Cluster.addvnet",cluster_to_update_id,vnet_id); + } + } + + for (var vnet_id in original_vnets_list) + { + if (!selected_vnets_list[vnet_id]) + { + Sunstone.runAction("Cluster.delvnet",cluster_to_update_id,vnet_id); + } + } + + for (var ds_id in selected_datastore_list) + { + if (!original_datastores_list[ds_id]) + { + Sunstone.runAction("Cluster.adddatastore",cluster_to_update_id,ds_id); + } + } + + for (var ds_id in original_datastores_list) + { + if (!selected_datastore_list[ds_id]) + { + Sunstone.runAction("Cluster.deldatastore",cluster_to_update_id,ds_id); + } + } + + $create_cluster_dialog.dialog('close'); + Sunstone.runAction('Cluster.list'); + updateClustersView(); + return false; + }); +} + + +/* -------- Host datatable -------- */ + +//Setup actions +var cluster_host_actions = { + + "ClusterHost.list" : { + type: "list", + call: OpenNebula.Host.list, + callback: updateClusterHostsView, + error: onError + }, + + "ClusterHostInfo.list" : { + type: "list", + call: OpenNebula.Host.list, + callback: updateClusterHostsInfoView, + error: onError + } +} + +//callback to update the list of hosts for Create dialog +function updateClusterHostsView (request,host_list){ + var host_list_array = []; + + $.each(host_list,function(){ + //Grab table data from the host_list + host_list_array.push(hostElementArray(this)); + }); + + updateView(host_list_array,dataTable_cluster_hosts); +} + +//callback to update the list of hosts for info panel +function updateClusterHostsInfoView (request,host_list){ + var host_list_array = []; + + $.each(host_list,function(){ + if(this.HOST.CLUSTER_ID == cluster_info.ID) + host_list_array.push(hostElementArray(this)); + }); + + updateView(host_list_array,dataTable_cluster_hosts_panel); +} + + +/* -------- Virtual Networks datatable -------- */ + +//Setup actions +var cluster_vnet_actions = { + + "ClusterVN.list" : { + type: "list", + call: OpenNebula.Network.list, + callback: updateVNetworksView, + error: onError + }, + + "ClusterVNInfo.list" : { + type: "list", + call: OpenNebula.Network.list, + callback: updateClusterVNetworksInfoView, + error: onError + } +} + +//updates the list of virtual networks for Create dialog +function updateVNetworksView(request, network_list){ + var network_list_array = []; + + $.each(network_list,function(){ + network_list_array.push(vNetworkElementArray(this)); + }); + + updateView(network_list_array,dataTable_cluster_vnets); +} + +//callback to update the list of vnets for info panel +function updateClusterVNetworksInfoView (request,vnet_list){ + var vnet_list_array = []; + + $.each(vnet_list,function(){ + if(this.VNET.CLUSTER_ID == cluster_info.ID) + vnet_list_array.push(vNetworkElementArray(this)); + }); + + updateView(vnet_list_array,dataTable_cluster_vnets_panel); +} + + +/* -------- Datastores datatable -------- */ + +//Setup actions +var cluster_datastore_actions = { + + "ClusterDS.list" : { + type: "list", + call: OpenNebula.Datastore.list, + callback: updateDatastoresView, + error: onError + }, + + "ClusterDSInfo.list" : { + type: "list", + call: OpenNebula.Datastore.list, + callback: updateClusterDatastoresInfoView, + error: onError + } +} + +//updates the list of datastores for Create dialog +function updateDatastoresView(request, list){ + var list_array = []; + + $.each(list,function(){ + list_array.push( datastoreElementArray(this)); + }); + + updateView(list_array,dataTable_cluster_datastores); + updateDatastoreSelect(); + updateInfraDashboard("datastores",list); +} + +//callback to update the list of datastores for info panel +function updateClusterDatastoresInfoView (request,datastore_list){ + var datastore_list_array = []; + + $.each(datastore_list,function(){ + if(this.DATASTORE.CLUSTER_ID == cluster_info.ID) + datastore_list_array.push(datastoreElementArray(this)); + }); + + updateView(datastore_list_array,dataTable_cluster_datastores_panel); +} + + +/* -------- End of datatables section -------- */ var clusters_tab_content = '\ @@ -38,34 +861,36 @@ var clusters_tab_content = '\ \ '; -var create_cluster_tmpl = -'
\ -
\ - \ -
\ -
\ -
\ -
\ -
\ -
\ -
\ -
'; - var clusters_select=""; var dataTable_clusters; var $create_cluster_dialog; + //Setup actions var cluster_actions = { "Cluster.create" : { type: "create", - call : OpenNebula.Cluster.create, - callback : function(){ - //addClusterElement, + call: OpenNebula.Cluster.create, + callback: function(request, response){ + for (var host in request.request.data[0].cluster.hosts) + if (request.request.data[0].cluster.hosts[host]) + Sunstone.runAction("Cluster.addhost",response.CLUSTER.ID,host); + for (var vnet in request.request.data[0].cluster.vnets) + if (request.request.data[0].cluster.vnets[vnet]) + Sunstone.runAction("Cluster.addvnet",response.CLUSTER.ID,vnet); + for (var datastore in request.request.data[0].cluster.datastores) + if (request.request.data[0].cluster.datastores[datastore]) + Sunstone.runAction("Cluster.adddatastore",response.CLUSTER.ID,datastore); + Sunstone.runAction('Cluster.list'); + updateClustersView(); + + setTimeout(Sunstone.runAction('Cluster.list'),5000); + setTimeout(updateClustersView(),5000); + }, - error : onError, + error: onError, notify: true }, @@ -81,22 +906,19 @@ var cluster_actions = { error: onError }, - "Cluster.show" : { - type: "single", - call: OpenNebula.Cluster.show, - callback: updateClusterElement, - error: onError - }, - -/* - "Cluster.showinfo" : { type: "single", call: OpenNebula.Cluster.show, callback: updateClusterInfo, error: onError }, -*/ + + "Cluster.show_to_update" : { + type: "single", + call: OpenNebula.Cluster.show, + callback: fillPopPup, + error: onError + }, "Cluster.refresh" : { type: "custom", @@ -177,11 +999,12 @@ var cluster_actions = { notify:true }, - "Cluster.update" : { + "Cluster.update_template" : { // Update template type: "single", call: OpenNebula.Cluster.update, - callback: function(){ - notifyMessage(tr("Template updated correctly")); + callback: function(request,response){ + notifyMessage(tr("Template updated correctly")); + Sunstone.runAction('Cluster.showinfo',request.request.data[0]); }, error: onError }, @@ -196,17 +1019,9 @@ var cluster_actions = { }, "Cluster.update_dialog" : { - type: "custom", - call: function() { - popUpTemplateUpdateDialog("Cluster", - makeSelectOptions(dataTable_clusters, - 1,//idcol - 2,//namecol - [], - []), - clusterElements()); - } - } + type: "single", + call: popUpUpdateClusterDialog + }, }; var cluster_buttons = { @@ -230,25 +1045,6 @@ var cluster_buttons = { } }; -/* -var host_info_panel = { - "host_info_tab" : { - title: tr("Host information"), - content:"" - }, - - "host_template_tab" : { - title: tr("Host template"), - content: "" - }, - "host_monitoring_tab": { - title: tr("Monitoring information"), - content: "" - } -}; -*/ - - var clusters_tab = { title: tr("Clusters"), content: clusters_tab_content, @@ -258,6 +1054,27 @@ var clusters_tab = { parentTab: "infra_tab" }; +var cluster_info_panel = { + "cluster_info_tab" : { + title: tr("Cluster information"), + content:"" + }, + + "cluster_host_tab" : { + title: tr("Cluster Hosts"), + content: "" + }, + "cluster_vnet_tab" : { + title: tr("Cluster Virtual Networks"), + content: "" + }, + "cluster_datastore_tab" : { + title: tr("Cluster Datastores"), + content: "" + } + +}; + // Cluster monitoring configuration. This config controls the monitoring // which is plotted in the cluster dashboards. @@ -385,9 +1202,12 @@ SunstoneMonitoringConfig['CLUSTER_HOST'] = { } +Sunstone.addActions(cluster_host_actions); +Sunstone.addActions(cluster_vnet_actions); +Sunstone.addActions(cluster_datastore_actions); Sunstone.addActions(cluster_actions); Sunstone.addMainTab('clusters_tab',clusters_tab); -//Sunstone.addInfoPanel("host_info_panel",host_info_panel); +Sunstone.addInfoPanel("cluster_info_panel",cluster_info_panel); //return lists of selected elements in cluster list function clusterElements(){ @@ -482,6 +1302,162 @@ function updateClustersView (request,list){ updateInfraDashboard("clusters",list); }; + +// Updates the cluster info panel tab content and pops it up +function updateClusterInfo(request,cluster){ + cluster_info = cluster.CLUSTER; + cluster_template = cluster_info.TEMPLATE; + + //Information tab + var info_tab = { + title : tr("Information"), + content : + '\ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
' + + tr("Information for Cluster") + + ' - '+cluster_info.NAME+'
' + tr("id") + ''+cluster_info.ID+'
' + tr("Name") + ''+cluster_info.NAME+'
' + + insert_extended_template_table(cluster_template, + "Cluster", + cluster_info.ID) + } + + var cluster_host_tab = { + title: tr("Hosts"), + content : '
' + host_datatable_table_tmpl + '
' + } + + var cluster_vnet_tab = { + title: tr("Virtual Networks"), + content : '
' + vnet_datatable_table_tmpl + '
' + } + + var cluster_datastore_tab = { + title: tr("Datastores"), + content : '
' + datastore_datatable_table_tmpl + '
' + } + + //Sunstone.updateInfoPanelTab(info_panel_name,tab_name, new tab object); + Sunstone.updateInfoPanelTab("cluster_info_panel","cluster_info_tab",info_tab); + Sunstone.updateInfoPanelTab("cluster_info_panel","cluster_host_tab",cluster_host_tab); + Sunstone.updateInfoPanelTab("cluster_info_panel","cluster_vnet_tab",cluster_vnet_tab); + Sunstone.updateInfoPanelTab("cluster_info_panel","cluster_datastore_tab",cluster_datastore_tab); + + Sunstone.popUpInfoPanel("cluster_info_panel"); + + // Hosts datatable + + dataTable_cluster_hosts_panel = $("#datatable_cluster_hosts_info_panel").dataTable({ + "bJQueryUI": true, + "bSortClasses": false, + "sDom" : '<"H"lfrC>t<"F"ip>', + "oColVis": { //exclude checkbox column + "aiExclude": [ 0 ] + }, + "bAutoWidth":false, + "sPaginationType": "full_numbers", + "aoColumnDefs": [ + { "bSortable": false, "aTargets": ["check"] }, + { "sWidth": "60px", "aTargets": [0,4] }, + { "sWidth": "35px", "aTargets": [1] }, + { "sWidth": "100px", "aTargets": [9,3,10,11,12] }, + { "sWidth": "150", "aTargets": [5,6,7,8] }, + { "bVisible": false, "aTargets": [0,3,5,6,7,8,10,11,12]} + ], + "oLanguage": (datatable_lang != "") ? + { + sUrl: "locale/"+lang+"/"+datatable_lang + } : "" + }); + + //preload it + dataTable_cluster_hosts_panel.fnClearTable(); + + addElement([ + spinner, + '','','','','','','','','','','',''],dataTable_cluster_hosts_panel); + + // Virtual networks datatable + + dataTable_cluster_vnets_panel = $("#datatable_cluster_vnets_info_panel", dialog).dataTable({ + "bJQueryUI": true, + "bSortClasses": false, + "bAutoWidth":false, + "sDom" : '<"H"lfrC>t<"F"ip>', + "oColVis": { + "aiExclude": [ 0 ] + }, + "sPaginationType": "full_numbers", + "aoColumnDefs": [ + { "bSortable": false, "aTargets": ["check"] }, + { "sWidth": "60px", "aTargets": [0,6,7,8] }, + { "sWidth": "35px", "aTargets": [1] }, + { "sWidth": "100px", "aTargets": [2,3,5] }, + { "bVisible": false, "aTargets": [0,5,7]} + ], + "oLanguage": (datatable_lang != "") ? + { + sUrl: "locale/"+lang+"/"+datatable_lang + } : "" + }); + + + //preload it + dataTable_cluster_vnets_panel.fnClearTable(); + addElement([ + spinner, + '','','','','','','','','','','',''],dataTable_cluster_vnets_panel); + + // Datastores datatable + + dataTable_cluster_datastores_panel = $("#datatable_cluster_datastores_info_panel", dialog).dataTable({ + "bJQueryUI": true, + "bSortClasses": false, + "sDom" : '<"H"lfrC>t<"F"ip>', + "oColVis": { + "aiExclude": [ 0 ] + }, + "sPaginationType": "full_numbers", + "bAutoWidth":false, + "aoColumnDefs": [ + { "bSortable": false, "aTargets": ["check"] }, + { "sWidth": "60px", "aTargets": [0] }, + { "sWidth": "35px", "aTargets": [1,9] }, + { "sWidth": "100px", "aTargets": [2,3,5,7,8] }, + { "bVisible": false, "aTargets": [0,5,6,7,8,9] } + ], + "oLanguage": (datatable_lang != "") ? + { + sUrl: "locale/"+lang+"/"+datatable_lang + } : "" + }); + + + //preload it + dataTable_cluster_datastores_panel.fnClearTable(); + addElement([ + spinner, + '','','','','','','','','','','',''],dataTable_cluster_datastores_panel); + + // initialize datatables values + Sunstone.runAction("ClusterHostInfo.list"); + Sunstone.runAction("ClusterVNInfo.list"); + Sunstone.runAction("ClusterDSInfo.list"); +} + + //generates the HTML for the dashboard of a specific cluster function clusterTabContent(cluster_json) { var cluster = cluster_json.CLUSTER; @@ -509,38 +1485,6 @@ function clusterTabContent(cluster_json) { } else if (cluster.VNETS.ID) vnets_n = 1; -/* - var dss_list = '
  • '+tr("No datastores in this cluster")+'
  • '; - if (cluster.DATASTORES.ID && - cluster.DATASTORES.ID.constructor == Array){ - dss_list = ''; - for (var i=0; i'; - }; - } else if (cluster.DATASTORES.ID) - dss_list = '
  • '+cluster.DATASTORES.ID+' - '+getDatastoreName(cluster.DATASTORES.ID)+'
  • '; - - var hosts_list = '
  • '+tr("No hosts in this cluster")+'
  • '; - if (cluster.HOSTS.ID && - cluster.HOSTS.ID.constructor == Array){ - hosts_list = ''; - for (var i=0; i'; - }; - } else if (cluster.HOSTS.ID) - hosts_list = '
  • '+cluster.HOSTS.ID+' - '+getHostName(cluster.HOSTS.ID)+'
  • '; - - var vnets_list = '
  • '+tr("No virtual networks in this cluster")+'
  • '; - if (cluster.VNETS.ID && - cluster.VNETS.ID.constructor == Array){ - vnets_list = ''; - for (var i=0; i'; - }; - } else if (cluster.VNETS.ID) - vnets_list = '
  • '+cluster.VNETS.ID+' - '+getVNetName(cluster.VNETS.ID)+'
  • '; -*/ - //special case for cluster none, simplified dashboard if (cluster.ID == "-"){ var html_code = '\ @@ -766,16 +1710,10 @@ function clusterTabContent(cluster_json) { function removeClusterMenus(){ var data = dataTable_clusters.fnGetData(); -// Sunstone.removeMainTab('cluster_vnets_tab_n',true); -// Sunstone.removeMainTab('cluster_datastores_tab_n',true); -// Sunstone.removeMainTab('cluster_hosts_tab_n',true); Sunstone.removeMainTab('cluster_tab_-',true); for (var i=0; i < data.length; i++){ var id = data[i][1]; -// Sunstone.removeMainTab('cluster_vnets_tab_'+id,true); -// Sunstone.removeMainTab('cluster_datastores_tab_'+id,true); -// Sunstone.removeMainTab('cluster_hosts_tab_'+id,true); Sunstone.removeMainTab('cluster_tab_'+id,true); }; }; @@ -816,36 +1754,11 @@ function newClusterMenuElement(element){ content: clusterTabContent(element), tabClass: 'subTab subsubTab', parentTab: 'clusters_tab' -// buttons: null - }; -/* - var submenu_hosts = { - title: tr("Hosts"), - content: '', - tabClass: "subTab clusterHosts subsubTab", - parentTab: "cluster_tab_" + cluster.ID + }; - var submenu_datastores = { - title: tr("Datastores"), - content: '', - tabClass: "subTab clusterDatastores subsubTab", - parentTab: "cluster_tab_" + cluster.ID - }; - - var submenu_vnets = { - title: tr("Virtual Networks"), - content: '', - tabClass: "subTab clusterVnets subsubTab", - parentTab: "cluster_tab_" + cluster.ID - }; -*/ // Add to sunstone Sunstone.addMainTab('cluster_tab_'+cluster.ID,menu_cluster,true); - -// Sunstone.addMainTab('cluster_hosts_tab_'+cluster.ID,submenu_hosts,true); -// Sunstone.addMainTab('cluster_datastores_tab_'+cluster.ID,submenu_datastores,true); -// Sunstone.addMainTab('cluster_vnets_tab_'+cluster.ID,submenu_vnets,true); }; // Basicly, we show the hosts/datastore/vnets tab, but before we set @@ -869,78 +1782,8 @@ function clusterResourceViewListeners(){ showTab(dest,'li_cluster_tab'+filter_id); return false; }); -/* - $('div#menu li.clusterHosts').live('click',function(){ - var id = $(this).attr('id'); - id = id.split('_'); - id = id[id.length-1]; - dataTable_hosts.fnFilter(getClusterName(id),3,false,true,false,true); - showTab('#hosts_tab',$(this).attr('id').substring(3)); - return false; - }); - - $('div#menu li.clusterDatastores').live('click',function(){ - var id = $(this).attr('id'); - id = id.split('_'); - id = id[id.length-1]; - dataTable_datastores.fnFilter(getClusterName(id),5,false,true,false,true); - showTab('#datastores_tab',$(this).attr('id').substring(3)); - return false; - }); - - $('div#menu li.clusterVnets').live('click',function(){ - var id = $(this).attr('id'); - id = id.split('_'); - id = id[id.length-1]; - dataTable_vNetworks.fnFilter(getClusterName(id),5,false,true,false,true); - showTab('#vnets_tab',$(this).attr('id').substring(3)); - return false; - }); -*/ }; -//Prepares the host creation dialog -function setupCreateClusterDialog(){ - dialogs_context.append('
    '); - $create_cluster_dialog = $('div#create_cluster_dialog'); - var dialog = $create_cluster_dialog; - - dialog.html(create_cluster_tmpl); - dialog.dialog({ - autoOpen: false, - modal: true, - width: 400 - }); - - $('button',dialog).button(); - - //Handle the form submission - $('#create_cluster_form',dialog).submit(function(){ - if (!($('#name',this).val().length)){ - notifyError(tr("Cluster name missing!")); - return false; - } - - var cluster_json = { - "cluster": { - "name": $('#name',this).val() - } - }; - - //Create the OpenNebula.Cluster. - //If it is successfull we refresh the list. - Sunstone.runAction("Cluster.create",cluster_json); - $create_cluster_dialog.dialog('close'); - return false; - }); -} - -//Open creation dialogs -function popUpCreateClusterDialog(){ - $create_cluster_dialog.dialog('open'); - return false; -} - // Receives the list of hosts, divides them into clusters. // For each cluster, it calls the monitoring action for the hosts @@ -983,7 +1826,6 @@ function setClusterAutorefresh() { },INTERVAL+someTime()); } - function clusters_sel() { return clusters_select; } @@ -993,6 +1835,7 @@ function clusters_sel() { //and add specific listeners $(document).ready(function(){ + //prepare host datatable dataTable_clusters = $("#datatable_clusters",main_tabs_context).dataTable({ "bJQueryUI": true, @@ -1021,7 +1864,7 @@ $(document).ready(function(){ '','','','',''],dataTable_clusters); Sunstone.runAction("Cluster.list"); - setupCreateClusterDialog(); + dialogs_context.append('
    '); setClusterAutorefresh(); @@ -1029,5 +1872,5 @@ $(document).ready(function(){ initCheckAllBoxes(dataTable_clusters); tableCheckboxesListener(dataTable_clusters); - infoListener(dataTable_clusters); + infoListener(dataTable_clusters, "Cluster.showinfo"); }); diff --git a/src/sunstone/public/js/plugins/datastores-tab.js b/src/sunstone/public/js/plugins/datastores-tab.js index cac0a1aca7..7e7eae2cf8 100644 --- a/src/sunstone/public/js/plugins/datastores-tab.js +++ b/src/sunstone/public/js/plugins/datastores-tab.js @@ -90,57 +90,69 @@ var create_datastore_tmpl = \ '; -var update_datastore_tmpl = - '
    \ -

    '+tr("Please, choose and modify the datastore you want to update")+':

    \ -
    \ - \ - \ -
    \ -
    \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ -
    '+tr("Permissions")+':'+tr("Use")+''+tr("Manage")+''+tr("Admin")+'
    '+tr("Owner")+'
    '+tr("Group")+'
    '+tr("Other")+'
    \ -
    \ - \ -
    \ - \ -
    \ -
    \ -
    \ - \ -
    \ -
    \ -
    '; +var datastore_image_table_tmpl='\ + \ + '+tr("All")+'\ + '+tr("ID")+'\ + '+tr("Owner")+'\ + '+tr("Group")+'\ + '+tr("Name")+'\ + '+tr("Datastore")+'\ + '+tr("Size")+'\ + '+tr("Type")+'\ + '+tr("Registration time")+'\ + '+tr("Persistent")+'\ + '+tr("Status")+'\ + '+tr("#VMS")+'\ + '+tr("Target")+'\ + \ + \ + \ + ' var datastores_select=""; var dataTable_datastores; var $create_datastore_dialog; + +/* -------- Image datatable -------- */ + +//Setup actions +var datastore_image_actions = { + + "DatastoreImageInfo.list" : { + type: "list", + call: OpenNebula.Image.list, + callback: updateDatastoreImagesInfoView, + error: onError + } +} + +//callback to update the list of images for Create dialog +function updateDatastoreImagesInfoView (request,image_list){ + var image_list_array = []; + + $.each(image_list,function(){ + //Grab table data from the image_list + image_list_array.push(imageElementArray(this)); + }); + + updateView(image_list_array,dataTable_datastore_images_panel); +} + +//callback to update the list of images for info panel +function updateDatastoreimagesInfoView (request,image_list){ + var image_list_array = []; + + $.each(image_list,function(){ + if(this.IMAGE.DATASTORE_ID == datastore_info.ID) + image_list_array.push(imageElementArray(this)); + }); + + updateView(image_list_array,dataTable_datastore_images_panel); +} + + //Setup actions var datastore_actions = { @@ -187,29 +199,25 @@ var datastore_actions = { error: onError }, - "Datastore.fetch_template" : { - type: "single", - call: OpenNebula.Datastore.fetch_template, - callback: function (request,response) { - $('#datastore_template_update_dialog #datastore_template_update_textarea').val(response.template); - }, - error: onError - }, "Datastore.fetch_permissions" : { type: "single", call: OpenNebula.Datastore.show, callback: function(request,element_json){ - var dialog = $('#datastore_template_update_dialog form'); var ds = element_json.DATASTORE; - setPermissionsTable(ds,dialog); + setPermissionsTable(ds,$(".datastore_permissions_table")); }, error: onError }, - "Datastore.update_dialog" : { - type: "custom", - call: popUpDatastoreTemplateUpdateDialog + "Datastore.update_template" : { + type: "single", + call: OpenNebula.Datastore.update, + callback: function(request) { + notifyMessage("Template updated correctly"); + Sunstone.runAction('Datastore.showinfo',request.request.data[0]); + }, + error: onError }, "Datastore.update" : { @@ -309,12 +317,6 @@ var datastore_buttons = { text: tr("+ New"), condition: mustBeAdmin }, - "Datastore.update_dialog" : { - type: "action", - text: tr("Update properties"), - alwaysActive: true, - condition: mustBeAdmin - }, "Datastore.addtocluster" : { type: "confirm_with_select", text: tr("Select cluster"), @@ -351,11 +353,7 @@ var datastore_buttons = { var datastore_info_panel = { "datastore_info_tab" : { - title: tr("Datastore information"), - content: "" - }, - "datastore_template_tab" : { - title: tr("Datastore template"), + title: tr("Information"), content: "" } } @@ -370,6 +368,7 @@ var datastores_tab = { } Sunstone.addActions(datastore_actions); +Sunstone.addActions(datastore_image_actions); Sunstone.addMainTab('datastores_tab',datastores_tab); Sunstone.addInfoPanel('datastore_info_panel',datastore_info_panel); @@ -451,12 +450,9 @@ function updateDatastoreInfo(request,ds){ images_str=getImageName(info.IMAGES.ID); }; - var info_tab = { - title : tr("Datastore information"), - content: - '\ + var info_tab_content = '
    \ \ - \ + \ \ \ \ @@ -491,39 +487,74 @@ function updateDatastoreInfo(request,ds){ \ \ \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ \ -
    '+tr("Datastore information")+' - '+info.NAME+'
    '+tr("Information for Datastore")+' - '+info.NAME+'
    '+tr("Base path")+''+info.BASE_PATH+'
    '+tr("Images")+''+images_str+'
    '+tr("Permissions")+'
         '+tr("Owner")+''+ownerPermStr(info)+'
         '+tr("Group")+''+groupPermStr(info)+'
         '+tr("Other")+''+otherPermStr(info)+'
    ' + '; + + + // Inserts the extended template table to the show info tab (down tab) + info_tab_content += insert_extended_template_table(info.TEMPLATE, + "Datastore", + info.ID) + + // Inserts the change permissions table + info_tab_content += insert_permissions_table("Datastore",info.ID); + + + var info_tab = { + title : tr("Information"), + content: info_tab_content } - var template_tab = { - title: tr("Datastore Template"), - content: - '\ - '+ - prettyPrintJSON(info.TEMPLATE)+ - '
    '+tr("Datastore template")+'
    ' + var datastore_info_tab = { + title: tr("Images"), + content : '
    ' + datastore_image_table_tmpl + '
    ' } + + // Add tabs Sunstone.updateInfoPanelTab("datastore_info_panel","datastore_info_tab",info_tab); - Sunstone.updateInfoPanelTab("datastore_info_panel","datastore_template_tab",template_tab); + Sunstone.updateInfoPanelTab("datastore_info_panel","datastore_image_tab",datastore_info_tab); Sunstone.popUpInfoPanel("datastore_info_panel"); + + // Define datatables + // Images datatable + + dataTable_datastore_images_panel = $("#datatable_datastore_images_info_panel").dataTable({ + "bJQueryUI": true, + "bSortClasses": false, + "bAutoWidth":false, + "sDom" : '<"H"lfrC>t<"F"ip>', + "oColVis": { + "aiExclude": [ 0 ] + }, + "sPaginationType": "full_numbers", + "aoColumnDefs": [ + { "bSortable": false, "aTargets": ["check"] }, + { "sWidth": "60px", "aTargets": [0,2,3,9,10] }, + { "sWidth": "35px", "aTargets": [1,6,11,12] }, + { "sWidth": "100px", "aTargets": [5,7] }, + { "sWidth": "150px", "aTargets": [8] }, + { "bVisible": false, "aTargets": [6,8,12]} + ], + "oLanguage": (datatable_lang != "") ? + { + sUrl: "locale/"+lang+"/"+datatable_lang + } : "" + }); + + //preload it + dataTable_datastore_images_panel.fnClearTable(); + + addElement([ + spinner, + '','','','','','','','','','','',''],dataTable_datastore_images_panel); + + + // initialize datatables values + Sunstone.runAction("DatastoreImageInfo.list"); + + Sunstone.runAction("Datastore.fetch_permissions",info.ID); + } // Set up the create datastore dialog @@ -593,107 +624,6 @@ function popUpCreateDatastoreDialog(){ $create_datastore_dialog.dialog('open'); } -function setupDatastoreTemplateUpdateDialog(){ - //Append to DOM - dialogs_context.append('
    '); - var dialog = $('#datastore_template_update_dialog',dialogs_context); - - //Put HTML in place - dialog.html(update_datastore_tmpl); - - var height = Math.floor($(window).height()*0.8); //set height to a percentage of the window - - //Convert into jQuery - dialog.dialog({ - autoOpen:false, - width:500, - modal:true, - height:height, - resizable:true - }); - - $('button',dialog).button(); - - $('#datastore_template_update_select',dialog).change(function(){ - var id = $(this).val(); - $('.permissions_table input',dialog).removeAttr('checked'); - $('.permissions_table',dialog).removeAttr('update'); - if (id && id.length){ - var dialog = $('#datastore_template_update_dialog'); - $('#template_template_update_textarea',dialog).val(tr("Loading")+"..."); - Sunstone.runAction("Datastore.fetch_template",id); - Sunstone.runAction("Datastore.fetch_permissions",id); - } else { - $('#datastore_template_update_textarea',dialog).val(""); - }; - }); - - $('.permissions_table input',dialog).change(function(){ - $(this).parents('table').attr('update','update'); - }); - - $('form',dialog).submit(function(){ - var dialog = $(this); - var new_template = $('#datastore_template_update_textarea',dialog).val(); - var id = $('#datastore_template_update_select',dialog).val(); - if (!id || !id.length) { - $(this).parents('#datastore_template_update_dialog').dialog('close'); - return false; - }; - - var permissions = $('.permissions_table',dialog); - if (permissions.attr('update')){ - var perms = { - octet : buildOctet(permissions) - }; - Sunstone.runAction("Datastore.chmod",id,perms); - }; - - Sunstone.runAction("Datastore.update",id,new_template); - $(this).parents('#datastore_template_update_dialog').dialog('close'); - return false; - }); -}; - -// Standard template edition dialog -// If one element is selected auto fecth template -// otherwise let user select -function popUpDatastoreTemplateUpdateDialog(){ - var select = makeSelectOptions(dataTable_datastores, - 1,//id_col - 4,//name_col - [], - [] - ); - var sel_elems = getSelectedNodes(dataTable_datastores); - - - var dialog = $('#datastore_template_update_dialog'); - $('#datastore_template_update_select',dialog).html(select); - $('#datastore_template_update_textarea',dialog).val(""); - $('.permissions_table input',dialog).removeAttr('checked'); - $('.permissions_table',dialog).removeAttr('update'); - - if (sel_elems.length >= 1){ //several items in the list are selected - //grep them - var new_select= sel_elems.length > 1? '' : ""; - $('option','').each(function(){ - var val = $(this).val(); - if ($.inArray(val,sel_elems) >= 0){ - new_select+=''; - }; - }); - $('#datastore_template_update_select',dialog).html(new_select); - if (sel_elems.length == 1) { - $('#datastore_template_update_select option',dialog).attr('selected','selected'); - $('#datastore_template_update_select',dialog).trigger("change"); - }; - }; - - dialog.dialog('open'); - return false; -}; - //Prepares autorefresh function setDatastoreAutorefresh(){ setInterval(function(){ @@ -738,7 +668,6 @@ $(document).ready(function(){ Sunstone.runAction("Datastore.list"); setupCreateDatastoreDialog(); - setupDatastoreTemplateUpdateDialog(); setDatastoreAutorefresh(); initCheckAllBoxes(dataTable_datastores); diff --git a/src/sunstone/public/js/plugins/hosts-tab.js b/src/sunstone/public/js/plugins/hosts-tab.js index 9d1e2088c2..028394b004 100644 --- a/src/sunstone/public/js/plugins/hosts-tab.js +++ b/src/sunstone/public/js/plugins/hosts-tab.js @@ -243,34 +243,12 @@ var host_actions = { error: hostMonitorError }, - "Host.fetch_template" : { - type: "single", - call: OpenNebula.Host.fetch_template, - callback: function (request,response) { - $('#template_update_dialog #template_update_textarea').val(response.template); - }, - error: onError - }, - - "Host.update_dialog" : { - type: "custom", - call: function() { - popUpTemplateUpdateDialog("Host", - makeSelectOptions(dataTable_hosts, - 1,//id_col - 2,//name_col - [], - [] - ), - getSelectedNodes(dataTable_hosts)); - } - }, - - "Host.update" : { + "Host.update_template" : { type: "single", call: OpenNebula.Host.update, - callback: function() { + callback: function(request) { notifyMessage(tr("Template updated correctly")); + Sunstone.runAction('Host.showinfo',request.request.data[0]); }, error: onError }, @@ -319,12 +297,7 @@ var host_buttons = { text: tr("+ New"), condition: mustBeAdmin }, - "Host.update_dialog" : { - type: "action", - text: tr("Update a template"), - alwaysActive: true, - condition: mustBeAdmin - }, + "Host.addtocluster" : { type: "confirm_with_select", text: tr("Select cluster"), @@ -571,53 +544,53 @@ function hostElementArray(host_json){ // Generate CPU progress bars var max_cpu = parseInt(host.HOST_SHARE.MAX_CPU); - if (!max_cpu) { + if (!max_cpu) { max_cpu = 100 } var allocated_cpu = parseInt(host.HOST_SHARE.CPU_USAGE); var ratio_allocated_cpu = Math.round((allocated_cpu / max_cpu) * 100); - var pb_allocated_cpu = progressBar(ratio_allocated_cpu, { + var pb_allocated_cpu = progressBar(ratio_allocated_cpu, { label: allocated_cpu + ' / ' + max_cpu + ' (' + ratio_allocated_cpu + '%)', - width: '150px', - height: '15px', + width: '150px', + height: '15px', fontSize: '1em' }); var real_cpu = parseInt(host.HOST_SHARE.USED_CPU); var ratio_real_cpu = Math.round((real_cpu / max_cpu) * 100); - var pb_real_cpu = progressBar(ratio_real_cpu, { + var pb_real_cpu = progressBar(ratio_real_cpu, { label: real_cpu + ' / ' + max_cpu + ' (' + ratio_real_cpu + '%)', - width: '150px', - height: '15px', + width: '150px', + height: '15px', fontSize: '1em'}); // Generate MEM progress bars var max_mem = parseInt(host.HOST_SHARE.MAX_MEM); - if (!max_mem) { + if (!max_mem) { max_mem = 100 } var allocated_mem = parseInt(host.HOST_SHARE.MEM_USAGE); var ratio_allocated_mem = Math.round((allocated_mem / max_mem) * 100); - var pb_allocated_mem = progressBar(ratio_allocated_mem, { + var pb_allocated_mem = progressBar(ratio_allocated_mem, { label: humanize_size(allocated_mem) + ' / ' + humanize_size(max_mem) + ' (' + ratio_allocated_mem + '%)', - width: '150px', - height: '15px', + width: '150px', + height: '15px', fontSize: '1em' }); var real_mem = parseInt(host.HOST_SHARE.USED_MEM); var ratio_real_mem = Math.round((real_mem / max_mem) * 100); - var pb_real_mem = progressBar(ratio_real_mem, { + var pb_real_mem = progressBar(ratio_real_mem, { label: humanize_size(real_mem) + ' / ' + humanize_size(max_mem) + ' (' + ratio_real_mem + '%)', - width: '150px', - height: '15px', + width: '150px', + height: '15px', fontSize: '1em' }); @@ -697,11 +670,11 @@ function updateHostInfo(request,host){ //Information tab var info_tab = { - title : tr("Host information"), + title : tr("Information"), content : '\ \ - \ + \ \ \ \ @@ -768,18 +741,11 @@ function updateHostInfo(request,host){ \ \ \ -
    ' + tr("Host information") + ' - '+host_info.NAME+'
    ' + tr("Information for Host") + ' - '+host_info.NAME+'
    '+host_info.HOST_SHARE.RUNNING_VMS+'
    ' + ' + insert_extended_template_table(host_info.TEMPLATE, + "Host", + host_info.ID) } - //Template tab - var template_tab = { - title : tr("Host template"), - content : - '\ - '+ - prettyPrintJSON(host_info.TEMPLATE)+ - '
    ' + tr("Host template") + '
    ' - } var monitor_tab = { title: tr("Monitoring information"), @@ -788,7 +754,6 @@ function updateHostInfo(request,host){ //Sunstone.updateInfoPanelTab(info_panel_name,tab_name, new tab object); Sunstone.updateInfoPanelTab("host_info_panel","host_info_tab",info_tab); - Sunstone.updateInfoPanelTab("host_info_panel","host_template_tab",template_tab); Sunstone.updateInfoPanelTab("host_info_panel","host_monitoring_tab",monitor_tab); Sunstone.popUpInfoPanel("host_info_panel"); diff --git a/src/sunstone/public/js/plugins/vnets-tab.js b/src/sunstone/public/js/plugins/vnets-tab.js index f11aa4a365..0f5badc766 100644 --- a/src/sunstone/public/js/plugins/vnets-tab.js +++ b/src/sunstone/public/js/plugins/vnets-tab.js @@ -355,36 +355,33 @@ var vnet_actions = { notify: true }, - "Network.fetch_template" : { + "Network.rename" : { type: "single", - call: OpenNebula.Network.fetch_template, - callback: function (request,response) { - $('#vnet_template_update_dialog #vnet_template_update_textarea').val(response.template); + call: OpenNebula.Network.rename, + callback: function(request) { + notifyMessage("VirtualNetwork renamed correctly"); + Sunstone.runAction('Network.showinfo',request.request.data[0]); }, - error: onError + error: onError, + notify: true }, "Network.fetch_permissions" : { type: "single", call: OpenNebula.Network.show, callback: function(request,vnet_json){ - var dialog = $('#vnet_template_update_dialog form'); var vnet = vnet_json.VNET; - setPermissionsTable(vnet,dialog); + setPermissionsTable(vnet,$(".network_permissions_table")); }, error: onError }, - "Network.update_dialog" : { - type: "custom", - call: popUpVNetTemplateUpdateDialog - }, - - "Network.update" : { + "Network.update_template" : { type: "single", call: OpenNebula.Network.update, - callback: function() { + callback: function(request) { notifyMessage("Template updated correctly"); + Sunstone.runAction('Network.showinfo',request.request.data[0]); }, error: onError }, @@ -434,11 +431,6 @@ var vnet_buttons = { text: tr("+ New") }, - "Network.update_dialog" : { - type: "action", - text: tr("Update properties"), - alwaysActive: true - }, "Network.addtocluster" : { type: "confirm_with_select", text: tr("Select cluster"), @@ -566,8 +558,8 @@ function updateVNetworkInfo(request,vn){ var info_tab_content = '\ \ - \ + \ \ \ \ @@ -575,7 +567,11 @@ function updateVNetworkInfo(request,vn){ \ \ \ - \ + \ + \ \ \ \ @@ -605,30 +601,17 @@ function updateVNetworkInfo(request,vn){ \ \ \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \
    '+tr("Virtual Network")+' '+vn_info.ID+' '+ - tr("information")+'
    '+tr("Information for Virtual Network")+' - '+vn_info.NAME+' '+ + '
    '+tr("ID")+'
    '+tr("Name")+''+vn_info.NAME+''+vn_info.NAME+'
    \ + e\ +
    \ +
    '+tr("Cluster")+''+tr("VLAN ID")+''+ (typeof(vn_info.VLAN_ID) == "object" ? "--": vn_info.VLAN_ID) +'
    '+tr("Permissions")+'
         '+tr("Owner")+''+ownerPermStr(vn_info)+'
         '+tr("Group")+''+groupPermStr(vn_info)+'
         '+tr("Other")+''+otherPermStr(vn_info)+'
    '; - info_tab_content += '\ - \ - '+ - prettyPrintJSON(vn_info.TEMPLATE)+ - '
    '+tr("Virtual Network template (attributes)")+'
    '; + info_tab_content += insert_extended_template_table(vn_info.TEMPLATE, + "Network", + vn_info.ID); + + info_tab_content += insert_permissions_table("Network",vn_info.ID); var info_tab = { - title: tr("Virtual Network information"), + title: tr("Information"), content: info_tab_content }; @@ -637,11 +620,33 @@ function updateVNetworkInfo(request,vn){ content: printLeases(vn_info) }; + $("#div_edit_link").die(); + $(".div_edit_rename_link").die(); + + // Listener for key,value pair edit action + $("#div_edit_rename_link").live("click", function() { + var value_str = $(".value_td_rename").text(); + $(".value_td_rename").html(''); + }); + + $(".input_edit_value_rename").live("change", function() { + var value_str = $(".input_edit_value_rename").val(); + if(value_str!="") + { + // Let OpenNebula know + var name_template = {"name": value_str}; + Sunstone.runAction("Network.rename",vn_info.ID,name_template); + } + }); + + Sunstone.updateInfoPanelTab("vnet_info_panel","vnet_info_tab",info_tab); Sunstone.updateInfoPanelTab("vnet_info_panel","vnet_leases_tab",leases_tab); Sunstone.popUpInfoPanel("vnet_info_panel"); + Sunstone.runAction("Network.fetch_permissions",vn_info.ID); + } // Prints the lis of leases depending on the Vnet TYPE @@ -1023,109 +1028,6 @@ function popUpCreateVnetDialog() { } -function setupVNetTemplateUpdateDialog(){ - //Append to DOM - dialogs_context.append('
    '); - var dialog = $('#vnet_template_update_dialog',dialogs_context); - - //Put HTML in place - dialog.html(update_vnet_tmpl); - - var height = Math.floor($(window).height()*0.8); //set height to a percentage of the window - - //Convert into jQuery - dialog.dialog({ - autoOpen:false, - width:700, - modal:true, - height:height, - resizable:true - }); - - $('button',dialog).button(); - - $('#vnet_template_update_select',dialog).change(function(){ - var id = $(this).val(); - $('.permissions_table input',dialog).removeAttr('checked') - $('.permissions_table',dialog).removeAttr('update'); - if (id && id.length){ - var dialog = $('#vnet_template_update_dialog'); - $('#vnet_template_update_textarea',dialog).val(tr("Loading")+"..."); - - Sunstone.runAction("Network.fetch_permissions",id); - Sunstone.runAction("Network.fetch_template",id); - } else { - $('#vnet_template_update_textarea',dialog).val(""); - }; - }); - - $('.permissions_table input',dialog).change(function(){ - $(this).parents('table').attr('update','update'); - }); - - $('form',dialog).submit(function(){ - var dialog = $(this); - var new_template = $('#vnet_template_update_textarea',dialog).val(); - var id = $('#vnet_template_update_select',dialog).val(); - if (!id || !id.length) { - $(this).parents('#vnet_template_update_dialog').dialog('close'); - return false; - }; - - var permissions = $('.permissions_table',dialog); - if (permissions.attr('update')){ - var perms = { - octet : buildOctet(permissions) - }; - Sunstone.runAction("Network.chmod",id,perms); - }; - - Sunstone.runAction("Network.update",id,new_template); - $(this).parents('#vnet_template_update_dialog').dialog('close'); - return false; - }); -}; - - -// When 1 elem in the list is selected then fetch template automaticly -// Otherwise include selected elements in the select and let user choose -function popUpVNetTemplateUpdateDialog(){ - var select = makeSelectOptions(dataTable_vNetworks, - 1,//id_col - 4,//name_col - [], - [] - ); - var sel_elems = getSelectedNodes(dataTable_vNetworks); - - - var dialog = $('#vnet_template_update_dialog'); - $('#vnet_template_update_select',dialog).html(select); - $('#vnet_template_update_textarea',dialog).val(""); - $('.permissions_table input',dialog).removeAttr('checked'); - $('.permissions_table',dialog).removeAttr('update'); - - if (sel_elems.length >= 1){ //several items in the list are selected - //grep them - var new_select= sel_elems.length > 1? '' : ""; - $('option','').each(function(){ - var val = $(this).val(); - if ($.inArray(val,sel_elems) >= 0){ - new_select+=''; - }; - }); - $('#vnet_template_update_select',dialog).html(new_select); - if (sel_elems.length == 1) { - $('#vnet_template_update_select option',dialog).attr('selected','selected'); - $('#vnet_template_update_select',dialog).trigger("change"); - }; - }; - - dialog.dialog('open'); - return false; - -} - // Listeners to the add, hold, release, delete leases operations in the // extended information panel. function setupLeasesOps(){ @@ -1228,7 +1130,6 @@ $(document).ready(function(){ Sunstone.runAction("Network.list"); setupCreateVNetDialog(); - setupVNetTemplateUpdateDialog(); setupLeasesOps(); setVNetAutorefresh(); diff --git a/src/sunstone/public/js/sunstone-util.js b/src/sunstone/public/js/sunstone-util.js index c2bc9fb84b..cf641bbfb5 100644 --- a/src/sunstone/public/js/sunstone-util.js +++ b/src/sunstone/public/js/sunstone-util.js @@ -237,7 +237,7 @@ function notifyMessage(msg){ // Returns an HTML string with the json keys and values // Attempts to css format output, giving different values to // margins etc. according to depth level etc. -// See exapmle of use in plugins. +// See example of use in plugins. function prettyPrintJSON(template_json,padding,weight, border_bottom,padding_top_bottom){ var str = "" if (!template_json){ return "Not defined";} @@ -1217,7 +1217,7 @@ function quotaListItem(quota_json){ */ function progressBar(value, opts){ if (value > 100) value = 100; - + if (!opts) opts = {}; if (!opts.width) opts.width = 'auto'; @@ -1261,4 +1261,174 @@ function loadAccounting(resource, id, graphs, options){ graph_cfg.show_date = (end - start) > (3600 * 24)? true : false; Sunstone.runAction(resource+".accounting", id, graph_cfg); }; +} + +function insert_extended_template_table(template_json,resource_type,resource_id) +{ + var str = '\ + \ + \ + \ + \ + \ + \ + \ + \ + \ + ' + fromJSONtoHTMLTable(template_json, + resource_type, + resource_id) + + '
    ' + + tr("Extended Template") + + '
    \
    ' + + // Remove previous listeners + $("#new_key").die(); + $("#new_value").die(); + $("#div_minus").die(); + $("#div_edit").die(); + $(".input_edit_value").die(); + $("button").die(); + + // Add listener for add key and add value for Extended Template + $('button').live("click", function() { + if ( $('#new_value').val() != "" && $('#new_key').val() != "" ) + { + template_json[$('#new_key').val()] = $('#new_value').val(); + + var template_str = ""; + for(var key in template_json) + template_str=template_str+key+"="+ template_json[key]+"\n"; + + Sunstone.runAction(resource_type+".update_template",resource_id,template_str); + } + }); + + // Listener for key,value pair remove action + $("#div_minus").live("click", function() { + // Remove div_minus_ from the id + field=this.firstElementChild.id.substring(10,this.firstElementChild.id.length); + // Erase the value from the template + delete template_json[tr(field)]; + + // Convert from hash to string + var template_str = "\n"; + for(var key in template_json) + template_str=template_str+key+"="+ template_json[key]+"\n"; + + // Let OpenNebula know + Sunstone.runAction(resource_type+".update_template",resource_id,template_str); + }); + + // Listener for key,value pair edit action + $("#div_edit").live("click", function() { + var key_str=this.firstElementChild.id.substring(9,this.firstElementChild.id.length); + + var value_str = $("#value_td_input_"+key_str).text(); + $("#value_td_input_"+key_str).html(''); + + }); + + + $(".input_edit_value").live("change", function() { + var key_str = this.id.substring(11,this.id.length); + var value_str = this.value; + + delete template_json[key_str]; + template_json[key_str]=value_str; + + // Convert from hash to string + var template_str = "\n"; + for(var key in template_json) + template_str=template_str+key+"="+ template_json[key]+"\n"; + + // Let OpenNebula know + Sunstone.runAction(resource_type+".update_template",resource_id,template_str); + }); + + return str; +} + +// Returns an HTML string with the json keys and values +function fromJSONtoHTMLTable(template_json,resource_type,resource_id){ + var str = "" + if (!template_json){ return "Not defined";} + var field = null; + + if (template_json.constructor == Array){ + for (field = 0; field < template_json.length; ++field){ + str += fromJSONtoHTMLRow(field, + template_json[field], + template_json, + resource_type, + resource_id); + } + } else { + for (field in template_json) { + str += fromJSONtoHTMLRow(field, + template_json[field], + template_json, + resource_type, + resource_id); + } + } + return str; +} + +// Helper for fromJSONtoHTMLTable function +function fromJSONtoHTMLRow(field,value,template_json,resource_type,resource_id){ + var str = '\ + '+tr(field)+'\ + '+value+'\ +
    \ + e\ +
    \ + \ +
    \ + x\ +
    \ + \ + '; + + return str; +} + +// Returns HTML with listeners to control permissions +function insert_permissions_table(resource_type,resource_id){ + var str ='\ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
    '+tr("Permissions")+':'+tr("Use")+''+tr("Manage")+''+tr("Admin")+'
    '+tr("Owner")+'
    '+tr("Group")+'
    '+tr("Other")+'
    ' + + $(".permission_check").die(); + $(".permission_check").live('change',function(){ + var permissions_table = $("."+resource_type.toLowerCase()+"_permissions_table"); + var permissions_octect = { octet : buildOctet(permissions_table) }; + + Sunstone.runAction(resource_type+".chmod",resource_id,permissions_octect); + }); + + return str; + } \ No newline at end of file diff --git a/src/sunstone/views/index.erb b/src/sunstone/views/index.erb index e984a64d1f..da3551ec0d 100644 --- a/src/sunstone/views/index.erb +++ b/src/sunstone/views/index.erb @@ -326,6 +326,16 @@ hr{margin:18px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff <% end %> + + @@ -375,4 +385,4 @@ hr{margin:18px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff
    - \ No newline at end of file + diff --git a/src/template/Template.cc b/src/template/Template.cc index 4905639714..5e8725b093 100644 --- a/src/template/Template.cc +++ b/src/template/Template.cc @@ -22,6 +22,8 @@ #include #include +#define TO_UPPER(S) transform(S.begin(),S.end(),S.begin(),(int(*)(int))toupper) + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ @@ -473,6 +475,37 @@ bool Template::get( /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +bool Template::get( + const string& name, + bool& value) const +{ + string sval; + + get(name, sval); + + if ( sval == "" ) + { + value = false; + return false; + } + + TO_UPPER(sval); + + if ( sval == "YES" ) + { + value = true; + } + else + { + value = false; + } + + return true; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + string& Template::to_xml(string& xml) const { multimap::const_iterator it; diff --git a/src/tm_mad/iscsi/clone b/src/tm_mad/iscsi/clone index ccce7f0df8..89feebfc55 100755 --- a/src/tm_mad/iscsi/clone +++ b/src/tm_mad/iscsi/clone @@ -81,14 +81,10 @@ CLONE_CMD=$(cat < /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ @@ -63,7 +64,6 @@ int Quota::get_quota( void Quota::add_to_quota(VectorAttribute * attr, const string& va_name, float num) { istringstream iss; - ostringstream oss; float total; iss.str(attr->vector_value(va_name.c_str())); @@ -72,9 +72,7 @@ void Quota::add_to_quota(VectorAttribute * attr, const string& va_name, float nu total += num; - oss << total; - - attr->replace(va_name, oss.str()); + attr->replace(va_name, float_to_str(total)); } /* -------------------------------------------------------------------------- */ @@ -371,24 +369,22 @@ int Quota::update_limits( VectorAttribute * quota, const VectorAttribute * va) { - string limit; - float limit_i; + string limit; + float limit_f; for (int i=0; i < num_metrics; i++) { - limit = va->vector_value_str(metrics[i], limit_i); + limit = va->vector_value_str(metrics[i], limit_f); //No quota, NaN or negative if ((!is_default && - ( limit_i < -1 || ( limit_i == -1 && limit == "" ))) || - (is_default && limit_i < 0) ) + ( limit_f < -1 || ( limit_f == -1 && limit == "" ))) || + (is_default && limit_f < 0) ) { return -1; } - else - { - quota->replace(metrics[i], limit); - } + + quota->replace(metrics[i], float_to_str(limit_f)); } return 0; @@ -402,7 +398,7 @@ VectorAttribute * Quota::new_quota(VectorAttribute * va) map limits; string limit; - int limit_i; + float limit_f; for (int i=0; i < num_metrics; i++) { @@ -410,16 +406,16 @@ VectorAttribute * Quota::new_quota(VectorAttribute * va) metrics_used += "_USED"; - limit = va->vector_value_str(metrics[i], limit_i); + limit = va->vector_value_str(metrics[i], limit_f); //No quota, NaN or negative - if ( (!is_default && limit_i < -1) || - (is_default && limit_i < 0) ) + if ( (!is_default && limit_f < -1) || + (is_default && limit_f < 0) ) { return 0; } - limits.insert(make_pair(metrics[i], limit)); + limits.insert(make_pair(metrics[i], float_to_str(limit_f))); limits.insert(make_pair(metrics_used, "0")); } @@ -433,3 +429,23 @@ VectorAttribute * Quota::new_quota(VectorAttribute * va) return new VectorAttribute(template_name,limits); } +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +string Quota::float_to_str(const float &num) +{ + ostringstream oss; + + if ( num == ceil(num) ) + { + oss.precision(0); + } + else + { + oss.precision(2); + } + + oss << fixed << num; + + return oss.str(); +} diff --git a/src/vm/VirtualMachinePool.cc b/src/vm/VirtualMachinePool.cc index b00c431b80..8c40ffcd92 100644 --- a/src/vm/VirtualMachinePool.cc +++ b/src/vm/VirtualMachinePool.cc @@ -25,6 +25,7 @@ /* -------------------------------------------------------------------------- */ time_t VirtualMachinePool::_monitor_expiration; +bool VirtualMachinePool::_submit_on_hold; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ @@ -35,7 +36,8 @@ VirtualMachinePool::VirtualMachinePool( const string& hook_location, const string& remotes_location, vector& restricted_attrs, - time_t expire_time) + time_t expire_time, + bool on_hold) : PoolSQL(db, VirtualMachine::table, false) { const VectorAttribute * vattr; @@ -50,6 +52,7 @@ VirtualMachinePool::VirtualMachinePool( bool state_hook = false; _monitor_expiration = expire_time; + _submit_on_hold = on_hold; if ( _monitor_expiration == 0 ) { @@ -232,7 +235,7 @@ int VirtualMachinePool::allocate ( // ------------------------------------------------------------------------ vm = new VirtualMachine(-1, uid, gid, uname, gname, vm_template); - if (on_hold == true) + if ( _submit_on_hold == true || on_hold ) { vm->state = VirtualMachine::HOLD; }