mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-23 22:50:09 +03:00
Merge branch 'master' of git.opennebula.org:one
This commit is contained in:
commit
22a8915b1a
@ -148,16 +148,11 @@ protected:
|
||||
map<string, Attribute *>::iterator& it);
|
||||
|
||||
/**
|
||||
* Deletes a quota from the index. The quota pointer is freed.
|
||||
* @param it The quota iterator, as returned by Quota::get_quota
|
||||
* Checks if a quota has 0 limit and usage, and deletes it
|
||||
*
|
||||
* @param qid id of the quota
|
||||
*/
|
||||
virtual void del(map<string, Attribute *>::iterator& it)
|
||||
{
|
||||
Attribute * attr = it->second;
|
||||
delete attr;
|
||||
|
||||
attributes.erase(it);
|
||||
}
|
||||
void cleanup_quota(const string& qid);
|
||||
|
||||
private:
|
||||
/**
|
||||
|
@ -60,6 +60,7 @@ public:
|
||||
*/
|
||||
void del(Template* tmpl);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Gets a quota, overrides base to not to use ID.
|
||||
* @param id of the quota, ignored
|
||||
@ -83,17 +84,10 @@ public:
|
||||
VectorAttribute **va,
|
||||
map<string, Attribute *>::iterator& it)
|
||||
{
|
||||
it = attributes.end();
|
||||
it = attributes.begin();
|
||||
return get_quota(id, va);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides base to not delete anything
|
||||
* @param it The quota iterator, ignored
|
||||
*/
|
||||
void del(map<string, Attribute *>::iterator& it){}
|
||||
|
||||
protected:
|
||||
static const char * VM_METRICS[];
|
||||
|
||||
static const int NUM_VM_METRICS;
|
||||
|
@ -57,6 +57,20 @@ protected:
|
||||
int new_uid,
|
||||
int new_gid,
|
||||
RequestAttributes& att);
|
||||
|
||||
/**
|
||||
* Checks if the new owner cannot has other object with the same name (if
|
||||
* the pool does not allow it)
|
||||
*
|
||||
* @param oid Object id
|
||||
* @param noid New owner user id
|
||||
* @param error_str Error reason, if any
|
||||
*
|
||||
* @return 0 if the operation is allowed, -1 otherwise
|
||||
*/
|
||||
virtual int check_name_unique(int oid, int noid, string& error_str);
|
||||
|
||||
virtual PoolObjectSQL * get(const string& name, int uid, bool lock) = 0;
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
@ -75,6 +89,16 @@ public:
|
||||
};
|
||||
|
||||
~VirtualMachineChown(){};
|
||||
|
||||
int check_name_unique(int oid, int noid, string& error_str)
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
|
||||
PoolObjectSQL * get(const string& name, int uid, bool lock)
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
@ -86,13 +110,18 @@ public:
|
||||
TemplateChown():
|
||||
RequestManagerChown("TemplateChown",
|
||||
"Changes ownership of a virtual machine template")
|
||||
{
|
||||
{
|
||||
Nebula& nd = Nebula::instance();
|
||||
pool = nd.get_tpool();
|
||||
auth_object = PoolObjectSQL::TEMPLATE;
|
||||
};
|
||||
|
||||
~TemplateChown(){};
|
||||
|
||||
PoolObjectSQL * get(const string& name, int uid, bool lock)
|
||||
{
|
||||
return static_cast<VMTemplatePool*>(pool)->get(name, uid, lock);
|
||||
};
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
@ -113,6 +142,10 @@ public:
|
||||
|
||||
~VirtualNetworkChown(){};
|
||||
|
||||
PoolObjectSQL * get(const string& name, int uid, bool lock)
|
||||
{
|
||||
return static_cast<VirtualNetworkPool*>(pool)->get(name, uid, lock);
|
||||
};
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
@ -132,6 +165,10 @@ public:
|
||||
|
||||
~ImageChown(){};
|
||||
|
||||
PoolObjectSQL * get(const string& name, int uid, bool lock)
|
||||
{
|
||||
return static_cast<ImagePool*>(pool)->get(name, uid, lock);
|
||||
};
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
@ -156,6 +193,11 @@ public:
|
||||
|
||||
virtual void request_execute(xmlrpc_c::paramList const& _paramList,
|
||||
RequestAttributes& att);
|
||||
|
||||
PoolObjectSQL * get(const string& name, int uid, bool lock)
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
@ -175,6 +217,10 @@ public:
|
||||
|
||||
~DatastoreChown(){};
|
||||
|
||||
PoolObjectSQL * get(const string& name, int uid, bool lock)
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
@ -193,6 +239,11 @@ public:
|
||||
};
|
||||
|
||||
~DocumentChown(){};
|
||||
|
||||
PoolObjectSQL * get(const string& name, int uid, bool lock)
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
@ -875,7 +875,7 @@ TM_LVM_FILES="src/tm_mad/lvm/clone \
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
DATASTORE_DRIVER_COMMON_SCRIPTS="src/datastore_mad/remotes/xpath.rb \
|
||||
src/datastore_mad/remotes/downloader.rb \
|
||||
src/datastore_mad/remotes/downloader.sh \
|
||||
src/datastore_mad/remotes/libfs.sh"
|
||||
|
||||
DATASTORE_DRIVER_DUMMY_SCRIPTS="src/datastore_mad/remotes/dummy/cp \
|
||||
|
@ -206,9 +206,8 @@ EOT
|
||||
else
|
||||
rc = OneHelper.name_to_id(name, pool, poolname)
|
||||
|
||||
if rc.first==-1
|
||||
return -1, "OpenNebula #{poolname} #{name} " <<
|
||||
"not found, use the ID instead"
|
||||
if rc.first == -1
|
||||
return rc[0], rc[1]
|
||||
end
|
||||
|
||||
rc[1]
|
||||
|
@ -18,6 +18,8 @@ require 'cli_helper'
|
||||
|
||||
class OneQuotaHelper
|
||||
|
||||
EDITOR_PATH='/usr/bin/vi'
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Tables to format user quotas
|
||||
#---------------------------------------------------------------------------
|
||||
|
@ -1,286 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
# -------------------------------------------------------------------------- #
|
||||
# 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. #
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
require 'open3'
|
||||
require 'net/http'
|
||||
require 'uri'
|
||||
require 'optparse'
|
||||
require 'digest'
|
||||
require 'fileutils'
|
||||
|
||||
require 'pp'
|
||||
|
||||
|
||||
class Stream
|
||||
BLOCK_SIZE=1024*64
|
||||
|
||||
TYPES={
|
||||
"application/x-gzip" => "gunzip -c -",
|
||||
"application/x-bzip2" => "bunzip2 -c -",
|
||||
}
|
||||
|
||||
POSTPROCESS_TYPE={
|
||||
"application/x-tar" => "tar -xf #IN# -C #OUT#",
|
||||
"application/zip" => "unzip -d #OUT# #IN#"
|
||||
}
|
||||
|
||||
DIGEST={
|
||||
"md5" => lambda { Digest::MD5.new },
|
||||
"sha1" => lambda { Digest::SHA1.new },
|
||||
"sha256" => lambda { Digest::SHA2.new(256) },
|
||||
"sha384" => lambda { Digest::SHA2.new(384) },
|
||||
"sha512" => lambda { Digest::SHA2.new(512) },
|
||||
}
|
||||
|
||||
def initialize(from, to, options={})
|
||||
@from=from
|
||||
@to=to
|
||||
@options=options
|
||||
|
||||
@digests={}
|
||||
|
||||
@uncompress_proc=nil
|
||||
@compr_in=nil
|
||||
@compr_out=nil
|
||||
|
||||
@writer_thread=nil
|
||||
|
||||
prepare_digests
|
||||
end
|
||||
|
||||
def open_output_file
|
||||
if @to=='-'
|
||||
@output_file=STDOUT.dup
|
||||
else
|
||||
begin
|
||||
@output_file=File.open(@to, "w")
|
||||
rescue
|
||||
STDERR.puts "Error opening output file '#{@to}"
|
||||
exit(-1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def prepare_digests
|
||||
@options.each do |key, value|
|
||||
if DIGEST.has_key?(key)
|
||||
@digests[key]={
|
||||
:hash => value,
|
||||
:digest => DIGEST[key].call
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def process(data)
|
||||
begin
|
||||
try=5
|
||||
begin
|
||||
@compr_in.write(data)
|
||||
@compr_in.flush
|
||||
rescue
|
||||
if try>0
|
||||
try-=1
|
||||
sleep 0.1
|
||||
retry
|
||||
end
|
||||
end
|
||||
rescue
|
||||
STDERR.puts "Error uncompressing image."
|
||||
exit(-1)
|
||||
end
|
||||
|
||||
@digests.each do |name, algo|
|
||||
algo[:digest] << data
|
||||
end
|
||||
end
|
||||
|
||||
def type(header)
|
||||
io=Open3.popen3("file -b --mime-type -")
|
||||
io[0].write(header)
|
||||
io[0].close
|
||||
out=io[1].read.strip
|
||||
io[1].close
|
||||
out
|
||||
end
|
||||
|
||||
def set_compress(header)
|
||||
t=type(header)
|
||||
|
||||
compr=TYPES[t]||"cat"
|
||||
|
||||
compr="#{compr} >&#{@output_file.fileno}"
|
||||
|
||||
@uncompress_proc=Open3.popen3(compr)
|
||||
|
||||
@compr_in=@uncompress_proc[0]
|
||||
@compr_out=@uncompress_proc[1]
|
||||
end
|
||||
|
||||
def start_file_writer
|
||||
@writer_thread=Thread.new do
|
||||
while(!@compr_out.eof?)
|
||||
data=@compr_out.read(BLOCK_SIZE)
|
||||
if data
|
||||
#STDERR.puts "Compr reader #{data.length}"
|
||||
@output_file.write(data)
|
||||
#STDERR.puts "File writer #{data.length}"
|
||||
else
|
||||
#STDERR.puts "Data is empty!"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def wget_downloader(url)
|
||||
@popen=Open3.popen3("wget -O - '#{url}'")
|
||||
@popen[0].close
|
||||
@popen[1]
|
||||
end
|
||||
|
||||
def check_hashes
|
||||
fail=false
|
||||
|
||||
@digests.each do |name, d|
|
||||
given=d[:hash].downcase
|
||||
computed=d[:digest].hexdigest.downcase
|
||||
if given!=computed
|
||||
fail=true
|
||||
STDERR.puts "Digest #{name} does not match. "<<
|
||||
"#{given}!=#{computed}"
|
||||
end
|
||||
end
|
||||
|
||||
exit(-1) if fail
|
||||
end
|
||||
|
||||
def download
|
||||
io=nil
|
||||
|
||||
begin
|
||||
case @from
|
||||
when '-'
|
||||
io=STDIN
|
||||
when /^https?:\/\//
|
||||
io=wget_downloader(@from)
|
||||
when /^file:\/\/(.*)$/
|
||||
name=$1
|
||||
io=open(name, 'r')
|
||||
else
|
||||
io=open(@from, 'r')
|
||||
end
|
||||
rescue # Errno::ENOENT
|
||||
STDERR.puts "File not found"
|
||||
exit(-1)
|
||||
end
|
||||
|
||||
header=io.read(BLOCK_SIZE)
|
||||
|
||||
if !header
|
||||
if @popen
|
||||
STDERR.puts @popen[2].read.strip.split("\n").last
|
||||
exit(-1)
|
||||
end
|
||||
end
|
||||
|
||||
open_output_file
|
||||
|
||||
set_compress(header)
|
||||
|
||||
download_stderr=""
|
||||
|
||||
process(header)
|
||||
|
||||
while(!io.eof?)
|
||||
if defined?(@popen)
|
||||
@popen[2].read_nonblock(BLOCK_SIZE, download_stderr)
|
||||
end
|
||||
data=io.read(BLOCK_SIZE)
|
||||
process(data)
|
||||
end
|
||||
|
||||
@finished=true
|
||||
|
||||
@compr_in.close_write
|
||||
|
||||
check_hashes
|
||||
|
||||
postprocess if @to!='-'
|
||||
end
|
||||
|
||||
def postprocess
|
||||
f=open(@to)
|
||||
header=f.read(BLOCK_SIZE)
|
||||
f.close
|
||||
|
||||
t=type(header)
|
||||
|
||||
if POSTPROCESS_TYPE.has_key?(t)
|
||||
if @to[0,1]=='/'
|
||||
to=@to
|
||||
else
|
||||
to=ENV['PWD']+'/'+@to
|
||||
end
|
||||
|
||||
tmp_file="#{to}.tmp"
|
||||
FileUtils.mv(to, tmp_file)
|
||||
|
||||
FileUtils.mkdir(to)
|
||||
|
||||
cmd=POSTPROCESS_TYPE[t]
|
||||
cmd.gsub!('#IN#', tmp_file)
|
||||
cmd.gsub!('#OUT#', @to)
|
||||
|
||||
system(cmd)
|
||||
status=$?
|
||||
|
||||
if !status.success?
|
||||
STDERR.puts "Error uncompressing archive"
|
||||
exit(-1)
|
||||
end
|
||||
|
||||
FileUtils.rm(tmp_file)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
options={}
|
||||
|
||||
OptionParser.new do |opts|
|
||||
opts.banner="Usage: download_helper <source> <destination>"
|
||||
|
||||
Stream::DIGEST.each do |name, value|
|
||||
opts.on("--#{name} HASH", "Check #{name} hash") do |v|
|
||||
options[name]=v
|
||||
end
|
||||
end
|
||||
end.parse!
|
||||
|
||||
if ARGV.length<2
|
||||
STDERR.puts "You need to specify source and destination"
|
||||
exit(-1)
|
||||
end
|
||||
|
||||
input=ARGV[0]
|
||||
output=ARGV[1]
|
||||
|
||||
|
||||
s=Stream.new(input, output, options)
|
||||
s.download
|
||||
|
191
src/datastore_mad/remotes/downloader.sh
Executable file
191
src/datastore_mad/remotes/downloader.sh
Executable file
@ -0,0 +1,191 @@
|
||||
#!/bin/bash
|
||||
|
||||
# -------------------------------------------------------------------------- #
|
||||
# Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) #
|
||||
# #
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
|
||||
# not use this file except in compliance with the License. You may obtain #
|
||||
# a copy of the License at #
|
||||
# #
|
||||
# http://www.apache.org/licenses/LICENSE-2.0 #
|
||||
# #
|
||||
# Unless required by applicable law or agreed to in writing, software #
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, #
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
|
||||
# See the License for the specific language governing permissions and #
|
||||
# limitations under the License. #
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
# Execute a command (first parameter) and use the first kb of stdout
|
||||
# to determine the file type
|
||||
function get_type
|
||||
{
|
||||
command=$1
|
||||
|
||||
( $command | head -n 1024 | file -b --mime-type - ) 2>/dev/null
|
||||
}
|
||||
|
||||
# Gets the command needed to decompress an stream.
|
||||
function get_decompressor
|
||||
{
|
||||
type=$1
|
||||
|
||||
case "$type" in
|
||||
"application/x-gzip")
|
||||
echo "gunzip -c -"
|
||||
;;
|
||||
"application/x-bzip2")
|
||||
echo "bunzip2 -c -"
|
||||
;;
|
||||
*)
|
||||
echo "cat"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Function called to decompress a stream. The first parameter is the command
|
||||
# used to decompress the stream. Second parameter is the output file or
|
||||
# - for stdout.
|
||||
function decompress
|
||||
{
|
||||
command="$1"
|
||||
to="$2"
|
||||
|
||||
if [ "$to" = "-" ]; then
|
||||
$command
|
||||
else
|
||||
$command > "$to"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function called to hash a stream. First parameter is the algorithm name.
|
||||
function hasher
|
||||
{
|
||||
algo=$1
|
||||
|
||||
if [ -n "$algo" ]; then
|
||||
openssl dgst -$algo | awk '{print $NF}' > $HASH_FILE
|
||||
else
|
||||
# Needs something consuming stdin or the pipe will break
|
||||
cat >/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
# Unarchives a tar or a zip a file to a directpry with the same name.
|
||||
function unarchive
|
||||
{
|
||||
TO="$1"
|
||||
|
||||
file_type=$(get_type "cat $TO")
|
||||
|
||||
tmp="$TO"
|
||||
|
||||
# Add full path if it is relative
|
||||
if [ ${tmp:0:1} != "/" ]; then
|
||||
tmp="$PWD/$tmp"
|
||||
fi
|
||||
|
||||
IN="$tmp.tmp"
|
||||
OUT="$tmp"
|
||||
|
||||
case "$file_type" in
|
||||
"application/x-tar")
|
||||
command="tar -xf $IN -C $OUT"
|
||||
;;
|
||||
"application/zip")
|
||||
command="unzip -d $OUT $IN"
|
||||
;;
|
||||
*)
|
||||
command=""
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -n "$command" ]; then
|
||||
mv "$OUT" "$IN"
|
||||
mkdir "$OUT"
|
||||
|
||||
$command
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
echo "Error uncompressing archive" >&2
|
||||
exit -1
|
||||
fi
|
||||
|
||||
rm "$IN"
|
||||
fi
|
||||
}
|
||||
|
||||
TEMP=`getopt -o m:s: -l md5:,sha1: -- "$@"`
|
||||
|
||||
if [ $? != 0 ] ; then
|
||||
echo "Arguments error"
|
||||
exit -1
|
||||
fi
|
||||
|
||||
eval set -- "$TEMP"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
-m|--md5)
|
||||
HASH_TYPE=md5
|
||||
HASH=$2
|
||||
shift 2
|
||||
;;
|
||||
-s|--sha1)
|
||||
HASH_TYPE=sha1
|
||||
HASH=$2
|
||||
shift 2
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
FROM="$1"
|
||||
TO="$2"
|
||||
|
||||
# File used by the hasher function to store the resulting hash
|
||||
export HASH_FILE="/tmp/downloader.hash.$$"
|
||||
|
||||
case "$FROM" in
|
||||
http://*|https://*)
|
||||
# -k so it does not check the certificate
|
||||
# -L to follow redirects
|
||||
# -sS to hide output except on failure
|
||||
command="curl -sS -k -L $FROM"
|
||||
;;
|
||||
*)
|
||||
command="cat $FROM"
|
||||
;;
|
||||
esac
|
||||
|
||||
file_type=$(get_type "$command")
|
||||
decompressor=$(get_decompressor "$file_type")
|
||||
|
||||
$command | tee >( decompress "$decompressor" "$TO" ) \
|
||||
>( hasher $HASH_TYPE ) >/dev/null
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
echo "Error copying" >&2
|
||||
exit -1
|
||||
fi
|
||||
|
||||
if [ -n "$HASH_TYPE" ]; then
|
||||
HASH_RESULT=$( cat $HASH_FILE)
|
||||
rm $HASH_FILE
|
||||
if [ "$HASH_RESULT" != "$HASH" ]; then
|
||||
echo "Hash does not match" >&2
|
||||
exit -1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Unarchive only if the destination is filesystem
|
||||
if [ "$TO" != "-" ]; then
|
||||
unarchive "$TO"
|
||||
fi
|
||||
|
@ -78,7 +78,7 @@ if [ -n "$SHA1" ]; then
|
||||
HASHES="$HASHES --sha1 $SHA1"
|
||||
fi
|
||||
|
||||
COPY_COMMAND="$UTILS_PATH/downloader.rb $HASHES $SRC $DST"
|
||||
COPY_COMMAND="$UTILS_PATH/downloader.sh $HASHES $SRC $DST"
|
||||
|
||||
# ------------ Copy the image to the repository -------------
|
||||
|
||||
|
@ -101,7 +101,7 @@ if [ -n "$SHA1" ]; then
|
||||
HASHES="$HASHES --sha1 $SHA1"
|
||||
fi
|
||||
|
||||
COPY_COMMAND="$UTILS_PATH/downloader.rb $HASHES $SRC -"
|
||||
COPY_COMMAND="$UTILS_PATH/downloader.sh $HASHES $SRC -"
|
||||
|
||||
case $SRC in
|
||||
http://*)
|
||||
|
@ -90,7 +90,7 @@ if [ -n "$SHA1" ]; then
|
||||
HASHES="$HASHES --sha1 $SHA1"
|
||||
fi
|
||||
|
||||
COPY_COMMAND="$UTILS_PATH/downloader.rb $HASHES $SRC -"
|
||||
COPY_COMMAND="$UTILS_PATH/downloader.sh $HASHES $SRC -"
|
||||
|
||||
case $SRC in
|
||||
http://*)
|
||||
|
@ -78,7 +78,7 @@ if [ -n "$SHA1" ]; then
|
||||
HASHES="$HASHES --sha1 $SHA1"
|
||||
fi
|
||||
|
||||
COPY_COMMAND="$UTILS_PATH/downloader.rb $HASHES $SRC $DST"
|
||||
COPY_COMMAND="$UTILS_PATH/downloader.sh $HASHES $SRC $DST"
|
||||
|
||||
# ------------ Copy the image to the repository -------------
|
||||
|
||||
|
@ -92,7 +92,16 @@ int ImageManager::acquire_image(Image *img, string& error)
|
||||
{
|
||||
case Image::READY:
|
||||
img->inc_running();
|
||||
img->set_state(Image::USED);
|
||||
|
||||
if ( img->isPersistent() )
|
||||
{
|
||||
img->set_state(Image::USED_PERS);
|
||||
}
|
||||
else
|
||||
{
|
||||
img->set_state(Image::USED);
|
||||
}
|
||||
|
||||
ipool->update(img);
|
||||
break;
|
||||
|
||||
@ -641,15 +650,24 @@ int ImageManager::stat_image(Template* img_tmpl,
|
||||
break;
|
||||
|
||||
case Image::DATABLOCK:
|
||||
img_tmpl->get("SIZE", res);
|
||||
img_tmpl->get("PATH", res);
|
||||
|
||||
if (res.empty())
|
||||
if (res.empty())//no PATH
|
||||
{
|
||||
res = "SIZE attribute is mandatory for DATABLOCK.";
|
||||
return -1;
|
||||
img_tmpl->get("SIZE", res);
|
||||
|
||||
if (res.empty())
|
||||
{
|
||||
res = "Either SIZE or PATH are mandatory for DATABLOCK.";
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
img_data << "<IMAGE><PATH>" << res << "</PATH></IMAGE>";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
add_request(&sr);
|
||||
|
@ -89,16 +89,14 @@ module OpenNebula
|
||||
if NOKOGIRI
|
||||
element=@xml.xpath(key.to_s)
|
||||
|
||||
if element.size == 0
|
||||
return nil
|
||||
end
|
||||
return nil if element.size == 0
|
||||
else
|
||||
element=@xml.elements[key.to_s]
|
||||
|
||||
return "" if element && !element.has_text?
|
||||
end
|
||||
|
||||
if element
|
||||
element.text
|
||||
end
|
||||
element.text if element
|
||||
end
|
||||
|
||||
# Delete an element from the xml
|
||||
|
@ -28,6 +28,87 @@ module Migrator
|
||||
|
||||
def up
|
||||
|
||||
oneadmin_row = nil
|
||||
@db.fetch("SELECT * FROM user_pool WHERE oid = 0") do |row|
|
||||
oneadmin_row = row
|
||||
end
|
||||
|
||||
if oneadmin_row[:gid] != 0
|
||||
|
||||
puts " > Oneadmin user will be moved to the oneadmin group"
|
||||
|
||||
# Change user group
|
||||
|
||||
doc = Document.new(oneadmin_row[:body])
|
||||
|
||||
doc.root.each_element("GID") { |e|
|
||||
e.text = "0"
|
||||
}
|
||||
|
||||
doc.root.each_element("GNAME") { |e|
|
||||
e.text = "oneadmin"
|
||||
}
|
||||
|
||||
@db[:user_pool].filter(:oid=>0).delete
|
||||
|
||||
@db[:user_pool].insert(
|
||||
:oid => oneadmin_row[:oid],
|
||||
:name => oneadmin_row[:name],
|
||||
:body => doc.root.to_s,
|
||||
:uid => oneadmin_row[:oid],
|
||||
:gid => 0,
|
||||
:owner_u => oneadmin_row[:owner_u],
|
||||
:group_u => oneadmin_row[:group_u],
|
||||
:other_u => oneadmin_row[:other_u])
|
||||
|
||||
# Remove oneadmin's id from previous group
|
||||
|
||||
group_row = nil
|
||||
|
||||
@db.fetch("SELECT * FROM group_pool WHERE oid = #{oneadmin_row[:gid]}") do |row|
|
||||
group_row = row
|
||||
end
|
||||
|
||||
doc = Document.new(group_row[:body])
|
||||
|
||||
doc.root.delete_element("USERS/ID[.=0]")
|
||||
|
||||
@db[:group_pool].filter(:oid=>group_row[:oid]).delete
|
||||
|
||||
@db[:group_pool].insert(
|
||||
:oid => group_row[:oid],
|
||||
:name => group_row[:name],
|
||||
:body => doc.root.to_s,
|
||||
:uid => group_row[:oid],
|
||||
:gid => group_row[:gid],
|
||||
:owner_u => group_row[:owner_u],
|
||||
:group_u => group_row[:group_u],
|
||||
:other_u => group_row[:other_u])
|
||||
|
||||
# Add oneadmin's id to oneadmin group
|
||||
|
||||
@db.fetch("SELECT * FROM group_pool WHERE oid = 0") do |row|
|
||||
group_row = row
|
||||
end
|
||||
|
||||
doc = Document.new(group_row[:body])
|
||||
|
||||
doc.root.get_elements("USERS")[0].add_element("ID").text = "0"
|
||||
|
||||
@db[:group_pool].filter(:oid=>group_row[:oid]).delete
|
||||
|
||||
@db[:group_pool].insert(
|
||||
:oid => group_row[:oid],
|
||||
:name => group_row[:name],
|
||||
:body => doc.root.to_s,
|
||||
:uid => group_row[:oid],
|
||||
:gid => group_row[:gid],
|
||||
:owner_u => group_row[:owner_u],
|
||||
:group_u => group_row[:group_u],
|
||||
:other_u => group_row[:other_u])
|
||||
end
|
||||
|
||||
|
||||
@db.run "ALTER TABLE datastore_pool RENAME TO old_datastore_pool;"
|
||||
@db.run "CREATE TABLE datastore_pool (oid INTEGER PRIMARY KEY, name VARCHAR(128), body TEXT, uid INTEGER, gid INTEGER, owner_u INTEGER, group_u INTEGER, other_u INTEGER, UNIQUE(name));"
|
||||
|
||||
|
@ -115,6 +115,41 @@ PoolObjectSQL * RequestManagerChown::get_and_quota(
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
int RequestManagerChown::check_name_unique(int oid, int noid, string& error_str)
|
||||
{
|
||||
PoolObjectSQL * object;
|
||||
string name;
|
||||
int obj_oid;
|
||||
ostringstream oss;
|
||||
|
||||
object = pool->get(oid, true);
|
||||
|
||||
name = object->get_name();
|
||||
|
||||
object->unlock();
|
||||
|
||||
object = get(name, noid, true);
|
||||
|
||||
if ( object != 0 )
|
||||
{
|
||||
obj_oid = object->get_oid();
|
||||
object->unlock();
|
||||
|
||||
oss << PoolObjectSQL::type_to_str(PoolObjectSQL::USER)
|
||||
<< " [" << noid << "] already owns "
|
||||
<< PoolObjectSQL::type_to_str(auth_object) << " ["
|
||||
<< obj_oid << "] with NAME " << name;
|
||||
|
||||
error_str = oss.str();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void RequestManagerChown::request_execute(xmlrpc_c::paramList const& paramList,
|
||||
RequestAttributes& att)
|
||||
{
|
||||
@ -123,6 +158,7 @@ void RequestManagerChown::request_execute(xmlrpc_c::paramList const& paramList,
|
||||
int ngid = xmlrpc_c::value_int(paramList.getInt(3));
|
||||
|
||||
int rc;
|
||||
string error_str;
|
||||
|
||||
string oname;
|
||||
string nuname;
|
||||
@ -194,6 +230,17 @@ void RequestManagerChown::request_execute(xmlrpc_c::paramList const& paramList,
|
||||
}
|
||||
}
|
||||
|
||||
// --------------- Check name uniqueness -----------------------------------
|
||||
|
||||
if ( noid != -1 )
|
||||
{
|
||||
if ( check_name_unique(oid, noid, error_str) != 0 )
|
||||
{
|
||||
failure_response(INTERNAL, request_error(error_str, ""), att);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// --------------- Update the object and check quotas ----------------------
|
||||
|
||||
if ( auth_object == PoolObjectSQL::VM ||
|
||||
@ -286,6 +333,21 @@ void UserChown::request_execute(xmlrpc_c::paramList const& paramList,
|
||||
return;
|
||||
}
|
||||
|
||||
if ( oid == UserPool::ONEADMIN_ID )
|
||||
{
|
||||
ostringstream oss;
|
||||
|
||||
oss << PoolObjectSQL::type_to_str(PoolObjectSQL::USER)
|
||||
<< " [" << UserPool::ONEADMIN_ID << "] " << UserPool::oneadmin_name
|
||||
<< " cannot be moved outside of the "
|
||||
<< PoolObjectSQL::type_to_str(PoolObjectSQL::GROUP)
|
||||
<< " [" << GroupPool::ONEADMIN_ID << "] "
|
||||
<< GroupPool::ONEADMIN_NAME;
|
||||
|
||||
failure_response(INTERNAL, request_error(oss.str(), ""), att);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( att.uid != 0 )
|
||||
{
|
||||
AuthRequest ar(att.uid, att.gid);
|
||||
|
@ -45,7 +45,8 @@ module OpenNebulaJSON
|
||||
end
|
||||
|
||||
rc = case action_hash['perform']
|
||||
when "chown" then self.chown(action_hash['params'])
|
||||
when "chown" then self.chown(action_hash['params'])
|
||||
when "set_quota" then self.set_quota(action_hash['params'])
|
||||
else
|
||||
error_msg = "#{action_hash['perform']} action not " <<
|
||||
" available for this resource"
|
||||
@ -56,5 +57,11 @@ module OpenNebulaJSON
|
||||
def chown(params=Hash.new)
|
||||
super(params['owner_id'].to_i)
|
||||
end
|
||||
|
||||
def set_quota(params=Hash.new)
|
||||
quota_json = params['quotas']
|
||||
quota_template = template_to_str(quota_json)
|
||||
super(quota_template)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -58,6 +58,7 @@ module OpenNebulaJSON
|
||||
when "chown" then self.chown(action_hash['params'])
|
||||
when "chmod" then self.chmod_octet(action_hash['params'])
|
||||
when "chtype" then self.chtype(action_hash['params'])
|
||||
when "clone" then self.clone(action_hash['params'])
|
||||
else
|
||||
error_msg = "#{action_hash['perform']} action not " <<
|
||||
" available for this resource"
|
||||
@ -84,5 +85,9 @@ module OpenNebulaJSON
|
||||
def chtype(params=Hash.new)
|
||||
super(params['type'])
|
||||
end
|
||||
|
||||
def clone(params=Hash.new)
|
||||
super(params['name'])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -42,6 +42,7 @@ module OpenNebulaJSON
|
||||
when "chgrp" then self.chgrp(action_hash['params'])
|
||||
when "chauth" then self.chauth(action_hash['params'])
|
||||
when "update" then self.update(action_hash['params'])
|
||||
when "set_quota" then self.set_quota(action_hash['params'])
|
||||
when "addgroup" then self.addgroup(action_hash['params'])
|
||||
when "delgroup" then self.delgroup(action_hash['params'])
|
||||
else
|
||||
@ -67,6 +68,12 @@ module OpenNebulaJSON
|
||||
super(params['template_raw'])
|
||||
end
|
||||
|
||||
def set_quota(params=Hash.new)
|
||||
quota_json = params['quotas']
|
||||
quota_template = template_to_str(quota_json)
|
||||
super(quota_template)
|
||||
end
|
||||
|
||||
def addgroup(params=Hash.new)
|
||||
super(params['group_id'].to_i)
|
||||
end
|
||||
|
@ -663,4 +663,12 @@ ul.action_list li a:hover{
|
||||
font-family: serif;
|
||||
text-align:center;
|
||||
vertical-align:middle;
|
||||
}
|
||||
|
||||
.quota_edit_icon:hover, .quota_remove_icon:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
div.current_quotas ul{
|
||||
list-style: none;
|
||||
}
|
@ -693,6 +693,13 @@ var OpenNebula = {
|
||||
},
|
||||
"list": function(params){
|
||||
OpenNebula.Action.list(params,OpenNebula.Group.resource);
|
||||
},
|
||||
"set_quota" : function(params){
|
||||
var action_obj = { quotas : params.data.extra_param };
|
||||
OpenNebula.Action.simple_action(params,OpenNebula.Group.resource,"set_quota",action_obj);
|
||||
},
|
||||
"show" : function(params){
|
||||
OpenNebula.Action.show(params,OpenNebula.Group.resource);
|
||||
}
|
||||
},
|
||||
|
||||
@ -736,6 +743,11 @@ var OpenNebula = {
|
||||
"fetch_template" : function(params){
|
||||
OpenNebula.Action.show(params,OpenNebula.User.resource,"template");
|
||||
},
|
||||
"set_quota" : function(params){
|
||||
var action_obj = { quotas : params.data.extra_param };
|
||||
OpenNebula.Action.simple_action(params,OpenNebula.User.resource,"set_quota",action_obj);
|
||||
},
|
||||
|
||||
// "addgroup" : function(params){
|
||||
// var action_obj = {"group_id": params.data.extra_param };
|
||||
// OpenNebula.Action.simple_action(params,OpenNebula.User.resource,
|
||||
@ -804,6 +816,11 @@ var OpenNebula = {
|
||||
OpenNebula.Image.resource,
|
||||
"chtype",
|
||||
action_obj);
|
||||
},
|
||||
"clone" : function(params) {
|
||||
var name = params.data.extra_param ? params.data.extra_param : "";
|
||||
var action_obj = { "name" : name };
|
||||
OpenNebula.Action.simple_action(params,OpenNebula.Image.resource, "clone", action_obj);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
var groups_select="";
|
||||
var dataTable_groups;
|
||||
var $create_group_dialog;
|
||||
var $group_quotas_dialog;
|
||||
|
||||
var groups_tab_content = '\
|
||||
<h2>'+tr("Groups")+'</h2>\
|
||||
@ -59,6 +60,69 @@ var create_group_tmpl =
|
||||
</fieldset>\
|
||||
</form>';
|
||||
|
||||
var group_quotas_tmpl = '<form id="group_quotas_form" action="">\
|
||||
<fieldset>\
|
||||
<div>'+tr("Please add/edit/remove quotas and click on the apply changes button. Note that if several items are selected, changes will be applied to each of them")+'.</div>\
|
||||
<div>'+tr("Add quota")+':</div>\
|
||||
<div id="quota_types">\
|
||||
<label>'+tr("Quota type")+':</label>\
|
||||
<input type="radio" name="quota_type" value="vm">'+tr("Virtual Machine")+'</input>\
|
||||
<input type="radio" name="quota_type" value="datastore">'+tr("Datastore")+'</input>\
|
||||
<input type="radio" name="quota_type" value="image">'+tr("Image")+'</input>\
|
||||
<input type="radio" name="quota_type" value="network">'+tr("Network")+'</input>\
|
||||
</div>\
|
||||
<div id="vm_quota">\
|
||||
<label>'+tr("Max VMs")+':</label>\
|
||||
<input type="text" name="VMS"></input><br />\
|
||||
<label>'+tr("Max Memory (MB)")+':</label>\
|
||||
<input type="text" name="MEMORY"></input><br />\
|
||||
<label>'+tr("Max CPU")+':</label>\
|
||||
<input type="text" name="CPU"></input>\
|
||||
</div>\
|
||||
<div id="datastore_quota">\
|
||||
<label>'+tr("Datastore")+'</label>\
|
||||
<select name="ID"></select><br />\
|
||||
<label>'+tr("Max size (MB)")+':</label>\
|
||||
<input type="text" name="SIZE"></input><br />\
|
||||
<label>'+tr("Max images")+':</label>\
|
||||
<input type="text" name="IMAGES"></input>\
|
||||
</div>\
|
||||
<div id="image_quota">\
|
||||
<label>'+tr("Image")+'</label>\
|
||||
<select name="ID"></select><br />\
|
||||
<label>'+tr("Max RVMs")+'</label>\
|
||||
<input type="text" name="RVMS"></input>\
|
||||
</div>\
|
||||
<div id="network_quota">\
|
||||
<label>'+tr("Network")+'</label>\
|
||||
<select name="ID"></select><br />\
|
||||
<label>'+tr("Max leases")+'</label>\
|
||||
<input type="text" name="LEASES"></input>\
|
||||
</div>\
|
||||
<button style="width:100px!important;" class="add_remove_button add_button" id="add_quota_button" value="add_quota">'+tr("Add/edit quota")+'</button>\
|
||||
<div class="clear"></div>\
|
||||
<div class="clear"></div>\
|
||||
<div>'+tr("Current quotas")+':</div>\
|
||||
<div class="current_quotas">\
|
||||
<label>'+tr("VM quota")+':</label><br />\
|
||||
<ul id="quotas_ul_vm">\
|
||||
</ul>\
|
||||
<label>'+tr("Datastore quotas")+':</label><br />\
|
||||
<ul id="quotas_ul_datastore">\
|
||||
</ul>\
|
||||
<label>'+tr("Image quotas")+':</label><br />\
|
||||
<ul id="quotas_ul_image">\
|
||||
</ul>\
|
||||
<label>'+tr("Network quotas")+':</label><br />\
|
||||
<ul id="quotas_ul_network">\
|
||||
</ul>\
|
||||
</div>\
|
||||
<div class="form_buttons">\
|
||||
<button class="button" type="submit" value="Group.set_quota">'+tr("Apply changes")+'</button>\
|
||||
</div>\
|
||||
</fieldset>\
|
||||
</form>';
|
||||
|
||||
|
||||
var group_actions = {
|
||||
"Group.create" : {
|
||||
@ -119,6 +183,34 @@ var group_actions = {
|
||||
// error : onError,
|
||||
// notify:true
|
||||
// },
|
||||
|
||||
"Group.fetch_quotas" : {
|
||||
type: "single",
|
||||
call: OpenNebula.Group.show,
|
||||
callback: function (request,response) {
|
||||
var parsed = parseQuotas(response.GROUP);
|
||||
$('ul#quotas_ul_vm',$group_quotas_dialog).html(parsed.VM)
|
||||
$('ul#quotas_ul_datastore',$group_quotas_dialog).html(parsed.DATASTORE)
|
||||
$('ul#quotas_ul_image',$group_quotas_dialog).html(parsed.IMAGE)
|
||||
$('ul#quotas_ul_network',$group_quotas_dialog).html(parsed.NETWORK)
|
||||
},
|
||||
error: onError
|
||||
},
|
||||
|
||||
"Group.quotas_dialog" : {
|
||||
type: "custom",
|
||||
call: popUpGroupQuotasDialog
|
||||
},
|
||||
|
||||
"Group.set_quota" : {
|
||||
type: "multiple",
|
||||
call: OpenNebula.Group.set_quota,
|
||||
elements: groupElements,
|
||||
callback: function() {
|
||||
notifyMessage(tr("Quotas updated correctly"));
|
||||
},
|
||||
error: onError
|
||||
},
|
||||
"Group.help" : {
|
||||
type: "custom",
|
||||
call: function() {
|
||||
@ -145,7 +237,10 @@ var group_buttons = {
|
||||
// tip: "Select the new group owner:",
|
||||
// condition : True
|
||||
// },
|
||||
|
||||
"Group.quotas_dialog" : {
|
||||
type : "action",
|
||||
text : tr("Update quotas")
|
||||
},
|
||||
"Group.delete" : {
|
||||
type: "confirm",
|
||||
text: tr("Delete")
|
||||
@ -276,6 +371,19 @@ function popUpCreateGroupDialog(){
|
||||
return false;
|
||||
}
|
||||
|
||||
function setupGroupQuotasDialog(){
|
||||
dialogs_context.append('<div title="'+tr("Group quotas")+'" id="group_quotas_dialog"></div>');
|
||||
$group_quotas_dialog = $('#group_quotas_dialog',dialogs_context);
|
||||
var dialog = $group_quotas_dialog;
|
||||
dialog.html(group_quotas_tmpl);
|
||||
|
||||
setupQuotasDialog(dialog);
|
||||
}
|
||||
|
||||
function popUpGroupQuotasDialog(){
|
||||
popUpQuotasDialog($group_quotas_dialog, 'Group', groupElements())
|
||||
}
|
||||
|
||||
//Prepares the autorefresh
|
||||
function setGroupAutorefresh(){
|
||||
setInterval(function(){
|
||||
@ -312,6 +420,7 @@ $(document).ready(function(){
|
||||
|
||||
Sunstone.runAction("Group.list");
|
||||
setupCreateGroupDialog();
|
||||
setupGroupQuotasDialog();
|
||||
setGroupAutorefresh();
|
||||
|
||||
initCheckAllBoxes(dataTable_groups);
|
||||
|
@ -436,6 +436,16 @@ var image_actions = {
|
||||
error: onError,
|
||||
notify: true
|
||||
},
|
||||
"Image.clone_dialog" : {
|
||||
type: "custom",
|
||||
call: popUpImageCloneDialog
|
||||
},
|
||||
"Image.clone" : {
|
||||
type: "single",
|
||||
call: OpenNebula.Image.clone,
|
||||
error: onError,
|
||||
notify: true
|
||||
},
|
||||
"Image.help" : {
|
||||
type: "custom",
|
||||
call: function() {
|
||||
@ -496,6 +506,10 @@ var image_buttons = {
|
||||
}
|
||||
}
|
||||
},
|
||||
"Image.clone_dialog" : {
|
||||
type: "action",
|
||||
text: tr("Clone"),
|
||||
},
|
||||
"Image.delete" : {
|
||||
type: "confirm",
|
||||
text: tr("Delete")
|
||||
@ -1136,6 +1150,78 @@ function setupImageActionCheckboxes(){
|
||||
|
||||
}
|
||||
|
||||
function setupImageCloneDialog(){
|
||||
//Append to DOM
|
||||
dialogs_context.append('<div id="image_clone_dialog" title="'+tr("Clone an image")+'"></div>');
|
||||
var dialog = $('#image_clone_dialog',dialogs_context);
|
||||
|
||||
//Put HTML in place
|
||||
|
||||
var html = '<form><fieldset>\
|
||||
<div class="clone_one">'+tr("Choose a new name for the image")+':</div>\
|
||||
<div class="clone_several">'+tr("Several image are selected, please choose prefix to name the new copies")+':</div>\
|
||||
<br />\
|
||||
<label class="clone_one">'+tr("Name")+':</label>\
|
||||
<label class="clone_several">'+tr("Prefix")+':</label>\
|
||||
<input type="text" name="name"></input>\
|
||||
<div class="form_buttons">\
|
||||
<button class="button" id="image_clone_button" value="Image.clone">\
|
||||
'+tr("Clone")+'\
|
||||
</button>\
|
||||
</div></fieldset></form>\
|
||||
';
|
||||
|
||||
dialog.html(html);
|
||||
|
||||
//Convert into jQuery
|
||||
dialog.dialog({
|
||||
autoOpen:false,
|
||||
width:375,
|
||||
modal:true,
|
||||
resizable:false,
|
||||
});
|
||||
|
||||
$('button',dialog).button();
|
||||
|
||||
$('form',dialog).submit(function(){
|
||||
var name = $('input', this).val();
|
||||
var sel_elems = imageElements();
|
||||
if (!name || !sel_elems.length)
|
||||
notifyError('A name or prefix is needed!');
|
||||
if (sel_elems.length > 1){
|
||||
for (var i=0; i< sel_elems.length; i++)
|
||||
Sunstone.runAction('Image.clone',
|
||||
sel_elems[i],
|
||||
name+getImageName(sel_elems[i]));
|
||||
} else {
|
||||
Sunstone.runAction('Image.clone',sel_elems[0],name)
|
||||
};
|
||||
dialog.dialog('close');
|
||||
setTimeout(function(){
|
||||
Sunstone.runAction('Image.refresh');
|
||||
}, 1500);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
function popUpImageCloneDialog(){
|
||||
var dialog = $('#image_clone_dialog');
|
||||
var sel_elems = imageElements();
|
||||
//show different text depending on how many elements are selected
|
||||
if (sel_elems.length > 1){
|
||||
$('.clone_one',dialog).hide();
|
||||
$('.clone_several',dialog).show();
|
||||
$('input',dialog).val('Copy of ');
|
||||
}
|
||||
else {
|
||||
$('.clone_one',dialog).show();
|
||||
$('.clone_several',dialog).hide();
|
||||
$('input',dialog).val('Copy of '+getImageName(sel_elems[0]));
|
||||
};
|
||||
|
||||
$(dialog).dialog('open');
|
||||
}
|
||||
|
||||
//The DOM is ready at this point
|
||||
$(document).ready(function(){
|
||||
|
||||
@ -1172,6 +1258,7 @@ $(document).ready(function(){
|
||||
setupImageTemplateUpdateDialog();
|
||||
setupTips($create_image_dialog);
|
||||
setupImageActionCheckboxes();
|
||||
setupImageCloneDialog();
|
||||
setImageAutorefresh();
|
||||
|
||||
initCheckAllBoxes(dataTable_images);
|
||||
|
@ -91,16 +91,18 @@ var market_actions = {
|
||||
document.getElementById("img_name").value = response['name'];
|
||||
document.getElementById("img_path").value = response['links']['download']['href'];
|
||||
|
||||
$("#custom_var_image_box",$create_image_dialog).empty();
|
||||
|
||||
var md5 = response['files'][0]['checksum']['md5']
|
||||
if ( md5 ) {
|
||||
option = '<option value=\''+md5+'\' name="MD5">MD5='+md5+'</option>';
|
||||
$("#custom_var_image_box").append(option);
|
||||
$("#custom_var_image_box",$create_image_dialog).append(option);
|
||||
}
|
||||
|
||||
var sha1 = response['files'][0]['checksum']['sha1']
|
||||
if ( sha1 ) {
|
||||
option = '<option value=\''+sha1+'\' name="SHA1">SHA1='+sha1+'</option>';
|
||||
$("#custom_var_image_box").append(option);
|
||||
$("#custom_var_image_box",$create_image_dialog).append(option);
|
||||
}
|
||||
|
||||
popUpCreateImageDialog();
|
||||
@ -237,6 +239,13 @@ function infoListenerMarket(dataTable){
|
||||
var id = aData["_id"]["$oid"];
|
||||
if (!id) return true;
|
||||
|
||||
var count = $('tbody .check_item:checked', dataTable).length;
|
||||
|
||||
if (e.ctrlKey || count >= 1){
|
||||
$('.check_item',this).trigger('click');
|
||||
return false;
|
||||
}
|
||||
|
||||
popDialogLoading();
|
||||
|
||||
$.ajax({
|
||||
@ -263,11 +272,9 @@ function infoListenerMarket(dataTable){
|
||||
|
||||
function onlyOneCheckboxListener(dataTable) {
|
||||
$('tbody input.check_item', dataTable).live("change", function(){
|
||||
var checked = $('input.check_item:checked', $('tr', dataTable));
|
||||
var self = this;
|
||||
checked.each(function(){
|
||||
if(this!=self) this.checked = ''
|
||||
})
|
||||
var checked = $(this).is(':checked');
|
||||
$('input.check_item:checked', dataTable).removeAttr('checked');
|
||||
$(this).attr('checked', checked);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
var dataTable_users;
|
||||
var users_select="";
|
||||
var $create_user_dialog;
|
||||
var $user_quotas_dialog;
|
||||
var $update_pw_dialog;
|
||||
|
||||
var users_tab_content = '\
|
||||
@ -100,6 +101,69 @@ var update_pw_tmpl = '<form id="update_user_pw_form" action="">\
|
||||
</fieldset>\
|
||||
</form>';
|
||||
|
||||
var user_quotas_tmpl = '<form id="user_quotas_form" action="">\
|
||||
<fieldset>\
|
||||
<div>'+tr("Please add/edit/remove quotas and click on the apply changes button. Note that if several items are selected, changes will be applied to each of them")+'.</div>\
|
||||
<div>'+tr("Add quota")+':</div>\
|
||||
<div id="quota_types">\
|
||||
<label>'+tr("Quota type")+':</label>\
|
||||
<input type="radio" name="quota_type" value="vm">'+tr("Virtual Machine")+'</input>\
|
||||
<input type="radio" name="quota_type" value="datastore">'+tr("Datastore")+'</input>\
|
||||
<input type="radio" name="quota_type" value="image">'+tr("Image")+'</input>\
|
||||
<input type="radio" name="quota_type" value="network">'+tr("Network")+'</input>\
|
||||
</div>\
|
||||
<div id="vm_quota">\
|
||||
<label>'+tr("Max VMs")+':</label>\
|
||||
<input type="text" name="VMS"></input><br />\
|
||||
<label>'+tr("Max Memory (MB)")+':</label>\
|
||||
<input type="text" name="MEMORY"></input><br />\
|
||||
<label>'+tr("Max CPU")+':</label>\
|
||||
<input type="text" name="CPU"></input>\
|
||||
</div>\
|
||||
<div id="datastore_quota">\
|
||||
<label>'+tr("Datastore")+'</label>\
|
||||
<select name="ID"></select><br />\
|
||||
<label>'+tr("Max size (MB)")+':</label>\
|
||||
<input type="text" name="SIZE"></input><br />\
|
||||
<label>'+tr("Max images")+':</label>\
|
||||
<input type="text" name="IMAGES"></input>\
|
||||
</div>\
|
||||
<div id="image_quota">\
|
||||
<label>'+tr("Image")+'</label>\
|
||||
<select name="ID"></select><br />\
|
||||
<label>'+tr("Max RVMs")+'</label>\
|
||||
<input type="text" name="RVMS"></input>\
|
||||
</div>\
|
||||
<div id="network_quota">\
|
||||
<label>'+tr("Network")+'</label>\
|
||||
<select name="ID"></select><br />\
|
||||
<label>'+tr("Max leases")+'</label>\
|
||||
<input type="text" name="LEASES"></input>\
|
||||
</div>\
|
||||
<button style="width:100px!important;" class="add_remove_button add_button" id="add_quota_button" value="add_quota">'+tr("Add/edit quota")+'</button>\
|
||||
<div class="clear"></div>\
|
||||
<div class="clear"></div>\
|
||||
<div>'+tr("Current quotas")+':</div>\
|
||||
<div class="current_quotas">\
|
||||
<label>'+tr("VM quota")+':</label><br />\
|
||||
<ul id="quotas_ul_vm">\
|
||||
</ul>\
|
||||
<label>'+tr("Datastore quotas")+':</label><br />\
|
||||
<ul id="quotas_ul_datastore">\
|
||||
</ul>\
|
||||
<label>'+tr("Image quotas")+':</label><br />\
|
||||
<ul id="quotas_ul_image">\
|
||||
</ul>\
|
||||
<label>'+tr("Network quotas")+':</label><br />\
|
||||
<ul id="quotas_ul_network">\
|
||||
</ul>\
|
||||
</div>\
|
||||
<div class="form_buttons">\
|
||||
<button class="button" type="submit" value="User.set_quota">'+tr("Apply changes")+'</button>\
|
||||
</div>\
|
||||
</fieldset>\
|
||||
</form>';
|
||||
|
||||
|
||||
var user_actions = {
|
||||
"User.create" : {
|
||||
@ -254,6 +318,34 @@ var user_actions = {
|
||||
error: onError
|
||||
},
|
||||
|
||||
"User.fetch_quotas" : {
|
||||
type: "single",
|
||||
call: OpenNebula.User.show,
|
||||
callback: function (request,response) {
|
||||
var parsed = parseQuotas(response.USER);
|
||||
$('ul#quotas_ul_vm',$user_quotas_dialog).html(parsed.VM)
|
||||
$('ul#quotas_ul_datastore',$user_quotas_dialog).html(parsed.DATASTORE)
|
||||
$('ul#quotas_ul_image',$user_quotas_dialog).html(parsed.IMAGE)
|
||||
$('ul#quotas_ul_network',$user_quotas_dialog).html(parsed.NETWORK)
|
||||
},
|
||||
error: onError
|
||||
},
|
||||
|
||||
"User.quotas_dialog" : {
|
||||
type: "custom",
|
||||
call: popUpUserQuotasDialog
|
||||
},
|
||||
|
||||
"User.set_quota" : {
|
||||
type: "multiple",
|
||||
call: OpenNebula.User.set_quota,
|
||||
elements: userElements,
|
||||
callback: function() {
|
||||
notifyMessage(tr("Quotas updated correctly"));
|
||||
},
|
||||
error: onError
|
||||
},
|
||||
|
||||
"User.help" : {
|
||||
type: "custom",
|
||||
call: function() {
|
||||
@ -283,6 +375,10 @@ var user_buttons = {
|
||||
type : "action",
|
||||
text : tr("Change password"),
|
||||
},
|
||||
"User.quotas_dialog" : {
|
||||
type : "action",
|
||||
text : tr("Update quotas")
|
||||
},
|
||||
"User.chgrp" : {
|
||||
type: "confirm_with_select",
|
||||
text: tr("Change group"),
|
||||
@ -331,6 +427,10 @@ var user_info_panel = {
|
||||
title: tr("User information"),
|
||||
content:""
|
||||
},
|
||||
"user_quotas_tab" : {
|
||||
title: tr("User quotas"),
|
||||
content:""
|
||||
},
|
||||
};
|
||||
|
||||
var users_tab = {
|
||||
@ -473,7 +573,25 @@ function updateUserInfo(request,user){
|
||||
'</table>'
|
||||
};
|
||||
|
||||
var quotas_tab = {
|
||||
title : tr("User quotas"),
|
||||
content : '\
|
||||
<table class="info_table">\
|
||||
<tbody>'+prettyPrintJSON(user_info.DATASTORE_QUOTA)+'</tbody>\
|
||||
</table>\
|
||||
<table class="info_table">\
|
||||
<tbody>'+prettyPrintJSON(user_info.VM_QUOTA)+'</tbody>\
|
||||
</table>\
|
||||
<table class="info_table">\
|
||||
<tbody>'+prettyPrintJSON(user_info.IMAGE_QUOTA)+'</tbody>\
|
||||
</table>\
|
||||
<table class="info_table">\
|
||||
<tbody>'+prettyPrintJSON(user_info.NETWORK_QUOTA)+'</tbody>\
|
||||
</table>'
|
||||
};
|
||||
|
||||
Sunstone.updateInfoPanelTab("user_info_panel","user_info_tab",info_tab);
|
||||
Sunstone.updateInfoPanelTab("user_info_panel","user_quotas_tab",quotas_tab);
|
||||
Sunstone.popUpInfoPanel("user_info_panel");
|
||||
};
|
||||
|
||||
@ -554,8 +672,22 @@ function setupUpdatePasswordDialog(){
|
||||
});
|
||||
};
|
||||
|
||||
function setupUserQuotasDialog(){
|
||||
dialogs_context.append('<div title="'+tr("User quotas")+'" id="user_quotas_dialog"></div>');
|
||||
$user_quotas_dialog = $('#user_quotas_dialog',dialogs_context);
|
||||
var dialog = $user_quotas_dialog;
|
||||
dialog.html(user_quotas_tmpl);
|
||||
|
||||
setupQuotasDialog(dialog);
|
||||
}
|
||||
|
||||
function popUpUserQuotasDialog(){
|
||||
popUpQuotasDialog($user_quotas_dialog, 'User', userElements())
|
||||
}
|
||||
|
||||
function popUpCreateUserDialog(){
|
||||
$create_user_dialog.dialog('open');
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -564,8 +696,6 @@ function popUpUpdatePasswordDialog(){
|
||||
$update_pw_dialog.dialog('open');
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Prepare the autorefresh of the list
|
||||
function setUserAutorefresh(){
|
||||
setInterval(function(){
|
||||
@ -610,6 +740,7 @@ $(document).ready(function(){
|
||||
|
||||
setupCreateUserDialog();
|
||||
setupUpdatePasswordDialog();
|
||||
setupUserQuotasDialog();
|
||||
setUserAutorefresh();
|
||||
|
||||
initCheckAllBoxes(dataTable_users);
|
||||
|
@ -953,4 +953,208 @@ function buildOctet(permTable){
|
||||
other+=1;
|
||||
|
||||
return ""+owner+group+other;
|
||||
};
|
||||
};
|
||||
|
||||
function setupQuotasDialog(dialog){
|
||||
|
||||
var height = Math.floor($(window).height()*0.8); //set height to a percentage of the window
|
||||
|
||||
//Prepare jquery dialog
|
||||
dialog.dialog({
|
||||
autoOpen: false,
|
||||
modal:true,
|
||||
width: 740,
|
||||
height: height
|
||||
});
|
||||
|
||||
$('button',dialog).button();
|
||||
$('#vm_quota,#datastore_quota,#image_quota,#network_quota',dialog).hide();
|
||||
|
||||
$('#quota_types input',dialog).click(function(){
|
||||
$('#vm_quota,#datastore_quota,#image_quota,#network_quota',dialog).hide();
|
||||
$('#'+$(this).val()+'_quota',dialog).show();
|
||||
$('#add_quota_button',dialog).show();
|
||||
})
|
||||
|
||||
$('#add_quota_button',dialog).hide();
|
||||
|
||||
$('#add_quota_button',dialog).click(function(){
|
||||
var sel = $('#quota_types input:checked',dialog).val();
|
||||
var fields = $('div#'+sel+'_quota input,div#'+sel+'_quota select',dialog);
|
||||
var json = {};
|
||||
|
||||
for (var i = 0; i < fields.length; i++){
|
||||
var field = $(fields[i]);
|
||||
var name = field.attr('name');
|
||||
var value = field.val();
|
||||
if (name == 'ID' && !value.length){
|
||||
notifyError(tr("Please select an element"));
|
||||
return false;
|
||||
};
|
||||
if (!value) value = 0;
|
||||
json[name] = value;
|
||||
};
|
||||
|
||||
json['TYPE'] = sel.toUpperCase();
|
||||
|
||||
var li = quotaListItem(json)
|
||||
$('ul#quotas_ul_'+sel,dialog).append($(li).hide().fadeIn());
|
||||
return false;
|
||||
});
|
||||
|
||||
$('form', dialog).submit(function(){
|
||||
var obj = {};
|
||||
$('ul li',this).each(function(){
|
||||
var json = JSON.parse($(this).attr('quota'));
|
||||
var type = json['TYPE'];
|
||||
delete json['TYPE'];
|
||||
obj[type.toUpperCase()] = json;
|
||||
});
|
||||
|
||||
var action = $('div.form_buttons button',this).val();
|
||||
var sel_elems = SunstoneCfg["actions"][action].elements();
|
||||
Sunstone.runAction(action,sel_elems,obj);
|
||||
dialog.dialog('close');
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
function popUpQuotasDialog(dialog, resource, sel_elems){
|
||||
var im_sel = makeSelectOptions(dataTable_images,1,4,[],[]);
|
||||
var vn_sel = makeSelectOptions(dataTable_vNetworks,1,4,[],[]);
|
||||
$('#datastore_quota select',dialog).html(datastores_sel());
|
||||
$('#image_quota select',dialog).html(im_sel);
|
||||
$('#network_quota select',dialog).html(vn_sel);
|
||||
|
||||
|
||||
//If only one user is selected we fecth the user's quotas, otherwise we do nothing.
|
||||
if (sel_elems.length == 1){
|
||||
var id = sel_elems[0];
|
||||
Sunstone.runAction(resource + '.fetch_quotas',id);
|
||||
} else {
|
||||
$('ul',dialog).empty();
|
||||
};
|
||||
|
||||
dialog.dialog('open');
|
||||
}
|
||||
|
||||
function setupQuotaIcons(){
|
||||
$('.quota_edit_icon').live('click',function(){
|
||||
var dialog = $(this).parents('form');
|
||||
var li = $(this).parents('li');
|
||||
var quota = JSON.parse(li.attr('quota'));
|
||||
switch (quota.TYPE){
|
||||
case "VM":
|
||||
$('div#vm_quota input[name="VMS"]',dialog).val(quota.VMS);
|
||||
$('div#vm_quota input[name="MEMORY"]',dialog).val(quota.MEMORY);
|
||||
$('div#vm_quota input[name="CPU"]',dialog).val(quota.CPU);
|
||||
break;
|
||||
case "DATASTORE":
|
||||
$('div#datastore_quota select[name="ID"]',dialog).val(quota.ID);
|
||||
$('div#datastore_quota input[name="SIZE"]',dialog).val(quota.SIZE);
|
||||
$('div#datastore_quota input[name="IMAGES"]').val(quota.IMAGES);
|
||||
break;
|
||||
case "IMAGE":
|
||||
$('div#image_quota select[name="ID"]',dialog).val(quota.ID);
|
||||
$('div#image_quota input[name="RVMS"]',dialog).val(quota.RVMS);
|
||||
break;
|
||||
case "NETWORK":
|
||||
$('div#network_quota select[name="ID"]',dialog).val(quota.ID);
|
||||
$('div#network_quota input[name="LEASES"]',dialog).val(quota.LEASES);
|
||||
break;
|
||||
}
|
||||
$('div#quota_types input[value="'+quota.TYPE.toLowerCase()+'"]',dialog).trigger('click');
|
||||
$(this).parents('li').fadeOut(function(){$(this).remove()});
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.quota_remove_icon').live('click',function(){
|
||||
$(this).parents('li').fadeOut(function(){$(this).remove()});
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
function parseQuotas(elem){
|
||||
var quotas = [];
|
||||
var results = {
|
||||
VM : "",
|
||||
DATASTORE : "",
|
||||
IMAGE : "",
|
||||
NETWORK : ""
|
||||
}
|
||||
//max 1 vm quota
|
||||
if (!$.isEmptyObject(elem.VM_QUOTA)){
|
||||
elem.VM_QUOTA.VM.TYPE = 'VM'
|
||||
quotas.push(elem.VM_QUOTA.VM)
|
||||
}
|
||||
|
||||
var ds_arr = []
|
||||
if ($.isArray(elem.DATASTORE_QUOTA.DATASTORE)){
|
||||
ds_arr = elem.DATASTORE_QUOTA.DATASTORE
|
||||
} else if (!$.isEmptyObject(elem.DATASTORE_QUOTA)){
|
||||
ds_arr = [elem.DATASTORE_QUOTA.DATASTORE]
|
||||
}
|
||||
|
||||
for (var i = 0; i < ds_arr.length; i++){
|
||||
ds_arr[i].TYPE = 'DATASTORE';
|
||||
quotas.push(ds_arr[i]);
|
||||
}
|
||||
|
||||
var im_arr = []
|
||||
if ($.isArray(elem.IMAGE_QUOTA.IMAGE)){
|
||||
im_arr = elem.IMAGE_QUOTA.IMAGE
|
||||
} else if (!$.isEmptyObject(elem.IMAGE_QUOTA)){
|
||||
im_arr = [elem.IMAGE_QUOTA.IMAGE]
|
||||
}
|
||||
|
||||
for (var i = 0; i < im_arr.length; i++){
|
||||
im_arr[i].TYPE = 'IMAGE';
|
||||
quotas.push(im_arr[i]);
|
||||
}
|
||||
|
||||
var vn_arr = []
|
||||
if ($.isArray(elem.NETWORK_QUOTA)){
|
||||
vn_arr = elem.NETWORK_QUOTA.NETWORK
|
||||
} else if (!$.isEmptyObject(elem.NETWORK_QUOTA)){
|
||||
vn_arr = [elem.NETWORK_QUOTA.NETWORK]
|
||||
}
|
||||
|
||||
for (var i = 0; i < vn_arr.length; i++){
|
||||
vn_arr[i].TYPE = 'NETWORK';
|
||||
quotas.push(vn_arr[i]);
|
||||
}
|
||||
|
||||
for (var i = 0; i < quotas.length; i++){
|
||||
var li = quotaListItem(quotas[i]);
|
||||
results[quotas[i].TYPE] += li;
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
//Receives a quota json object. Returns a nice string out of it.
|
||||
function quotaListItem(quota_json){
|
||||
var value = JSON.stringify(quota_json)
|
||||
var str = '<li quota=\''+value+'\'><pre style="margin:0;">';
|
||||
switch(quota_json.TYPE){
|
||||
case "VM":
|
||||
str += 'VMs: ' + quota_json.VMS + (quota_json.VMS_USED ? ' (' + quota_json.VMS_USED + '). ' : ". ") +
|
||||
'Memory: ' + quota_json.MEMORY + (quota_json.MEMORY_USED ? ' (' + quota_json.MEMORY_USED + '). ' : ". ") +
|
||||
'CPU: ' + quota_json.CPU + (quota_json.CPU_USED ? ' (' + quota_json.CPU_USED + '). ' : ". ");
|
||||
break;
|
||||
case "DATASTORE":
|
||||
str += 'ID: ' + getDatastoreName(quota_json.ID) + '. ' +
|
||||
'Size: ' + quota_json.SIZE + (quota_json.SIZE_USED ? ' (' + quota_json.SIZE_USED + '). ' : ". ") +
|
||||
'Images: ' + quota_json.IMAGES + (quota_json.IMAGES_USED ? ' (' + quota_json.IMAGES_USED + '). ' : ".");
|
||||
break;
|
||||
case "IMAGE":
|
||||
str += 'ID: ' + getImageName(quota_json.ID) + '. ' +
|
||||
'RVMs: ' + quota_json.RVMS + (quota_json.RVMS_USED ? ' (' + quota_json.RVMS_USED + '). ' : ". ");
|
||||
break;
|
||||
case "NETWORK":
|
||||
str += 'ID: ' + getVNetName(quota_json.ID) + '. ' +
|
||||
'Leases: ' + quota_json.LEASES + (quota_json.LEASES_USED ? ' (' + quota_json.LEASES_USED + '). ': ". ");
|
||||
break;
|
||||
}
|
||||
str += '<i class="quota_edit_icon icon-pencil"></i> <i class="quota_remove_icon icon-remove"></i></pre></li>';
|
||||
return str;
|
||||
}
|
@ -309,6 +309,11 @@ $(document).ready(function(){
|
||||
//This dialog is shared to update templates
|
||||
setupTemplateUpdateDialog();
|
||||
|
||||
//Setup quota icons
|
||||
//Live listeners not working when being added in specific
|
||||
//context of users/groups dialog. Adding them globally then.
|
||||
setupQuotaIcons();
|
||||
|
||||
//Listen for .action_buttons
|
||||
//An action buttons runs a predefined action. If it has type
|
||||
//"multiple" it runs that action on the elements of a datatable.
|
||||
@ -373,6 +378,8 @@ $(document).ready(function(){
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
|
||||
//Start with the dashboard (supposing we have one).
|
||||
showTab('dashboard_tab');
|
||||
|
||||
|
@ -122,6 +122,8 @@ int Quota::set(vector<Attribute*> * new_quotas, string& error)
|
||||
goto error_limits;
|
||||
}
|
||||
}
|
||||
|
||||
cleanup_quota(id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -271,12 +273,8 @@ void Quota::del_quota(const string& qid, map<string, int>& usage_req)
|
||||
{
|
||||
VectorAttribute * q;
|
||||
map<string, int>::iterator it;
|
||||
map<string, Attribute *>::iterator q_it;
|
||||
|
||||
int limit, limit_tmp;
|
||||
int usage, usage_tmp;
|
||||
|
||||
if ( get_quota(qid, &q, q_it) == -1)
|
||||
if ( get_quota(qid, &q) == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -286,9 +284,6 @@ void Quota::del_quota(const string& qid, map<string, int>& usage_req)
|
||||
return;
|
||||
}
|
||||
|
||||
limit = 0;
|
||||
usage = 0;
|
||||
|
||||
for (int i=0; i < num_metrics; i++)
|
||||
{
|
||||
string metrics_used = metrics[i];
|
||||
@ -303,6 +298,41 @@ void Quota::del_quota(const string& qid, map<string, int>& usage_req)
|
||||
}
|
||||
|
||||
add_to_quota(q, metrics_used, -it->second);
|
||||
}
|
||||
|
||||
cleanup_quota(qid);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void Quota::cleanup_quota(const string& qid)
|
||||
{
|
||||
VectorAttribute * q;
|
||||
map<string, int>::iterator it;
|
||||
map<string, Attribute *>::iterator q_it;
|
||||
|
||||
int limit, limit_tmp;
|
||||
int usage, usage_tmp;
|
||||
|
||||
if ( get_quota(qid, &q, q_it) == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( q == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
limit = 0;
|
||||
usage = 0;
|
||||
|
||||
for (int i=0; i < num_metrics; i++)
|
||||
{
|
||||
string metrics_used = metrics[i];
|
||||
|
||||
metrics_used += "_USED";
|
||||
|
||||
q->vector_value(metrics[i], limit_tmp);
|
||||
q->vector_value(metrics_used.c_str(), usage_tmp);
|
||||
@ -313,7 +343,9 @@ void Quota::del_quota(const string& qid, map<string, int>& usage_req)
|
||||
|
||||
if ( limit == 0 && usage == 0 )
|
||||
{
|
||||
del(q_it);
|
||||
delete static_cast<Attribute *>(q_it->second);
|
||||
|
||||
attributes.erase(q_it);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user