1
0
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:
Ruben S. Montero 2011-09-02 17:20:25 +02:00
commit a6fff726c4
32 changed files with 1206 additions and 966 deletions

View File

@ -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

View File

@ -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"
#-------------------------------------------------------------------------------

View File

@ -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

View 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

View 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

View File

@ -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:

View 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

View 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>

View 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>

View 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>

View 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

View 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

View 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

View File

@ -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

View File

@ -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>"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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(' ')

View File

@ -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]

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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|

View File

@ -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);

View File

@ -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);

View File

@ -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"

View File

@ -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"
}

View File

@ -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"

View File

@ -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"

View File

@ -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