mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-16 22:50:10 +03:00
Merge branch 'feature-788'
This commit is contained in:
commit
a6fff726c4
@ -90,14 +90,21 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the source path of the image
|
||||
* @return source of image
|
||||
* Sets the source path of the image
|
||||
*/
|
||||
void set_source(const string& _source)
|
||||
{
|
||||
source = _source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the size for the image
|
||||
*/
|
||||
void set_size(unsigned int _size_mb)
|
||||
{
|
||||
size_mb = _size_mb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of the image
|
||||
* @return type
|
||||
@ -285,27 +292,32 @@ private:
|
||||
/**
|
||||
* Type of the Image
|
||||
*/
|
||||
ImageType type;
|
||||
ImageType type;
|
||||
|
||||
/**
|
||||
* Persistency of the Image
|
||||
*/
|
||||
int persistent_img;
|
||||
int persistent_img;
|
||||
|
||||
/**
|
||||
* Registration time
|
||||
*/
|
||||
time_t regtime;
|
||||
time_t regtime;
|
||||
|
||||
/**
|
||||
* Path to the image
|
||||
*/
|
||||
string source;
|
||||
string source;
|
||||
|
||||
/**
|
||||
* Size of the image in MB
|
||||
*/
|
||||
unsigned int size_mb;
|
||||
|
||||
/**
|
||||
* Image state
|
||||
*/
|
||||
ImageState state;
|
||||
ImageState state;
|
||||
|
||||
/**
|
||||
* Number of VMs using the image
|
||||
|
@ -229,6 +229,7 @@ VAR_DIRS="$VAR_LOCATION/remotes \
|
||||
$VAR_LOCATION/remotes/auth/ssh \
|
||||
$VAR_LOCATION/remotes/auth/x509 \
|
||||
$VAR_LOCATION/remotes/auth/server \
|
||||
$VAR_LOCATION/remotes/auth/quota \
|
||||
$VAR_LOCATION/remotes/auth/dummy"
|
||||
|
||||
SUNSTONE_DIRS="$SUNSTONE_LOCATION/models \
|
||||
@ -326,6 +327,7 @@ INSTALL_FILES=(
|
||||
AUTH_SERVER_FILES:$VAR_LOCATION/remotes/auth/server
|
||||
AUTH_DUMMY_FILES:$VAR_LOCATION/remotes/auth/dummy
|
||||
AUTH_PLAIN_FILES:$VAR_LOCATION/remotes/auth/plain
|
||||
AUTH_QUOTA_FILES:$VAR_LOCATION/remotes/auth/quota
|
||||
VMM_EXEC_KVM_SCRIPTS:$VAR_LOCATION/remotes/vmm/kvm
|
||||
VMM_EXEC_XEN_SCRIPTS:$VAR_LOCATION/remotes/vmm/xen
|
||||
VMM_EXEC_XEN_KVM_POLL:$VAR_LOCATION/remotes/vmm/kvm/poll
|
||||
@ -467,6 +469,7 @@ BIN_FILES="src/nebula/oned \
|
||||
src/cli/onetemplate \
|
||||
src/cli/oneacl \
|
||||
src/onedb/onedb \
|
||||
src/authm_mad/remotes/quota/onequota \
|
||||
share/scripts/one"
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
@ -490,6 +493,7 @@ RUBY_LIB_FILES="src/mad/ruby/ActionManager.rb \
|
||||
src/oca/ruby/OpenNebula.rb \
|
||||
src/tm_mad/TMScript.rb \
|
||||
src/authm_mad/remotes/ssh/ssh_auth.rb \
|
||||
src/authm_mad/remotes/quota/quota.rb \
|
||||
src/authm_mad/remotes/server/server_auth.rb \
|
||||
src/authm_mad/remotes/x509/x509_auth.rb"
|
||||
|
||||
@ -596,6 +600,8 @@ AUTH_DUMMY_FILES="src/authm_mad/remotes/dummy/authenticate"
|
||||
|
||||
AUTH_PLAIN_FILES="src/authm_mad/remotes/plain/authenticate"
|
||||
|
||||
AUTH_QUOTA_FILES="src/authm_mad/remotes/quota/authorize"
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Transfer Manager commands, to be installed under $LIB_LOCATION/tm_commands
|
||||
# - NFS TM, $LIB_LOCATION/tm_commands/nfs
|
||||
@ -708,6 +714,7 @@ HM_ETC_FILES="src/hm_mad/hmrc"
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
AUTH_ETC_FILES="src/authm_mad/remotes/server/server_auth.conf \
|
||||
src/authm_mad/remotes/quota/quota.conf \
|
||||
src/authm_mad/remotes/x509/x509_auth.conf"
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
@ -98,14 +98,14 @@ module OneWatchClient
|
||||
max_per_vm =
|
||||
rsql.
|
||||
group(:id, :last_poll).
|
||||
select(:last_poll, :MAX[mr.to_sym].as(:max_mr))
|
||||
select{[:last_poll, max(mr.to_sym).as(:max_mr)]}
|
||||
|
||||
# SUM the monitoring resource for each last_poll value
|
||||
last_poll_and_sum =
|
||||
max_per_vm.
|
||||
from_self.
|
||||
group(:last_poll).
|
||||
select(:last_poll, :SUM[:max_mr].as(:sum_mr))
|
||||
select{[:last_poll, sum(:max_mr).as(:sum_mr)]}
|
||||
|
||||
# Retrieve the information in an Array
|
||||
a = Array.new
|
||||
@ -113,7 +113,7 @@ module OneWatchClient
|
||||
if row[:last_poll] && row[:last_poll] != 0
|
||||
a << [row[:last_poll], row[:sum_mr].to_i]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
a
|
||||
end
|
||||
@ -229,4 +229,4 @@ module OneWatchClient
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
44
src/authm_mad/test/spec_common.rb → src/authm_mad/remotes/quota/authorize
Normal file → Executable file
44
src/authm_mad/test/spec_common.rb → src/authm_mad/remotes/quota/authorize
Normal file → Executable file
@ -1,3 +1,5 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
# -------------------------------------------------------------------------- #
|
||||
# Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org) #
|
||||
# #
|
||||
@ -14,14 +16,48 @@
|
||||
# limitations under the License. #
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
require 'pp'
|
||||
ONE_LOCATION=ENV["ONE_LOCATION"]
|
||||
|
||||
$: << '../../oca/ruby'
|
||||
$: << '..'
|
||||
if !ONE_LOCATION
|
||||
RUBY_LIB_LOCATION="/usr/lib/one/ruby"
|
||||
ETC_LOCATION="/etc/one/"
|
||||
else
|
||||
RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby"
|
||||
ETC_LOCATION=ONE_LOCATION+"/etc/"
|
||||
end
|
||||
|
||||
require 'db_helpers'
|
||||
$: << RUBY_LIB_LOCATION
|
||||
|
||||
require 'scripts_common'
|
||||
require 'opennebula'
|
||||
require 'quota'
|
||||
|
||||
user_id = ARGV.shift
|
||||
|
||||
overall_evalutation = ARGV.pop
|
||||
exit -1 if overall_evalutation == 0
|
||||
|
||||
quota = Quota.new
|
||||
|
||||
#q = {
|
||||
# :cpu => 10,
|
||||
# :memory => 2048,
|
||||
# :storage => 100000,
|
||||
# :num_vms => 5
|
||||
#}
|
||||
#
|
||||
#quota.set(1, q)
|
||||
#OpenNebula.log_debug("quotas: #{quota.get(1)}")
|
||||
|
||||
ARGV.each {|request|
|
||||
rc = quota.authorize(user_id, request)
|
||||
|
||||
if rc
|
||||
OpenNebula.error_message rc
|
||||
exit -1
|
||||
end
|
||||
}
|
||||
|
||||
#OpenNebula.log_debug("AUTHORIZE ARGS: #{ARGV.join(' ')}")
|
||||
|
||||
exit 0
|
166
src/authm_mad/remotes/quota/onequota
Executable file
166
src/authm_mad/remotes/quota/onequota
Executable file
@ -0,0 +1,166 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
# -------------------------------------------------------------------------- #
|
||||
# Copyright 2002-2011, 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. #
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
ONE_LOCATION=ENV["ONE_LOCATION"]
|
||||
|
||||
if !ONE_LOCATION
|
||||
RUBY_LIB_LOCATION="/usr/lib/one/ruby"
|
||||
else
|
||||
RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby"
|
||||
end
|
||||
|
||||
$: << RUBY_LIB_LOCATION
|
||||
$: << RUBY_LIB_LOCATION+"/cli"
|
||||
|
||||
require 'command_parser'
|
||||
require 'cli_helper'
|
||||
require 'one_helper'
|
||||
require 'quota'
|
||||
|
||||
require 'pp'
|
||||
|
||||
QUOTA_KEYS = Quota::DB_QUOTA_SCHEMA.keys
|
||||
|
||||
def show_table(values, usage=nil)
|
||||
size = usage ? 12 : 8
|
||||
|
||||
values.sort!{|v1, v2| v1[:uid]<=>v2[:uid] }
|
||||
|
||||
table=CLIHelper::ShowTable.new(nil, self) do
|
||||
column :uid, "ONE identifier for the User", :size=>4 do |d|
|
||||
d[:uid]
|
||||
end
|
||||
|
||||
QUOTA_KEYS.each { |key|
|
||||
column key, "#{key} quota", :size=>size do |d|
|
||||
if usage
|
||||
"#{usage[key].to_i}/#{d[key].to_i}"
|
||||
else
|
||||
"#{d[key].to_i}"
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
default :uid, *QUOTA_KEYS
|
||||
end
|
||||
|
||||
table.show(values)
|
||||
end
|
||||
|
||||
cmd=CommandParser::CmdParser.new(ARGV) do
|
||||
usage "`onequota` <command> [<args>] [<options>]"
|
||||
version OpenNebulaHelper::ONE_VERSION
|
||||
|
||||
quota = Quota.new
|
||||
|
||||
########################################################################
|
||||
# Global Options
|
||||
########################################################################
|
||||
set :option, CommandParser::OPTIONS
|
||||
|
||||
########################################################################
|
||||
# Argument Formats
|
||||
########################################################################
|
||||
quota_list_desc = <<-EOT.unindent
|
||||
List of quota keys, comma separated.
|
||||
Available quotas: #{QUOTA_KEYS.join(', ')}
|
||||
EOT
|
||||
|
||||
set :format, :quota_list, quota_list_desc do |arg|
|
||||
arg_list = arg.split(',')
|
||||
|
||||
rc = nil
|
||||
arg_list.each do |elem|
|
||||
if !QUOTA_KEYS.include?(elem.to_sym)
|
||||
rc = -1, "#{elem} is not a valid quota"
|
||||
end
|
||||
end
|
||||
|
||||
rc ? rc : [0, arg_list]
|
||||
end
|
||||
|
||||
set :format, :value_list, "List of quota values, comma separated." do |arg|
|
||||
arg_list = arg.split(',')
|
||||
arg_list.map! {|a| a.to_i }
|
||||
[0, arg_list]
|
||||
end
|
||||
|
||||
set :format, :userid, OpenNebulaHelper.rname_to_id_desc("USER") do |arg|
|
||||
OpenNebulaHelper.rname_to_id(arg, "USER")
|
||||
end
|
||||
|
||||
########################################################################
|
||||
# Commands
|
||||
########################################################################
|
||||
set_desc = <<-EOT.unindent
|
||||
Set a quota for a given user.
|
||||
Examples:
|
||||
onequota set 3 cpu 12
|
||||
onequota set 4 cpu,memory,storage 8,4096,10000
|
||||
EOT
|
||||
|
||||
command :set, set_desc, :userid, :quota_list, :value_list do
|
||||
user_id, keys, values = args
|
||||
|
||||
if keys.length != values.length
|
||||
exit_with_code -1, "The number of keys and values does not match"
|
||||
end
|
||||
|
||||
values_hash = Hash.new
|
||||
keys.each_with_index { |k,i|
|
||||
values_hash[k.to_sym] = values[i]
|
||||
}
|
||||
|
||||
quota.set_quota(user_id, values_hash)
|
||||
exit_with_code 0
|
||||
end
|
||||
|
||||
########################################################################
|
||||
delete_desc = "Delete the defined quotas for the given user"
|
||||
|
||||
command :delete, delete_desc, :userid do
|
||||
quota.delete_quota(args[0])
|
||||
exit_with_code 0
|
||||
end
|
||||
|
||||
########################################################################
|
||||
show_desc = "Show the user's quota and usage. (usage/quota)"
|
||||
|
||||
FORCE={
|
||||
:name => "force",
|
||||
:short => "-f",
|
||||
:large => "--force",
|
||||
:description => "Force the usage calculation instead of using the cache"
|
||||
}
|
||||
|
||||
command :show, show_desc, :userid, :options=>[FORCE] do
|
||||
user_usage = quota.get_usage(args[0],nil,options[:force])
|
||||
user_quota = quota.get_quota(args[0])
|
||||
|
||||
show_table([user_quota], user_usage)
|
||||
exit_with_code 0
|
||||
end
|
||||
|
||||
########################################################################
|
||||
list_desc = "List the defined quotas for all the users"
|
||||
|
||||
command :list, list_desc do
|
||||
show_table(quota.get_quota)
|
||||
exit_with_code 0
|
||||
end
|
||||
end
|
@ -14,12 +14,16 @@
|
||||
# limitations under the License. #
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
require 'rubygems'
|
||||
require 'sequel'
|
||||
|
||||
def check_column(schema, column)
|
||||
schema.find {|c| c[0] == column }.should_not == nil
|
||||
end
|
||||
|
||||
# Database URI
|
||||
#:db: sqlite:///var/one/onequota.db
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Default quotas, these apply to all users. Leave empty to disable quota for
|
||||
# a given metric.
|
||||
#-------------------------------------------------------------------------------
|
||||
:defaults:
|
||||
:cpu:
|
||||
:memory:
|
||||
:num_vms:
|
||||
:storage:
|
||||
|
289
src/authm_mad/remotes/quota/quota.rb
Normal file
289
src/authm_mad/remotes/quota/quota.rb
Normal file
@ -0,0 +1,289 @@
|
||||
# -------------------------------------------------------------------------- #
|
||||
# Copyright 2002-2011, 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 'sequel'
|
||||
require 'base64'
|
||||
require 'yaml'
|
||||
|
||||
class Quota
|
||||
###########################################################################
|
||||
# Constants with paths to relevant files and defaults
|
||||
###########################################################################
|
||||
ONE_LOCATION=ENV["ONE_LOCATION"]
|
||||
|
||||
if !ONE_LOCATION
|
||||
VAR_LOCATION = "/var/lib/one"
|
||||
ETC_LOCATION = "/etc/one"
|
||||
else
|
||||
VAR_LOCATION = ONE_LOCATION + "/var"
|
||||
ETC_LOCATION = ONE_LOCATION + "/etc"
|
||||
end
|
||||
|
||||
CONF_FILE = ETC_LOCATION + "/auth/quota.conf"
|
||||
|
||||
CONF = {
|
||||
:db => "sqlite://#{VAR_LOCATION}/onequota.db",
|
||||
:defaults => {
|
||||
:cpu => nil,
|
||||
:memory => nil,
|
||||
:num_vms => nil,
|
||||
:storage => nil
|
||||
}
|
||||
}
|
||||
|
||||
###########################################################################
|
||||
# Schema for the USAGE and QUOTA tables
|
||||
###########################################################################
|
||||
DB_QUOTA_SCHEMA = {
|
||||
:cpu => Float,
|
||||
:memory => Integer,
|
||||
:num_vms => Integer,
|
||||
:storage => Integer
|
||||
}
|
||||
|
||||
QUOTA_TABLE = :quotas
|
||||
USAGE_TABLE = :usage
|
||||
|
||||
###########################################################################
|
||||
# Usage params to calculate each quota
|
||||
###########################################################################
|
||||
VM_USAGE = {
|
||||
:cpu => {
|
||||
:proc_info => lambda {|template| template['CPU']},
|
||||
:xpath => 'TEMPLATE/CPU'
|
||||
},
|
||||
:memory => {
|
||||
:proc_info => lambda {|template| template['MEMORY']},
|
||||
:xpath => 'TEMPLATE/MEMORY'
|
||||
},
|
||||
:num_vms => {
|
||||
:proc_info => lambda {|template| 1 },
|
||||
:xpath => 'ID',
|
||||
:count => true
|
||||
}
|
||||
}
|
||||
|
||||
IMAGE_USAGE = {
|
||||
:storage => {
|
||||
:proc_info => lambda {|template| File.size(template['PATH']) },
|
||||
:xpath => 'SIZE'
|
||||
}
|
||||
}
|
||||
|
||||
RESOURCES = ["VM", "IMAGE"]
|
||||
|
||||
###########################################################################
|
||||
# DB handling
|
||||
###########################################################################
|
||||
def initialize
|
||||
conf = YAML.load_file(CONF_FILE)
|
||||
@conf=CONF.merge(conf) {|key,h1,h2|
|
||||
h1.merge(h2) if h1.instance_of?(Hash) && h2.instance_of?(Hash)
|
||||
}
|
||||
|
||||
@client = OpenNebula::Client.new
|
||||
|
||||
@db=Sequel.connect(@conf[:db])
|
||||
|
||||
create_table(QUOTA_TABLE)
|
||||
create_table(USAGE_TABLE)
|
||||
end
|
||||
|
||||
# Creates database quota table if it does not exist
|
||||
def create_table(table)
|
||||
@db.create_table?(table) do
|
||||
Integer :uid
|
||||
|
||||
DB_QUOTA_SCHEMA.each { |key,value|
|
||||
column key, value
|
||||
}
|
||||
|
||||
primary_key :uid
|
||||
index :uid
|
||||
end
|
||||
end
|
||||
|
||||
# Adds new user limits
|
||||
def set(table, uid, quota={})
|
||||
data=quota.delete_if{|key,value| !DB_QUOTA_SCHEMA.keys.include?(key)}
|
||||
|
||||
quotas=@db[table].filter(:uid => uid)
|
||||
|
||||
if quotas.first
|
||||
quotas.update(data)
|
||||
else
|
||||
@db[table].insert(data.merge!(:uid => uid))
|
||||
end
|
||||
end
|
||||
|
||||
# Gets user limits
|
||||
def get(table, uid=nil)
|
||||
if uid
|
||||
@db[table].filter(:uid => uid).first
|
||||
else
|
||||
@db[table].all
|
||||
end
|
||||
end
|
||||
|
||||
# Delete user limits
|
||||
def delete(table, uid)
|
||||
quotas=@db[table].filter(:uid => uid)
|
||||
|
||||
if quotas.first
|
||||
quotas.delete
|
||||
end
|
||||
end
|
||||
|
||||
###########################################################################
|
||||
# Quota Client
|
||||
###########################################################################
|
||||
def set_quota(uid, quota={})
|
||||
set(QUOTA_TABLE, uid, quota)
|
||||
end
|
||||
|
||||
def get_quota(uid=nil)
|
||||
limit = get(QUOTA_TABLE, uid)
|
||||
limit ? limit : @conf[:defaults].merge!(:uid => uid)
|
||||
end
|
||||
|
||||
def delete_quota(uid)
|
||||
delete(QUOTA_TABLE, uid)
|
||||
end
|
||||
|
||||
###########################################################################
|
||||
# Authorization
|
||||
###########################################################################
|
||||
def authorize(user_id, request)
|
||||
obj, template_or_id, op, owner, pub, acl_eval = request.split(':')
|
||||
|
||||
if acl_eval == 0
|
||||
return "ACL evaluation denied"
|
||||
end
|
||||
|
||||
# Check if this op needs to check the quota
|
||||
return false unless with_quota?(obj, op)
|
||||
|
||||
# If the object is a template the info should be retrived from the
|
||||
# VM pool.
|
||||
obj = "VM" if obj == "TEMPLATE"
|
||||
template = Base64::decode64(template_or_id)
|
||||
|
||||
check_quotas(user_id.to_i, obj, template)
|
||||
end
|
||||
|
||||
def check_quotas(user_id, obj, template)
|
||||
info = get_resources(obj, template)
|
||||
total = get_usage(user_id, obj, true)
|
||||
quota = get_quota(user_id)
|
||||
|
||||
msg = ""
|
||||
info.each { |qname, quota_requested|
|
||||
unless quota[qname]
|
||||
next
|
||||
end
|
||||
|
||||
used = send(DB_QUOTA_SCHEMA[qname].name.to_sym, total[qname])
|
||||
request = send(DB_QUOTA_SCHEMA[qname].name.to_sym, quota_requested)
|
||||
limit = send(DB_QUOTA_SCHEMA[qname].name.to_sym, quota[qname])
|
||||
spent = used + request
|
||||
|
||||
if spent > limit
|
||||
msg << " #{qname.to_s.upcase} quota exceeded "
|
||||
msg << "(Quota: #{limit}, "
|
||||
msg << "Used: #{used}, "
|
||||
msg << "Asked: #{request})."
|
||||
end
|
||||
}
|
||||
|
||||
if msg==""
|
||||
return false
|
||||
else
|
||||
return msg.strip
|
||||
end
|
||||
end
|
||||
|
||||
def with_quota?(obj, op)
|
||||
return (obj == "VM" && op == "CREATE") ||
|
||||
(obj == "IMAGE" && op == "CREATE") ||
|
||||
(obj == "TEMPLATE" && op == "INSTANTIATE")
|
||||
end
|
||||
|
||||
###########################################################################
|
||||
# Usage
|
||||
###########################################################################
|
||||
def get_usage(user_id, resource=nil, force=false)
|
||||
if force
|
||||
if RESOURCES.include?(resource)
|
||||
resources = [resource]
|
||||
else
|
||||
resources = RESOURCES
|
||||
end
|
||||
|
||||
usage = Hash.new
|
||||
|
||||
resources.each{ |res|
|
||||
pool = get_pool(res, user_id)
|
||||
base_xpath = "/#{res}_POOL/#{resource}"
|
||||
Quota.const_get("#{res}_USAGE".to_sym).each { |key, params|
|
||||
pool.each_xpath("#{base_xpath}/#{params[:xpath]}") { |elem|
|
||||
if elem
|
||||
usage[key] ||= 0
|
||||
if params[:count]
|
||||
usage[key] += 1
|
||||
else
|
||||
usage[key] += send(DB_QUOTA_SCHEMA[key].name.to_sym, elem)
|
||||
end
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
set(USAGE_TABLE, user_id, usage) unless usage.empty?
|
||||
usage.merge!(:uid => user_id)
|
||||
}
|
||||
else
|
||||
usage = get(USAGE_TABLE, user_id)
|
||||
usage ||= {:uid => user_id}
|
||||
end
|
||||
|
||||
usage
|
||||
end
|
||||
|
||||
# Retrieve the useful information of the template for the specified
|
||||
# kind of resource
|
||||
def get_resources(resource, xml_template)
|
||||
template = OpenNebula::XMLElement.new
|
||||
template.initialize_xml(xml_template, 'TEMPLATE')
|
||||
|
||||
info = Hash.new
|
||||
|
||||
self.class.const_get("#{resource}_USAGE").each { |key, params|
|
||||
info[key] = params[:proc_info].call(template).to_i
|
||||
}
|
||||
|
||||
info
|
||||
end
|
||||
|
||||
# Returns a an Array than contains the elements of the resource Pool
|
||||
def get_pool(resource, user_id)
|
||||
pool = case resource
|
||||
when "VM" then OpenNebula::VirtualMachinePool.new(@client, user_id)
|
||||
when "IMAGE" then OpenNebula::ImagePool.new(@client, user_id)
|
||||
end
|
||||
|
||||
rc = pool.info
|
||||
return pool
|
||||
end
|
||||
end
|
26
src/authm_mad/remotes/quota/test/fixtures/imagepool.xml
vendored
Normal file
26
src/authm_mad/remotes/quota/test/fixtures/imagepool.xml
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
<IMAGE_POOL>
|
||||
<% images.each do |id,image| %>
|
||||
<IMAGE>
|
||||
<ID><%= id %></ID>
|
||||
<UID><%= image[:uid] ? image[:uid] : 0 %></UID>
|
||||
<GID><%= image[:gid] ? image[:gid] : 0 %></GID>
|
||||
<UNAME><%= image[:uname] ? image[:uname] : 'oneadmin' %></UNAME>
|
||||
<GNAME><%= image[:gname] ? image[:gname] : 'oneadmin' %></GNAME>
|
||||
<NAME><%= image[:name] ? image[:name] : 'ttylinux' %></NAME>
|
||||
<TYPE><%= image[:type] ? image[:type] : 0 %></TYPE>
|
||||
<PUBLIC><%= image[:pub] ? image[:pub] : 0 %></PUBLIC>
|
||||
<PERSISTENT><%= image[:persistent] ? image[:persistent] : 0 %></PERSISTENT>
|
||||
<REGTIME>1314875019</REGTIME>
|
||||
<SOURCE><%= image[:source] ? image[:source] : '/etc/hosts' %></SOURCE>
|
||||
<STATE><%= image[:state] ? image[:state] : 1 %></STATE>
|
||||
<SIZE><%= image[:size] ? image[:size] : 100 %></SIZE>
|
||||
<RUNNING_VMS>0</RUNNING_VMS>
|
||||
<TEMPLATE>
|
||||
<DEV_PREFIX><![CDATA[hd]]></DEV_PREFIX>
|
||||
<NAME><![CDATA[PEPE]]></NAME>
|
||||
<PATH><![CDATA[/etc/hosts]]></PATH>
|
||||
<TYPE><![CDATA[OS]]></TYPE>
|
||||
</TEMPLATE>
|
||||
</IMAGE>
|
||||
<% end %>
|
||||
</IMAGE_POOL>
|
46
src/authm_mad/remotes/quota/test/fixtures/vm.xml
vendored
Normal file
46
src/authm_mad/remotes/quota/test/fixtures/vm.xml
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
<VM>
|
||||
<ID><%= id %></ID>
|
||||
<UID><%= vm[:uid] ? vm[:uid] : 0 %></UID>
|
||||
<GID><%= vm[:gid] ? vm[:gid] : 0 %></GID>
|
||||
<NAME><%= vm[:name] ? vm[:uid] : 'pepe' %></NAME>
|
||||
<LAST_POLL><%= vm[:last_poll] ? vm[:last_poll] : '1309275256' %></LAST_POLL>
|
||||
<STATE><%= vm[:state] ? vm[:state] : 3 %></STATE>
|
||||
<LCM_STATE>3</LCM_STATE>
|
||||
<STIME>1309275252</STIME>
|
||||
<ETIME>0</ETIME>
|
||||
<DEPLOY_ID>dummy</DEPLOY_ID>
|
||||
<MEMORY><%= vm[:memory] ? vm[:memory] : 128 %></MEMORY>
|
||||
<CPU><%= vm[:cpu] ? vm[:cpu] : 1 %></CPU>
|
||||
<NET_TX><%= vm[:net_tx] ? vm[:net_tx] : 0 %></NET_TX>
|
||||
<NET_RX><%= vm[:net_rx] ? vm[:net_rx] : 0 %></NET_RX>
|
||||
<TEMPLATE>
|
||||
<CPU><![CDATA[1]]></CPU>
|
||||
<MEMORY><![CDATA[1024]]></MEMORY>
|
||||
<NAME><![CDATA[PEPEPE]]></NAME>
|
||||
<VCPU><![CDATA[1]]></VCPU>
|
||||
<VMID><![CDATA[4]]></VMID>
|
||||
</TEMPLATE>
|
||||
<% if history = vm[:history] %>
|
||||
<HISTORY_RECORDS>
|
||||
<% history.each do |h| %>
|
||||
<HISTORY>
|
||||
<SEQ><%= h[:seq] ? h[:seq] : 0 %></SEQ>
|
||||
<HOSTNAME><%= h[:hostname] ? h[:hostname] : "kvxen" %></HOSTNAME>
|
||||
<VM_DIR>/Users/dmolina/trabajo/acctmoni/install/var/</VM_DIR>
|
||||
<HID><%= h[:hid] ? h[:hid] : 0 %></HID>
|
||||
<STIME>1309275256</STIME>
|
||||
<ETIME>0</ETIME>
|
||||
<VMMMAD>vmm_dummy</VMMMAD>
|
||||
<TMMAD>tm_dummy</TMMAD>
|
||||
<PSTIME><%= h[:pstime] ? h[:pstime] : 0 %></PSTIME>
|
||||
<PETIME><%= h[:petime] ? h[:petime] : 0 %></PETIME>
|
||||
<RSTIME><%= h[:rstime] ? h[:rstime] : 0 %></RSTIME>
|
||||
<RETIME><%= h[:retime] ? h[:retime] : 0 %></RETIME>
|
||||
<ESTIME><%= h[:estime] ? h[:estime] : 0 %></ESTIME>
|
||||
<EETIME><%= h[:eetime] ? h[:eetime] : 0 %></EETIME>
|
||||
<REASON><%= h[:reason] ? h[:reason] : 0 %></REASON>
|
||||
</HISTORY>
|
||||
<% end %>
|
||||
</HISTORY_RECORDS>
|
||||
<% end %>
|
||||
</VM>
|
49
src/authm_mad/remotes/quota/test/fixtures/vmpool.xml
vendored
Normal file
49
src/authm_mad/remotes/quota/test/fixtures/vmpool.xml
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
<VM_POOL>
|
||||
<% vms.each do |id,vm| %>
|
||||
<VM>
|
||||
<ID><%= id %></ID>
|
||||
<UID><%= vm[:uid] ? vm[:uid] : 0 %></UID>
|
||||
<GID><%= vm[:gid] ? vm[:gid] : 0 %></GID>
|
||||
<NAME><%= vm[:name] ? vm[:uid] : 'pepe' %></NAME>
|
||||
<LAST_POLL><%= vm[:last_poll] ? vm[:last_poll] : '1309275256' %></LAST_POLL>
|
||||
<STATE><%= vm[:state] ? vm[:state] : 3 %></STATE>
|
||||
<LCM_STATE>3</LCM_STATE>
|
||||
<STIME>1309275252</STIME>
|
||||
<ETIME>0</ETIME>
|
||||
<DEPLOY_ID>dummy</DEPLOY_ID>
|
||||
<MEMORY><%= vm[:memory] ? vm[:memory] : 128 %></MEMORY>
|
||||
<CPU><%= vm[:cpu] ? vm[:cpu] : 1 %></CPU>
|
||||
<NET_TX><%= vm[:net_tx] ? vm[:net_tx] : 0 %></NET_TX>
|
||||
<NET_RX><%= vm[:net_rx] ? vm[:net_rx] : 0 %></NET_RX>
|
||||
<TEMPLATE>
|
||||
<CPU><![CDATA[<%= vm[:cpu] ? vm[:cpu] : 1 %>]]></CPU>
|
||||
<MEMORY><![CDATA[<%= vm[:memory] ? vm[:memory] : 128 %>]]></MEMORY>
|
||||
<NAME><![CDATA[PEPEPE]]></NAME>
|
||||
<VCPU><![CDATA[1]]></VCPU>
|
||||
<VMID><![CDATA[4]]></VMID>
|
||||
</TEMPLATE>
|
||||
<% if history = vm[:history] %>
|
||||
<HISTORY_RECORDS>
|
||||
<% h = history.last %>
|
||||
<HISTORY>
|
||||
<SEQ><%= h[:seq] ? h[:seq] : 0 %></SEQ>
|
||||
<HOSTNAME><%= h[:hostname] ? h[:hostname] : "kvxen" %></HOSTNAME>
|
||||
<VM_DIR>/Users/dmolina/trabajo/acctmoni/install/var/</VM_DIR>
|
||||
<HID><%= h[:hid] ? h[:hid] : 0 %></HID>
|
||||
<STIME>1309275256</STIME>
|
||||
<ETIME>0</ETIME>
|
||||
<VMMMAD>vmm_dummy</VMMMAD>
|
||||
<TMMAD>tm_dummy</TMMAD>
|
||||
<PSTIME><%= h[:pstime] ? h[:pstime] : 0 %></PSTIME>
|
||||
<PETIME><%= h[:petime] ? h[:petime] : 0 %></PETIME>
|
||||
<RSTIME><%= h[:rstime] ? h[:rstime] : 0 %></RSTIME>
|
||||
<RETIME><%= h[:retime] ? h[:retime] : 0 %></RETIME>
|
||||
<ESTIME><%= h[:estime] ? h[:estime] : 0 %></ESTIME>
|
||||
<EETIME><%= h[:eetime] ? h[:eetime] : 0 %></EETIME>
|
||||
<REASON><%= h[:reason] ? h[:reason] : 0 %></REASON>
|
||||
</HISTORY>
|
||||
</HISTORY_RECORDS>
|
||||
<% end %>
|
||||
</VM>
|
||||
<% end %>
|
||||
</VM_POOL>
|
53
src/authm_mad/remotes/quota/test/helper/mock_client.rb
Normal file
53
src/authm_mad/remotes/quota/test/helper/mock_client.rb
Normal file
@ -0,0 +1,53 @@
|
||||
require 'erb'
|
||||
|
||||
FPATH = "./fixtures/"
|
||||
|
||||
class MockClient
|
||||
def initialize
|
||||
@vms = Hash.new
|
||||
@done_vms = Hash.new
|
||||
|
||||
@images = Hash.new
|
||||
end
|
||||
|
||||
|
||||
def call(action, *args)
|
||||
xmlrpc_action = "one."+action
|
||||
|
||||
case xmlrpc_action
|
||||
when "one.vm.info"
|
||||
id = args[0]
|
||||
vm = @vms[id]
|
||||
return ERB.new(File.read(FPATH+'vm.xml')).result(binding)
|
||||
when "one.vmpool.info"
|
||||
case args[3]
|
||||
when -1
|
||||
vms = @vms
|
||||
return ERB.new(File.read(FPATH+'vmpool.xml')).result(binding)
|
||||
when 6 then
|
||||
vms = @done_vms
|
||||
return ERB.new(File.read(FPATH+'vmpool.xml')).result(binding)
|
||||
end
|
||||
when "one.imagepool.info"
|
||||
images = @images
|
||||
return ERB.new(File.read(FPATH+'imagepool.xml')).result(binding)
|
||||
end
|
||||
end
|
||||
|
||||
def add_vm(id, values)
|
||||
if values[:state] == 6
|
||||
@done_vms[id] = values.clone
|
||||
else
|
||||
@vms[id] = values.clone
|
||||
end
|
||||
end
|
||||
|
||||
def delete_vm(id)
|
||||
@vms.delete(id)
|
||||
@vms_done.delete(id)
|
||||
end
|
||||
|
||||
def add_image(id, values)
|
||||
@images[id] = values
|
||||
end
|
||||
end
|
31
src/authm_mad/remotes/quota/test/helper/test_helper.rb
Normal file
31
src/authm_mad/remotes/quota/test/helper/test_helper.rb
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
ONE_LOCATION = ENV['ONE_LOCATION']
|
||||
if !ONE_LOCATION
|
||||
RUBY_LIB_LOCATION="/usr/lib/one/ruby"
|
||||
else
|
||||
RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby"
|
||||
end
|
||||
|
||||
$: << RUBY_LIB_LOCATION
|
||||
|
||||
$: << './helper'
|
||||
$: << '.'
|
||||
$: << '..'
|
||||
|
||||
require 'mock_client'
|
||||
require 'opennebula'
|
||||
require 'quota'
|
||||
|
||||
class Quota
|
||||
def set_client(client)
|
||||
@client = client
|
||||
end
|
||||
|
||||
def rm_and_set_testdb
|
||||
`rm -f /tmp/onequota_test.db`
|
||||
@db=Sequel.connect("sqlite:///tmp/onequota_test.db")
|
||||
|
||||
create_table(QUOTA_TABLE)
|
||||
create_table(USAGE_TABLE)
|
||||
end
|
||||
end
|
343
src/authm_mad/remotes/quota/test/quota_spec.rb
Normal file
343
src/authm_mad/remotes/quota/test/quota_spec.rb
Normal file
@ -0,0 +1,343 @@
|
||||
$: << '.'
|
||||
|
||||
require 'helper/test_helper'
|
||||
|
||||
describe "Quota testing" do
|
||||
before(:all) do
|
||||
@mock_client = MockClient.new
|
||||
|
||||
@quota = Quota.new
|
||||
@quota.set_client(@mock_client)
|
||||
@quota.rm_and_set_testdb
|
||||
|
||||
@uid1 = 0
|
||||
@quota1 = {
|
||||
:cpu => 2.4,
|
||||
:memory => 1024,
|
||||
:num_vms => 4,
|
||||
:storage => 10000
|
||||
}
|
||||
|
||||
@uid2 = 1
|
||||
@quota2 = {
|
||||
:cpu => 1.2,
|
||||
:memory => 512,
|
||||
:num_vms => 2,
|
||||
:storage => 5000
|
||||
}
|
||||
|
||||
# Generate VM ACL request
|
||||
vm_template = <<-EOT
|
||||
<TEMPLATE>
|
||||
<CPU>2</CPU>
|
||||
<MEMORY>128</MEMORY>
|
||||
<TEMPLATE>
|
||||
EOT
|
||||
|
||||
vm_base64 = Base64::encode64(vm_template)
|
||||
@acl_vm_create = "VM:#{vm_base64}:CREATE:0:1:1"
|
||||
|
||||
# Generate IMAGE ACL request
|
||||
image_template = <<-EOT
|
||||
<TEMPLATE>
|
||||
<PATH>/etc/hosts</PATH>
|
||||
<TEMPLATE>
|
||||
EOT
|
||||
|
||||
image_base64 = Base64::encode64(image_template)
|
||||
@acl_image_create = "IMAGE:#{image_base64}:CREATE:0:1:1"
|
||||
|
||||
# Generate TEMPLATE ACL request
|
||||
temp_template = <<-EOT
|
||||
<TEMPLATE>
|
||||
<CPU>2</CPU>
|
||||
<MEMORY>128</MEMORY>
|
||||
<TEMPLATE>
|
||||
EOT
|
||||
|
||||
temp_base64 = Base64::encode64(temp_template)
|
||||
@acl_template_instantiate = "TEMPLATE:#{temp_base64}:INSTANTIATE:0:1:1"
|
||||
end
|
||||
|
||||
it "should check default quotas" do
|
||||
quota1 = @quota.get_quota(@uid1)
|
||||
quota1[:uid].should eql(0)
|
||||
quota1[:num_vms].should eql(nil)
|
||||
quota1[:cpu].should eql(nil)
|
||||
quota1[:memory].should eql(nil)
|
||||
quota1[:storage].should eql(nil)
|
||||
end
|
||||
|
||||
it "should check default usage cache" do
|
||||
usage1cache = @quota.get_usage(@uid1)
|
||||
usage1cache[:uid].should eql(0)
|
||||
usage1cache[:num_vms].should eql(nil)
|
||||
usage1cache[:cpu].should eql(nil)
|
||||
usage1cache[:memory].should eql(nil)
|
||||
usage1cache[:storage].should eql(nil)
|
||||
end
|
||||
|
||||
it "should check default cache (force)" do
|
||||
usage1force = @quota.get_usage(@uid1, nil, true)
|
||||
usage1force[:uid].should eql(0)
|
||||
usage1force[:num_vms].should eql(nil)
|
||||
usage1force[:cpu].should eql(nil)
|
||||
usage1force[:memory].should eql(nil)
|
||||
usage1force[:storage].should eql(nil)
|
||||
end
|
||||
|
||||
it "should authorize the user because there is no quota defined" do
|
||||
@quota.authorize(@uid1, @acl_vm_create).should eql(false)
|
||||
@quota.authorize(@uid1, @acl_image_create).should eql(false)
|
||||
@quota.authorize(@uid1, @acl_template_instantiate).should eql(false)
|
||||
end
|
||||
|
||||
it "should add a new VM" do
|
||||
values = {
|
||||
:cpu => 2,
|
||||
:memory => 128,
|
||||
:uid => 2,
|
||||
:gid => 4,
|
||||
}
|
||||
|
||||
@mock_client.add_vm(0, values)
|
||||
end
|
||||
|
||||
it "should check the usage cache is not updated" do
|
||||
usage1cache = @quota.get_usage(@uid1)
|
||||
usage1cache[:uid].should eql(0)
|
||||
usage1cache[:num_vms].should eql(nil)
|
||||
usage1cache[:cpu].should eql(nil)
|
||||
usage1cache[:memory].should eql(nil)
|
||||
usage1cache[:storage].should eql(nil)
|
||||
end
|
||||
|
||||
it "should check the cache (force)" do
|
||||
usage1force = @quota.get_usage(@uid1, nil, true)
|
||||
usage1force[:uid].should eql(0)
|
||||
usage1force[:num_vms].should eql(1)
|
||||
usage1force[:cpu].should eql(2.0)
|
||||
usage1force[:memory].should eql(128)
|
||||
usage1force[:storage].should eql(nil)
|
||||
end
|
||||
|
||||
it "should check the usage cache is updated and contains the last usage" do
|
||||
usage1cache = @quota.get_usage(@uid1)
|
||||
usage1cache[:uid].should eql(0)
|
||||
usage1cache[:num_vms].should eql(1)
|
||||
usage1cache[:cpu].should eql(2.0)
|
||||
usage1cache[:memory].should eql(128)
|
||||
usage1cache[:storage].should eql(nil)
|
||||
end
|
||||
|
||||
it "should add a new Image" do
|
||||
values = {
|
||||
:uid => 2,
|
||||
:gid => 4,
|
||||
:size => 1000
|
||||
}
|
||||
|
||||
@mock_client.add_image(0, values)
|
||||
end
|
||||
|
||||
it "should check the usage cache is not updated" do
|
||||
usage1cache = @quota.get_usage(@uid1)
|
||||
usage1cache[:uid].should eql(0)
|
||||
usage1cache[:num_vms].should eql(1)
|
||||
usage1cache[:cpu].should eql(2.0)
|
||||
usage1cache[:memory].should eql(128)
|
||||
usage1cache[:storage].should eql(nil)
|
||||
end
|
||||
|
||||
it "should check the cache (force)" do
|
||||
usage1force = @quota.get_usage(@uid1, nil, true)
|
||||
usage1force[:uid].should eql(0)
|
||||
usage1force[:num_vms].should eql(1)
|
||||
usage1force[:cpu].should eql(2.0)
|
||||
usage1force[:memory].should eql(128)
|
||||
usage1force[:storage].should eql(1000)
|
||||
end
|
||||
|
||||
it "should check the usage cache is updated and contains the last usage" do
|
||||
usage1cache = @quota.get_usage(@uid1)
|
||||
usage1cache[:uid].should eql(0)
|
||||
usage1cache[:num_vms].should eql(1)
|
||||
usage1cache[:cpu].should eql(2.0)
|
||||
usage1cache[:memory].should eql(128)
|
||||
usage1cache[:storage].should eql(1000)
|
||||
end
|
||||
|
||||
it "should add a second VM" do
|
||||
values = {
|
||||
:cpu => 2,
|
||||
:memory => 128,
|
||||
:uid => 2,
|
||||
:gid => 4,
|
||||
}
|
||||
|
||||
@mock_client.add_vm(1, values)
|
||||
end
|
||||
|
||||
it "should check the usage cache is not updated" do
|
||||
usage1cache = @quota.get_usage(@uid1)
|
||||
usage1cache[:uid].should eql(0)
|
||||
usage1cache[:num_vms].should eql(1)
|
||||
usage1cache[:cpu].should eql(2.0)
|
||||
usage1cache[:memory].should eql(128)
|
||||
usage1cache[:storage].should eql(1000)
|
||||
end
|
||||
|
||||
it "should check the cache (force)" do
|
||||
usage1force = @quota.get_usage(@uid1, nil, true)
|
||||
usage1force[:uid].should eql(0)
|
||||
usage1force[:num_vms].should eql(1*2)
|
||||
usage1force[:cpu].should eql(2.0*2)
|
||||
usage1force[:memory].should eql(128*2)
|
||||
usage1force[:storage].should eql(1000)
|
||||
end
|
||||
|
||||
it "should check the usage cache is updated and contains the last usage" do
|
||||
usage1cache = @quota.get_usage(@uid1)
|
||||
usage1cache[:uid].should eql(0)
|
||||
usage1cache[:num_vms].should eql(1*2)
|
||||
usage1cache[:cpu].should eql(2.0*2)
|
||||
usage1cache[:memory].should eql(128*2)
|
||||
usage1cache[:storage].should eql(1000)
|
||||
end
|
||||
|
||||
it "should add a second Image" do
|
||||
values = {
|
||||
:uid => 2,
|
||||
:gid => 4,
|
||||
:size => 1000
|
||||
}
|
||||
|
||||
@mock_client.add_image(1, values)
|
||||
end
|
||||
|
||||
it "should check the usage cache is not updated" do
|
||||
usage1cache = @quota.get_usage(@uid1)
|
||||
usage1cache[:uid].should eql(0)
|
||||
usage1cache[:num_vms].should eql(1*2)
|
||||
usage1cache[:cpu].should eql(2.0*2)
|
||||
usage1cache[:memory].should eql(128*2)
|
||||
usage1cache[:storage].should eql(1000)
|
||||
end
|
||||
|
||||
it "should check the cache (force)" do
|
||||
usage1force = @quota.get_usage(@uid1, nil, true)
|
||||
usage1force[:uid].should eql(0)
|
||||
usage1force[:num_vms].should eql(1*2)
|
||||
usage1force[:cpu].should eql(2.0*2)
|
||||
usage1force[:memory].should eql(128*2)
|
||||
usage1force[:storage].should eql(1000*2)
|
||||
end
|
||||
|
||||
it "should check the usage cache is updated and contains the last usage" do
|
||||
usage1cache = @quota.get_usage(@uid1)
|
||||
usage1cache[:uid].should eql(0)
|
||||
usage1cache[:num_vms].should eql(1*2)
|
||||
usage1cache[:cpu].should eql(2.0*2)
|
||||
usage1cache[:memory].should eql(128*2)
|
||||
usage1cache[:storage].should eql(1000*2)
|
||||
end
|
||||
|
||||
it "should add a new quota and check it" do
|
||||
@quota.set_quota(@uid1, @quota1)
|
||||
|
||||
quota = @quota.get_quota(@uid1)
|
||||
@quota1.each{ |key,value|
|
||||
quota[key].should eql(value)
|
||||
}
|
||||
end
|
||||
|
||||
it "should not authorize the user because the vm quota is spent" do
|
||||
err_msg = "CPU quota exceeded (Quota: 2.4, Used: 4.0, Asked: 2.0)."
|
||||
@quota.authorize(@uid1, @acl_vm_create).should eql(err_msg)
|
||||
@quota.authorize(@uid1, @acl_template_instantiate).should eql(err_msg)
|
||||
|
||||
@quota.authorize(@uid1, @acl_image_create).should eql(false)
|
||||
end
|
||||
|
||||
it "should add a new quota for another user and check it" do
|
||||
@quota.set_quota(@uid2, @quota2)
|
||||
|
||||
quota = @quota.get_quota(@uid2)
|
||||
@quota2.each{ |key,value|
|
||||
quota[key].should eql(value)
|
||||
}
|
||||
end
|
||||
|
||||
it "should list all the defined quotas" do
|
||||
quotas = @quota.get_quota
|
||||
quotas.each { |quota|
|
||||
if quota[:uid] == @uid1
|
||||
@quota1.each{ |key,value|
|
||||
quota[key].should eql(value)
|
||||
}
|
||||
elsif quota[:uid] == @uid2
|
||||
@quota2.each{ |key,value|
|
||||
quota[key].should eql(value)
|
||||
}
|
||||
end
|
||||
}
|
||||
|
||||
end
|
||||
|
||||
it "should update the first user quota and check it" do
|
||||
new_quota = Hash.new
|
||||
@quota1.each { |key,value|
|
||||
new_quota[key] = value*3
|
||||
}
|
||||
|
||||
@quota.set_quota(@uid1, new_quota)
|
||||
|
||||
quota = @quota.get_quota(@uid1)
|
||||
new_quota.each{ |key,value|
|
||||
quota[key] == value
|
||||
}
|
||||
end
|
||||
|
||||
it "should authorize the user because the quota is not spent" do
|
||||
@quota.authorize(@uid1, @acl_vm_create).should eql(false)
|
||||
@quota.authorize(@uid1, @acl_image_create).should eql(false)
|
||||
@quota.authorize(@uid1, @acl_template_instantiate).should eql(false)
|
||||
end
|
||||
|
||||
it "should update the first user quota and check it" do
|
||||
new_quota = {
|
||||
:storage => 0
|
||||
}
|
||||
|
||||
@quota.set_quota(@uid1, new_quota)
|
||||
|
||||
quota = @quota.get_quota(@uid1)
|
||||
|
||||
quota[:storage].should eql(new_quota[:storage])
|
||||
end
|
||||
|
||||
it "should not authorize the user because the image quota is spent" do
|
||||
@quota.authorize(@uid1, @acl_vm_create).should eql(false)
|
||||
@quota.authorize(@uid1, @acl_template_instantiate).should eql(false)
|
||||
|
||||
err_msg = "STORAGE quota exceeded (Quota: 0, Used: 2000, Asked: 1474)."
|
||||
@quota.authorize(@uid1, @acl_image_create).should eql(err_msg)
|
||||
end
|
||||
|
||||
it "should delete the quota and check it" do
|
||||
@quota.delete_quota(@uid1)
|
||||
|
||||
quota1 = @quota.get_quota(@uid1)
|
||||
quota1[:uid].should eql(0)
|
||||
quota1[:num_vms].should eql(nil)
|
||||
quota1[:cpu].should eql(nil)
|
||||
quota1[:memory].should eql(nil)
|
||||
quota1[:storage].should eql(nil)
|
||||
end
|
||||
|
||||
it "should authorize the user because the quota was deleted" do
|
||||
@quota.authorize(@uid1, @acl_vm_create).should eql(false)
|
||||
@quota.authorize(@uid1, @acl_image_create).should eql(false)
|
||||
@quota.authorize(@uid1, @acl_template_instantiate).should eql(false)
|
||||
end
|
||||
end
|
@ -1,55 +0,0 @@
|
||||
# -------------------------------------------------------------------------- #
|
||||
# Copyright 2002-2011, 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. #
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
class ClientMock
|
||||
def initialize(mock_data)
|
||||
@mock_data=mock_data
|
||||
end
|
||||
|
||||
def search_method(methods, args)
|
||||
keys=methods.keys
|
||||
|
||||
if keys.include? args[0]
|
||||
value=methods[args[0]]
|
||||
if value.class != Hash
|
||||
return value
|
||||
elsif args.length>1
|
||||
return search_method(value, args[1..-1])
|
||||
else
|
||||
nil
|
||||
end
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def call(action, *args)
|
||||
value=search_method(@mock_data, [action]+args.flatten)
|
||||
if value
|
||||
if value.class==Proc
|
||||
value.call(action, args.flatten)
|
||||
else
|
||||
value
|
||||
end
|
||||
else
|
||||
message="Action '#{action}(#{args.join(',')})' not defined"
|
||||
STDERR.puts message
|
||||
OpenNebula::Error.new(message)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1,551 +0,0 @@
|
||||
|
||||
vmpool.info:
|
||||
0: "<VM_POOL>
|
||||
<VM>
|
||||
<ID>
|
||||
0
|
||||
</ID>
|
||||
<UID>
|
||||
0
|
||||
</UID>
|
||||
<USERNAME>
|
||||
jfontan
|
||||
</USERNAME>
|
||||
<NAME>
|
||||
test
|
||||
</NAME>
|
||||
<LAST_POLL>
|
||||
0
|
||||
</LAST_POLL>
|
||||
<STATE>
|
||||
1
|
||||
</STATE>
|
||||
<LCM_STATE>
|
||||
0
|
||||
</LCM_STATE>
|
||||
<STIME>
|
||||
1278433840
|
||||
</STIME>
|
||||
<ETIME>
|
||||
0
|
||||
</ETIME>
|
||||
<DEPLOY_ID/>
|
||||
<MEMORY>
|
||||
0
|
||||
</MEMORY>
|
||||
<CPU>
|
||||
0
|
||||
</CPU>
|
||||
<NET_TX>
|
||||
0
|
||||
</NET_TX>
|
||||
<NET_RX>
|
||||
0
|
||||
</NET_RX>
|
||||
</VM>
|
||||
<VM>
|
||||
<ID>
|
||||
1
|
||||
</ID>
|
||||
<UID>
|
||||
0
|
||||
</UID>
|
||||
<USERNAME>
|
||||
jfontan
|
||||
</USERNAME>
|
||||
<NAME>
|
||||
test
|
||||
</NAME>
|
||||
<LAST_POLL>
|
||||
0
|
||||
</LAST_POLL>
|
||||
<STATE>
|
||||
1
|
||||
</STATE>
|
||||
<LCM_STATE>
|
||||
0
|
||||
</LCM_STATE>
|
||||
<STIME>
|
||||
1278433841
|
||||
</STIME>
|
||||
<ETIME>
|
||||
0
|
||||
</ETIME>
|
||||
<DEPLOY_ID/>
|
||||
<MEMORY>
|
||||
0
|
||||
</MEMORY>
|
||||
<CPU>
|
||||
0
|
||||
</CPU>
|
||||
<NET_TX>
|
||||
0
|
||||
</NET_TX>
|
||||
<NET_RX>
|
||||
0
|
||||
</NET_RX>
|
||||
</VM>
|
||||
</VM_POOL>"
|
||||
1: "<VM_POOL>
|
||||
<VM>
|
||||
<ID>
|
||||
2
|
||||
</ID>
|
||||
<UID>
|
||||
1
|
||||
</UID>
|
||||
<USERNAME>
|
||||
lero
|
||||
</USERNAME>
|
||||
<NAME>
|
||||
test
|
||||
</NAME>
|
||||
<LAST_POLL>
|
||||
0
|
||||
</LAST_POLL>
|
||||
<STATE>
|
||||
1
|
||||
</STATE>
|
||||
<LCM_STATE>
|
||||
0
|
||||
</LCM_STATE>
|
||||
<STIME>
|
||||
1278433868
|
||||
</STIME>
|
||||
<ETIME>
|
||||
0
|
||||
</ETIME>
|
||||
<DEPLOY_ID/>
|
||||
<MEMORY>
|
||||
0
|
||||
</MEMORY>
|
||||
<CPU>
|
||||
0
|
||||
</CPU>
|
||||
<NET_TX>
|
||||
0
|
||||
</NET_TX>
|
||||
<NET_RX>
|
||||
0
|
||||
</NET_RX>
|
||||
</VM>
|
||||
<VM>
|
||||
<ID>
|
||||
3
|
||||
</ID>
|
||||
<UID>
|
||||
1
|
||||
</UID>
|
||||
<USERNAME>
|
||||
lero
|
||||
</USERNAME>
|
||||
<NAME>
|
||||
test
|
||||
</NAME>
|
||||
<LAST_POLL>
|
||||
0
|
||||
</LAST_POLL>
|
||||
<STATE>
|
||||
1
|
||||
</STATE>
|
||||
<LCM_STATE>
|
||||
0
|
||||
</LCM_STATE>
|
||||
<STIME>
|
||||
1278433869
|
||||
</STIME>
|
||||
<ETIME>
|
||||
0
|
||||
</ETIME>
|
||||
<DEPLOY_ID/>
|
||||
<MEMORY>
|
||||
0
|
||||
</MEMORY>
|
||||
<CPU>
|
||||
0
|
||||
</CPU>
|
||||
<NET_TX>
|
||||
0
|
||||
</NET_TX>
|
||||
<NET_RX>
|
||||
0
|
||||
</NET_RX>
|
||||
</VM>
|
||||
</VM_POOL>"
|
||||
vm.info:
|
||||
0: "<VM>
|
||||
<ID>
|
||||
0
|
||||
</ID>
|
||||
<UID>
|
||||
0
|
||||
</UID>
|
||||
<NAME>
|
||||
test
|
||||
</NAME>
|
||||
<LAST_POLL>
|
||||
0
|
||||
</LAST_POLL>
|
||||
<STATE>
|
||||
1
|
||||
</STATE>
|
||||
<LCM_STATE>
|
||||
0
|
||||
</LCM_STATE>
|
||||
<STIME>
|
||||
1278433840
|
||||
</STIME>
|
||||
<ETIME>
|
||||
0
|
||||
</ETIME>
|
||||
<DEPLOY_ID/>
|
||||
<MEMORY>
|
||||
0
|
||||
</MEMORY>
|
||||
<CPU>
|
||||
0
|
||||
</CPU>
|
||||
<NET_TX>
|
||||
0
|
||||
</NET_TX>
|
||||
<NET_RX>
|
||||
0
|
||||
</NET_RX>
|
||||
<TEMPLATE>
|
||||
<CPU>
|
||||
<![CDATA[0.5]]>
|
||||
</CPU>
|
||||
<DISK>
|
||||
<READONLY>
|
||||
<![CDATA[no]]>
|
||||
</READONLY>
|
||||
<SOURCE>
|
||||
<![CDATA[/local/xen/domains/etch/disk.img]]>
|
||||
</SOURCE>
|
||||
<TARGET>
|
||||
<![CDATA[sda]]>
|
||||
</TARGET>
|
||||
</DISK>
|
||||
<DISK>
|
||||
<READONLY>
|
||||
<![CDATA[no]]>
|
||||
</READONLY>
|
||||
<SIZE>
|
||||
<![CDATA[1024]]>
|
||||
</SIZE>
|
||||
<TARGET>
|
||||
<![CDATA[sdb]]>
|
||||
</TARGET>
|
||||
<TYPE>
|
||||
<![CDATA[swap]]>
|
||||
</TYPE>
|
||||
</DISK>
|
||||
<MEMORY>
|
||||
<![CDATA[64]]>
|
||||
</MEMORY>
|
||||
<NAME>
|
||||
<![CDATA[test]]>
|
||||
</NAME>
|
||||
<NIC>
|
||||
<MAC>
|
||||
<![CDATA[00:ff:72:17:20:27]]>
|
||||
</MAC>
|
||||
</NIC>
|
||||
<OS>
|
||||
<INITRD>
|
||||
<![CDATA[/initrd.img]]>
|
||||
</INITRD>
|
||||
<KERNEL>
|
||||
<![CDATA[/vmlinuz]]>
|
||||
</KERNEL>
|
||||
<ROOT>
|
||||
<![CDATA[sda]]>
|
||||
</ROOT>
|
||||
</OS>
|
||||
<VMID>
|
||||
<![CDATA[0]]>
|
||||
</VMID>
|
||||
</TEMPLATE>
|
||||
</VM>"
|
||||
1: "<VM>
|
||||
<ID>
|
||||
1
|
||||
</ID>
|
||||
<UID>
|
||||
0
|
||||
</UID>
|
||||
<NAME>
|
||||
test
|
||||
</NAME>
|
||||
<LAST_POLL>
|
||||
0
|
||||
</LAST_POLL>
|
||||
<STATE>
|
||||
1
|
||||
</STATE>
|
||||
<LCM_STATE>
|
||||
0
|
||||
</LCM_STATE>
|
||||
<STIME>
|
||||
1278433841
|
||||
</STIME>
|
||||
<ETIME>
|
||||
0
|
||||
</ETIME>
|
||||
<DEPLOY_ID/>
|
||||
<MEMORY>
|
||||
0
|
||||
</MEMORY>
|
||||
<CPU>
|
||||
0
|
||||
</CPU>
|
||||
<NET_TX>
|
||||
0
|
||||
</NET_TX>
|
||||
<NET_RX>
|
||||
0
|
||||
</NET_RX>
|
||||
<TEMPLATE>
|
||||
<CPU>
|
||||
<![CDATA[1]]>
|
||||
</CPU>
|
||||
<DISK>
|
||||
<READONLY>
|
||||
<![CDATA[no]]>
|
||||
</READONLY>
|
||||
<SOURCE>
|
||||
<![CDATA[/local/xen/domains/etch/disk.img]]>
|
||||
</SOURCE>
|
||||
<TARGET>
|
||||
<![CDATA[sda]]>
|
||||
</TARGET>
|
||||
</DISK>
|
||||
<DISK>
|
||||
<READONLY>
|
||||
<![CDATA[no]]>
|
||||
</READONLY>
|
||||
<SIZE>
|
||||
<![CDATA[1024]]>
|
||||
</SIZE>
|
||||
<TARGET>
|
||||
<![CDATA[sdb]]>
|
||||
</TARGET>
|
||||
<TYPE>
|
||||
<![CDATA[swap]]>
|
||||
</TYPE>
|
||||
</DISK>
|
||||
<MEMORY>
|
||||
<![CDATA[256]]>
|
||||
</MEMORY>
|
||||
<NAME>
|
||||
<![CDATA[test]]>
|
||||
</NAME>
|
||||
<NIC>
|
||||
<MAC>
|
||||
<![CDATA[00:ff:72:17:20:27]]>
|
||||
</MAC>
|
||||
</NIC>
|
||||
<OS>
|
||||
<INITRD>
|
||||
<![CDATA[/initrd.img]]>
|
||||
</INITRD>
|
||||
<KERNEL>
|
||||
<![CDATA[/vmlinuz]]>
|
||||
</KERNEL>
|
||||
<ROOT>
|
||||
<![CDATA[sda]]>
|
||||
</ROOT>
|
||||
</OS>
|
||||
<VMID>
|
||||
<![CDATA[1]]>
|
||||
</VMID>
|
||||
</TEMPLATE>
|
||||
</VM>"
|
||||
2: "<VM>
|
||||
<ID>
|
||||
2
|
||||
</ID>
|
||||
<UID>
|
||||
1
|
||||
</UID>
|
||||
<NAME>
|
||||
test
|
||||
</NAME>
|
||||
<LAST_POLL>
|
||||
0
|
||||
</LAST_POLL>
|
||||
<STATE>
|
||||
1
|
||||
</STATE>
|
||||
<LCM_STATE>
|
||||
0
|
||||
</LCM_STATE>
|
||||
<STIME>
|
||||
1278433868
|
||||
</STIME>
|
||||
<ETIME>
|
||||
0
|
||||
</ETIME>
|
||||
<DEPLOY_ID/>
|
||||
<MEMORY>
|
||||
0
|
||||
</MEMORY>
|
||||
<CPU>
|
||||
0
|
||||
</CPU>
|
||||
<NET_TX>
|
||||
0
|
||||
</NET_TX>
|
||||
<NET_RX>
|
||||
0
|
||||
</NET_RX>
|
||||
<TEMPLATE>
|
||||
<CPU>
|
||||
<![CDATA[1.5]]>
|
||||
</CPU>
|
||||
<DISK>
|
||||
<READONLY>
|
||||
<![CDATA[no]]>
|
||||
</READONLY>
|
||||
<SOURCE>
|
||||
<![CDATA[/local/xen/domains/etch/disk.img]]>
|
||||
</SOURCE>
|
||||
<TARGET>
|
||||
<![CDATA[sda]]>
|
||||
</TARGET>
|
||||
</DISK>
|
||||
<DISK>
|
||||
<READONLY>
|
||||
<![CDATA[no]]>
|
||||
</READONLY>
|
||||
<SIZE>
|
||||
<![CDATA[1024]]>
|
||||
</SIZE>
|
||||
<TARGET>
|
||||
<![CDATA[sdb]]>
|
||||
</TARGET>
|
||||
<TYPE>
|
||||
<![CDATA[swap]]>
|
||||
</TYPE>
|
||||
</DISK>
|
||||
<MEMORY>
|
||||
<![CDATA[512]]>
|
||||
</MEMORY>
|
||||
<NAME>
|
||||
<![CDATA[test]]>
|
||||
</NAME>
|
||||
<NIC>
|
||||
<MAC>
|
||||
<![CDATA[00:ff:72:17:20:27]]>
|
||||
</MAC>
|
||||
</NIC>
|
||||
<OS>
|
||||
<INITRD>
|
||||
<![CDATA[/initrd.img]]>
|
||||
</INITRD>
|
||||
<KERNEL>
|
||||
<![CDATA[/vmlinuz]]>
|
||||
</KERNEL>
|
||||
<ROOT>
|
||||
<![CDATA[sda]]>
|
||||
</ROOT>
|
||||
</OS>
|
||||
<VMID>
|
||||
<![CDATA[2]]>
|
||||
</VMID>
|
||||
</TEMPLATE>
|
||||
</VM>"
|
||||
3: "<VM>
|
||||
<ID>
|
||||
3
|
||||
</ID>
|
||||
<UID>
|
||||
1
|
||||
</UID>
|
||||
<NAME>
|
||||
test
|
||||
</NAME>
|
||||
<LAST_POLL>
|
||||
0
|
||||
</LAST_POLL>
|
||||
<STATE>
|
||||
1
|
||||
</STATE>
|
||||
<LCM_STATE>
|
||||
0
|
||||
</LCM_STATE>
|
||||
<STIME>
|
||||
1278433869
|
||||
</STIME>
|
||||
<ETIME>
|
||||
0
|
||||
</ETIME>
|
||||
<DEPLOY_ID/>
|
||||
<MEMORY>
|
||||
0
|
||||
</MEMORY>
|
||||
<CPU>
|
||||
0
|
||||
</CPU>
|
||||
<NET_TX>
|
||||
0
|
||||
</NET_TX>
|
||||
<NET_RX>
|
||||
0
|
||||
</NET_RX>
|
||||
<TEMPLATE>
|
||||
<CPU>
|
||||
<![CDATA[2]]>
|
||||
</CPU>
|
||||
<DISK>
|
||||
<READONLY>
|
||||
<![CDATA[no]]>
|
||||
</READONLY>
|
||||
<SOURCE>
|
||||
<![CDATA[/local/xen/domains/etch/disk.img]]>
|
||||
</SOURCE>
|
||||
<TARGET>
|
||||
<![CDATA[sda]]>
|
||||
</TARGET>
|
||||
</DISK>
|
||||
<DISK>
|
||||
<READONLY>
|
||||
<![CDATA[no]]>
|
||||
</READONLY>
|
||||
<SIZE>
|
||||
<![CDATA[1024]]>
|
||||
</SIZE>
|
||||
<TARGET>
|
||||
<![CDATA[sdb]]>
|
||||
</TARGET>
|
||||
<TYPE>
|
||||
<![CDATA[swap]]>
|
||||
</TYPE>
|
||||
</DISK>
|
||||
<MEMORY>
|
||||
<![CDATA[1024]]>
|
||||
</MEMORY>
|
||||
<NAME>
|
||||
<![CDATA[test]]>
|
||||
</NAME>
|
||||
<NIC>
|
||||
<MAC>
|
||||
<![CDATA[00:ff:72:17:20:27]]>
|
||||
</MAC>
|
||||
</NIC>
|
||||
<OS>
|
||||
<INITRD>
|
||||
<![CDATA[/initrd.img]]>
|
||||
</INITRD>
|
||||
<KERNEL>
|
||||
<![CDATA[/vmlinuz]]>
|
||||
</KERNEL>
|
||||
<ROOT>
|
||||
<![CDATA[sda]]>
|
||||
</ROOT>
|
||||
</OS>
|
||||
<VMID>
|
||||
<![CDATA[3]]>
|
||||
</VMID>
|
||||
</TEMPLATE>
|
||||
</VM>"
|
@ -1,77 +0,0 @@
|
||||
# -------------------------------------------------------------------------- #
|
||||
# Copyright 2002-2011, 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 'spec_common'
|
||||
|
||||
require 'client_mock'
|
||||
require 'one_usage'
|
||||
|
||||
describe "OneUsage" do
|
||||
before(:all) do
|
||||
mock_data=YAML::load(File.read('oca_vms.yaml'))
|
||||
client=ClientMock.new(mock_data)
|
||||
@one_usage=OneUsage.new(client)
|
||||
end
|
||||
|
||||
it "should get information about vm users" do
|
||||
@one_usage.update_user(0)
|
||||
vms=@one_usage.vms(0)
|
||||
|
||||
vms.size.should == 2
|
||||
vms[0].cpu.should == 0.5
|
||||
vms[0].memory.should == 64
|
||||
vms[1].cpu.should == 1.0
|
||||
vms[1].memory.should == 256
|
||||
|
||||
usage=@one_usage.total(0)
|
||||
usage.cpu.should == 1.5
|
||||
usage.memory.should == 64+256
|
||||
|
||||
@one_usage.update_user(1)
|
||||
vms=@one_usage.vms(1)
|
||||
|
||||
vms.size.should == 2
|
||||
vms[2].cpu.should == 1.5
|
||||
vms[2].memory.should == 512
|
||||
vms[3].cpu.should == 2.0
|
||||
vms[3].memory.should == 1024
|
||||
|
||||
usage=@one_usage.total(1)
|
||||
usage.cpu.should == 3.5
|
||||
usage.memory.should == 512+1024
|
||||
end
|
||||
|
||||
it "should update information" do
|
||||
vms=@one_usage.vms(1)
|
||||
vms[4]=VmUsage.new(4.0, 2048)
|
||||
|
||||
usage=@one_usage.total(1)
|
||||
usage.cpu.should == 1.5 + 2.0 + 4.0
|
||||
usage.memory.should == 512+1024+2048
|
||||
|
||||
vms.delete(3)
|
||||
usage=@one_usage.total(1)
|
||||
usage.cpu.should == 1.5 + 4.0
|
||||
usage.memory.should == 512+2048
|
||||
|
||||
@one_usage.update_user(1)
|
||||
usage=@one_usage.total(1)
|
||||
usage.cpu.should == 1.5 + 2.0
|
||||
usage.memory.should == 512+1024
|
||||
end
|
||||
end
|
@ -1,97 +0,0 @@
|
||||
# -------------------------------------------------------------------------- #
|
||||
# Copyright 2002-2011, 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 'spec_common'
|
||||
|
||||
require 'client_mock'
|
||||
require 'quota'
|
||||
|
||||
def check_quota(uid, cpu, memory, num_vms)
|
||||
quota=@quota.get(uid)
|
||||
quota.should_not == nil
|
||||
quota[:cpu].should == cpu
|
||||
quota[:memory].should == memory
|
||||
quota[:num_vms].should == num_vms
|
||||
end
|
||||
|
||||
describe 'Quota' do
|
||||
before(:all) do
|
||||
@db=Sequel.sqlite
|
||||
mock_data=YAML::load(File.read('oca_vms.yaml'))
|
||||
client=ClientMock.new(mock_data)
|
||||
@quota=Quota.new(@db, client)
|
||||
end
|
||||
|
||||
it 'should create table' do
|
||||
@db.table_exists?(:quotas).should == true
|
||||
|
||||
schema=@db.schema(:quotas)
|
||||
check_column(schema, :uid)
|
||||
check_column(schema, :cpu)
|
||||
check_column(schema, :memory)
|
||||
check_column(schema, :num_vms)
|
||||
end
|
||||
|
||||
it 'should let add and retrieve quotas' do
|
||||
@quota.set(0, 10.0, 1024, 10)
|
||||
@quota.set(1, 20.0, 2048, 20)
|
||||
@quota.set(2, 40.0, 4096, 40)
|
||||
|
||||
check_quota(0, 10.0, 1024, 10)
|
||||
check_quota(1, 20.0, 2048, 20)
|
||||
check_quota(2, 40.0, 4096, 40)
|
||||
|
||||
@quota.get(3).should == @quota.defaults
|
||||
end
|
||||
|
||||
it 'should check for quotas' do
|
||||
@quota.update(0)
|
||||
@quota.update(1)
|
||||
@quota.check(0).should == false
|
||||
@quota.check(1).should == false
|
||||
|
||||
vms=@quota.get_user(0)
|
||||
vms[5]=VmUsage.new(40.0, 8192)
|
||||
|
||||
vms=@quota.get_user(1)
|
||||
vms[6]=VmUsage.new(40.0, 8192)
|
||||
|
||||
@quota.check(0).class.should == String
|
||||
@quota.check(1).class.should == String
|
||||
|
||||
@quota.update(0)
|
||||
@quota.update(1)
|
||||
@quota.check(0).should == false
|
||||
@quota.check(1).should == false
|
||||
end
|
||||
|
||||
it 'should let update limits' do
|
||||
@quota.set(0, nil, nil, nil)
|
||||
check_quota(0, nil, nil, nil)
|
||||
end
|
||||
|
||||
it 'should understand unlimited quotas' do
|
||||
vms=@quota.get_user(0)
|
||||
vms[7]=VmUsage.new(9999999999.0, 99999999999)
|
||||
@quota.check(0).should == false
|
||||
@quota.check(0, VmUsage.new(999999999.0, 99999999)).should == false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
@ -1,101 +0,0 @@
|
||||
# -------------------------------------------------------------------------- #
|
||||
# Copyright 2002-2011, 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 'spec_common'
|
||||
|
||||
require 'client_mock'
|
||||
require 'simple_permissions'
|
||||
|
||||
CONF=<<EOT
|
||||
:database: sqlite://auth.db
|
||||
:authentication: simple
|
||||
:quota:
|
||||
:enabled: false
|
||||
:defaults:
|
||||
:cpu: 10.0
|
||||
:memory: 1048576
|
||||
EOT
|
||||
|
||||
def gen_tokens(user_, action_, options={})
|
||||
user=user_.to_s
|
||||
action=action_.to_s.upcase
|
||||
|
||||
options={
|
||||
:vm => true,
|
||||
:host => true
|
||||
}.merge!(options)
|
||||
|
||||
pub=(options[:public] ? '1' : '0')
|
||||
id=(options[:id] ? options[:id].to_s : '1')
|
||||
#owner=(options[:owner] ? options[:owner].to_s : '1')
|
||||
|
||||
if action=='CREATE'
|
||||
vmowner='-'
|
||||
vmid='-'
|
||||
else
|
||||
vmowner=user
|
||||
vmid=user
|
||||
end
|
||||
|
||||
tokens=[]
|
||||
tokens<<"VM:#{vmid}:#{action}:#{vmowner}:#{pub}" if options[:vm]
|
||||
tokens+=[
|
||||
"NET:#{id}:#{action}:#{user}:#{pub}",
|
||||
"IMAGE:#{id}:#{action}:#{user}:#{pub}"
|
||||
]
|
||||
tokens<<"HOST:#{id}:#{action}:#{user}:#{pub}" if options[:host]
|
||||
|
||||
tokens
|
||||
end
|
||||
|
||||
describe SimplePermissions do
|
||||
before(:all) do
|
||||
@db=Sequel.sqlite
|
||||
mock_data=YAML::load(File.read('oca_vms.yaml'))
|
||||
client=ClientMock.new(mock_data)
|
||||
@perm=SimplePermissions.new(@db, client, YAML::load(CONF))
|
||||
end
|
||||
|
||||
it 'should let root manage everything' do
|
||||
@perm.auth(0, gen_tokens(1, :create)).should == true
|
||||
@perm.auth(0, gen_tokens(1, :delete)).should == true
|
||||
@perm.auth(0, gen_tokens(1, :manage)).should == true
|
||||
@perm.auth(0, gen_tokens(1, :use)).should == true
|
||||
end
|
||||
|
||||
it 'should let anyone use public objects' do
|
||||
@perm.auth(2, gen_tokens(1, :delete, :public => true)).
|
||||
should_not == true
|
||||
@perm.auth(2, gen_tokens(1, :manage, :public => true)).
|
||||
should_not == true
|
||||
|
||||
# take out vm create (the first token) as it can not be "used" by
|
||||
# other users even if public
|
||||
@perm.auth(2, gen_tokens(1, :use, :public => true, :vm => false)).
|
||||
should == true
|
||||
end
|
||||
|
||||
it 'should let users use their own objects' do
|
||||
@perm.auth(1, gen_tokens(1, :create, :host => false)).should == true
|
||||
@perm.auth(1, gen_tokens(1, :delete, :host => false)).should == true
|
||||
@perm.auth(1, gen_tokens(1, :manage, :host => false)).should == true
|
||||
@perm.auth(1, gen_tokens(1, :use)).should == true
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -127,6 +127,7 @@ module CLIHelper
|
||||
end
|
||||
|
||||
def default(*args)
|
||||
args.map!{|a| a.to_sym }
|
||||
@default_columns=args
|
||||
end
|
||||
|
||||
@ -194,7 +195,7 @@ module CLIHelper
|
||||
size=@columns[field][:size]
|
||||
return "%#{minus}#{size}.#{size}s" % [ data.to_s ]
|
||||
else
|
||||
exit -1, "Column not defined"
|
||||
exit -1, "Column #{field} not defined."
|
||||
end
|
||||
end
|
||||
|
||||
@ -222,7 +223,7 @@ module CLIHelper
|
||||
if @columns[c]
|
||||
format_str(c, c.to_s)
|
||||
else
|
||||
puts "Column not defined"
|
||||
puts "Column #{c} not defined."
|
||||
exit -1
|
||||
end
|
||||
}.compact.join(' ')
|
||||
|
@ -223,7 +223,7 @@ EOT
|
||||
|
||||
@opts.each{ |o|
|
||||
str = ""
|
||||
str << o[:short] if o[:short]
|
||||
str << o[:short].split(' ').first << ', ' if o[:short]
|
||||
str << o[:large]
|
||||
|
||||
printf opt_format, str, o[:description]
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
:NAME:
|
||||
:desc: Name of the Image
|
||||
:size: 16
|
||||
:size: 12
|
||||
:left: true
|
||||
|
||||
:USER:
|
||||
@ -18,6 +18,10 @@
|
||||
:size: 8
|
||||
:left: true
|
||||
|
||||
:SIZE:
|
||||
:desc: Size of the Image
|
||||
:size: 7
|
||||
|
||||
:TYPE:
|
||||
:desc: Type of the Image
|
||||
:size: 4
|
||||
@ -47,6 +51,7 @@
|
||||
- :USER
|
||||
- :GROUP
|
||||
- :NAME
|
||||
- :SIZE
|
||||
- :TYPE
|
||||
- :REGTIME
|
||||
- :PUBLIC
|
||||
|
@ -363,11 +363,11 @@ EOT
|
||||
|
||||
BinarySufix = ["K", "M", "G", "T" ]
|
||||
|
||||
def OpenNebulaHelper.unit_to_str(value, options)
|
||||
def OpenNebulaHelper.unit_to_str(value, options, unit="K")
|
||||
if options[:kilobytes]
|
||||
value
|
||||
else
|
||||
i=0
|
||||
i=BinarySufix.index(unit).to_i
|
||||
|
||||
while value > 1024 && i < 3 do
|
||||
value /= 1024.0
|
||||
|
@ -57,10 +57,10 @@ class OneImageHelper < OpenNebulaHelper::OneHelper
|
||||
str_h1="%-80s"
|
||||
|
||||
CLIHelper.print_header(str_h1 % "IMAGE #{image['ID']} INFORMATION")
|
||||
puts str % ["ID", image.id.to_s]
|
||||
puts str % ["ID", image.id.to_s]
|
||||
puts str % ["NAME", image.name]
|
||||
puts str % ["USER", image['UNAME']]
|
||||
puts str % ["GROUP", image['GNAME']]
|
||||
puts str % ["GROUP",image['GNAME']]
|
||||
puts str % ["TYPE", image.type_str]
|
||||
puts str % ["REGISTER TIME",
|
||||
OpenNebulaHelper.time_to_str(image['REGTIME'])]
|
||||
@ -68,7 +68,8 @@ class OneImageHelper < OpenNebulaHelper::OneHelper
|
||||
OpenNebulaHelper.boolean_to_str(image['PUBLIC'])]
|
||||
puts str % ["PERSISTENT",
|
||||
OpenNebulaHelper.boolean_to_str(image["PERSISTENT"])]
|
||||
puts str % ["SOURCE", image['SOURCE']]
|
||||
puts str % ["SOURCE",image['SOURCE']]
|
||||
puts str % ["SIZE", image['SIZE']]
|
||||
puts str % ["STATE", image.short_state_str]
|
||||
puts str % ["RUNNING_VMS", image['RUNNING_VMS']]
|
||||
puts
|
||||
@ -85,7 +86,7 @@ class OneImageHelper < OpenNebulaHelper::OneHelper
|
||||
d["ID"]
|
||||
end
|
||||
|
||||
column :NAME, "Name of the Image", :left, :size=>15 do |d|
|
||||
column :NAME, "Name of the Image", :left, :size=>12 do |d|
|
||||
d["NAME"]
|
||||
end
|
||||
|
||||
@ -127,7 +128,12 @@ class OneImageHelper < OpenNebulaHelper::OneHelper
|
||||
d['RUNNING_VMS']
|
||||
end
|
||||
|
||||
default :ID, :USER, :GROUP, :NAME, :TYPE, :REGTIME, :PUBLIC,
|
||||
column :SIZE, "Size of the image",
|
||||
:size=>7 do |d|
|
||||
OpenNebulaHelper.unit_to_str(d['SIZE'].to_i,options,"M")
|
||||
end
|
||||
|
||||
default :ID, :USER, :GROUP, :NAME, :SIZE, :TYPE, :REGTIME, :PUBLIC,
|
||||
:PERSISTENT , :STAT, :RVMS
|
||||
end
|
||||
|
||||
|
@ -37,7 +37,7 @@ class OneUserHelper < OpenNebulaHelper::OneHelper
|
||||
return -1, "Can not read file: #{arg}"
|
||||
end
|
||||
else
|
||||
if options[:plain]
|
||||
if options[:plain] || options[:ssh] || options[:x509]
|
||||
password = arg.gsub(/\s/, '')
|
||||
else
|
||||
password = Digest::SHA1.hexdigest(arg)
|
||||
@ -49,9 +49,11 @@ class OneUserHelper < OpenNebulaHelper::OneHelper
|
||||
|
||||
def password(options)
|
||||
if options[:ssh]
|
||||
require 'ssh_auth'
|
||||
if !options[:key]
|
||||
return -1, "You have to specify the --key option"
|
||||
end
|
||||
|
||||
options[:key] ||= ENV['HOME']+'/.ssh/id_rsa'
|
||||
require 'ssh_auth'
|
||||
|
||||
begin
|
||||
sshauth = SshAuth.new(:private_key=>options[:key])
|
||||
@ -61,10 +63,14 @@ class OneUserHelper < OpenNebulaHelper::OneHelper
|
||||
|
||||
return 0, sshauth.public_key
|
||||
elsif options[:x509]
|
||||
require 'x509_auth'
|
||||
|
||||
options[:cert] ||= ENV['X509_USER_CERT']
|
||||
|
||||
if !options[:cert]
|
||||
return -1, "You have to specify the --cert option"
|
||||
end
|
||||
|
||||
require 'x509_auth'
|
||||
|
||||
begin
|
||||
cert = [File.read(options[:cert])]
|
||||
x509auth = X509Auth.new(:certs_pem=>cert)
|
||||
|
@ -104,7 +104,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do
|
||||
:name => "time",
|
||||
:large => "--time x",
|
||||
:format => Integer,
|
||||
:description => "Token duration in hours, (default 1)"
|
||||
:description => "Token duration in seconds, defaults to 3600 (1 h)"
|
||||
}
|
||||
|
||||
create_options = [READ_FILE, PLAIN, SSH, X509, KEY, CERT]
|
||||
@ -139,20 +139,21 @@ cmd=CommandParser::CmdParser.new(ARGV) do
|
||||
oneuser create my_user my_password
|
||||
oneuser create my_user /tmp/mypass -r
|
||||
oneuser create my_user --ssh --key /tmp/id_rsa
|
||||
oneuser create my_user --ssh -r /tmp/public_key
|
||||
oneuser create my_user --x509 --cert /tmp/my_cert.pem
|
||||
EOT
|
||||
|
||||
command :create, create_desc, :username, [:password, nil],
|
||||
:options=>create_options do
|
||||
if options[:ssh] or options[:x509]
|
||||
if args[1]
|
||||
pass = args[1]
|
||||
else
|
||||
rc = helper.password(options)
|
||||
if rc.first == 0
|
||||
pass = rc[1]
|
||||
else
|
||||
exit_with_code *rc
|
||||
end
|
||||
else
|
||||
pass = args[1]
|
||||
end
|
||||
|
||||
helper.create_resource(options) do |user|
|
||||
@ -175,6 +176,27 @@ cmd=CommandParser::CmdParser.new(ARGV) do
|
||||
helper.login(args[0], options)
|
||||
end
|
||||
|
||||
key_desc = <<-EOT.unindent
|
||||
Shows a public key from a private SSH key. Use it as password
|
||||
for the SSH authentication mechanism.
|
||||
EOT
|
||||
|
||||
command :key, key_desc, :options=>[KEY] do
|
||||
require 'ssh_auth'
|
||||
|
||||
options[:key] ||= ENV['HOME']+'/.ssh/id_rsa'
|
||||
|
||||
begin
|
||||
sshauth = SshAuth.new(:private_key=>options[:key])
|
||||
rescue Exception => e
|
||||
exit_with_code -1, e.message
|
||||
end
|
||||
|
||||
puts sshauth.public_key
|
||||
exit_with_code 0
|
||||
end
|
||||
|
||||
|
||||
delete_desc = <<-EOT.unindent
|
||||
Deletes the given User
|
||||
EOT
|
||||
@ -189,17 +211,17 @@ cmd=CommandParser::CmdParser.new(ARGV) do
|
||||
Changes the given User's password
|
||||
EOT
|
||||
|
||||
command :passwd, passwd_desc, :userid, :password,
|
||||
command :passwd, passwd_desc, :userid, [:password, nil],
|
||||
:options=>create_options do
|
||||
if options[:ssh] or options[:x509]
|
||||
if args[1]
|
||||
pass = args[1]
|
||||
else
|
||||
rc = helper.password(options)
|
||||
if rc.first == 0
|
||||
pass = rc[1]
|
||||
else
|
||||
exit_with_code *rc
|
||||
end
|
||||
else
|
||||
pass = args[1]
|
||||
end
|
||||
|
||||
helper.perform_action(args[0],options,"Password changed") do |user|
|
||||
|
@ -43,6 +43,7 @@ Image::Image(int _uid,
|
||||
type(OS),
|
||||
regtime(time(0)),
|
||||
source("-"),
|
||||
size_mb(0),
|
||||
state(INIT),
|
||||
running_vms(0)
|
||||
{
|
||||
@ -334,6 +335,7 @@ string& Image::to_xml(string& xml) const
|
||||
"<PERSISTENT>" << persistent_img << "</PERSISTENT>" <<
|
||||
"<REGTIME>" << regtime << "</REGTIME>" <<
|
||||
"<SOURCE>" << source << "</SOURCE>" <<
|
||||
"<SIZE>" << size_mb << "</SIZE>" <<
|
||||
"<STATE>" << state << "</STATE>" <<
|
||||
"<RUNNING_VMS>" << running_vms << "</RUNNING_VMS>" <<
|
||||
obj_template->to_xml(template_xml) <<
|
||||
@ -374,6 +376,7 @@ int Image::from_xml(const string& xml)
|
||||
rc += xpath(regtime, "/IMAGE/REGTIME", 0);
|
||||
|
||||
rc += xpath(source, "/IMAGE/SOURCE", "not_found");
|
||||
rc += xpath(size_mb, "/IMAGE/SIZE", 0);
|
||||
rc += xpath(int_state, "/IMAGE/STATE", 0);
|
||||
rc += xpath(running_vms, "/IMAGE/RUNNING_VMS", -1);
|
||||
|
||||
|
@ -91,6 +91,7 @@ void ImageManagerDriver::protocol(
|
||||
int id;
|
||||
Image * image;
|
||||
string source;
|
||||
unsigned int size_mb;
|
||||
|
||||
string info;
|
||||
|
||||
@ -130,6 +131,27 @@ void ImageManagerDriver::protocol(
|
||||
else
|
||||
return;
|
||||
|
||||
// Parse driver message for CP, MV and MKFS
|
||||
// <CP|MV|MKFS> SUCESS IMAGE_ID SOURCE SIZE
|
||||
if ( (result == "SUCCESS") && (action != "RM") )
|
||||
{
|
||||
if ( is.good() )
|
||||
{
|
||||
is >> source >> ws;
|
||||
}
|
||||
|
||||
if ( is.good() )
|
||||
{
|
||||
is >> size_mb >> ws;
|
||||
}
|
||||
|
||||
if ( is.fail() )
|
||||
{
|
||||
result = "FAILURE";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get the image from the pool
|
||||
image = ipool->get(id,true);
|
||||
|
||||
@ -143,19 +165,9 @@ void ImageManagerDriver::protocol(
|
||||
{
|
||||
if ( result == "SUCCESS" )
|
||||
{
|
||||
string source;
|
||||
|
||||
if ( is.good() )
|
||||
{
|
||||
is >> source >> ws;
|
||||
}
|
||||
|
||||
if ( is.fail() )
|
||||
{
|
||||
goto error_cp;
|
||||
}
|
||||
|
||||
image->set_source(source);
|
||||
image->set_size(size_mb);
|
||||
|
||||
image->set_state(Image::READY);
|
||||
|
||||
ipool->update(image);
|
||||
@ -173,22 +185,13 @@ void ImageManagerDriver::protocol(
|
||||
{
|
||||
if (image->get_source() == "-")
|
||||
{
|
||||
string source;
|
||||
|
||||
if ( is.good() )
|
||||
{
|
||||
is >> source >> ws;
|
||||
}
|
||||
|
||||
if ( is.fail() )
|
||||
{
|
||||
goto error_mv;
|
||||
}
|
||||
|
||||
image->set_source(source);
|
||||
}
|
||||
|
||||
image->set_size(size_mb);
|
||||
|
||||
image->set_state(Image::READY);
|
||||
|
||||
ipool->update(image);
|
||||
|
||||
NebulaLog::log("ImM", Log::INFO, "Image saved and ready to use.");
|
||||
@ -202,19 +205,9 @@ void ImageManagerDriver::protocol(
|
||||
{
|
||||
if ( result == "SUCCESS" )
|
||||
{
|
||||
string source;
|
||||
|
||||
if ( is.good() )
|
||||
{
|
||||
is >> source >> ws;
|
||||
}
|
||||
|
||||
if ( is.fail() )
|
||||
{
|
||||
goto error_mkfs;
|
||||
}
|
||||
|
||||
image->set_source(source);
|
||||
image->set_size(size_mb);
|
||||
|
||||
image->set_state(Image::READY);
|
||||
|
||||
ipool->update(image);
|
||||
|
@ -52,6 +52,9 @@ http://*)
|
||||
;;
|
||||
esac
|
||||
|
||||
# ---------------- Get the size of the image & fix perms ------------
|
||||
exec_and_log "chmod 0660 $DST"
|
||||
|
||||
echo "$DST"
|
||||
SIZE=`fs_du $DST`
|
||||
|
||||
echo "$DST $SIZE"
|
||||
|
@ -39,3 +39,16 @@ EOF
|
||||
|
||||
echo "$IMAGE_REPOSITORY_PATH/`echo $CANONICAL_MD5 | cut -d ' ' -f1`"
|
||||
}
|
||||
|
||||
function fs_du {
|
||||
|
||||
SIZE=`$DU -m $1 2>/dev/null`
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
SIZE=0
|
||||
else
|
||||
SIZE=`echo $SIZE | cut -f1 -d' '`
|
||||
fi
|
||||
|
||||
echo "$SIZE"
|
||||
}
|
||||
|
@ -65,4 +65,7 @@ exec_and_log "$MKFS -t $FSTYPE $OPTS $DST" \
|
||||
|
||||
exec_and_log "chmod 0660 $DST"
|
||||
|
||||
echo "$DST"
|
||||
# ---------------- Get the size of the image ------------
|
||||
SIZE=`fs_du $DST`
|
||||
|
||||
echo "$DST $SIZE"
|
||||
|
@ -64,4 +64,7 @@ esac
|
||||
|
||||
exec_and_log "chmod 0660 $DST"
|
||||
|
||||
echo "$DST"
|
||||
# ---------------- Get the size of the image ------------
|
||||
SIZE=`fs_du $DST`
|
||||
|
||||
echo "$DST $SIZE"
|
||||
|
@ -20,6 +20,7 @@ BASH=/bin/bash
|
||||
CUT=cut
|
||||
DATE=/bin/date
|
||||
DD=/bin/dd
|
||||
DU=/bin/du
|
||||
LVCREATE=/sbin/lvcreate
|
||||
LVREMOVE=/sbin/lvremove
|
||||
LVS=/sbin/lvs
|
||||
|
Loading…
x
Reference in New Issue
Block a user