mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-16 22:50:10 +03:00
feature #788: Refactor Quota class
This commit is contained in:
parent
4df59c6310
commit
a328fd796a
@ -29,6 +29,7 @@ end
|
||||
$: << RUBY_LIB_LOCATION
|
||||
|
||||
require 'scripts_common'
|
||||
require 'opennebula'
|
||||
require 'quota'
|
||||
|
||||
user_id = ARGV.shift
|
||||
@ -49,7 +50,7 @@ quota = Quota.new
|
||||
#OpenNebula.log_debug("quotas: #{quota.get(1)}")
|
||||
|
||||
ARGV.each {|request|
|
||||
rc = quota.check_request(user_id, request)
|
||||
rc = quota.authorize(user_id, request)
|
||||
|
||||
if rc
|
||||
OpenNebula.error_message rc
|
||||
|
@ -1,124 +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 'OpenNebula'
|
||||
|
||||
# This class retrieves and caches vms and its consuption grouped
|
||||
# by users. 'update_user' method should be called to fill data for
|
||||
# a user before any calculation is made
|
||||
class OneUsage
|
||||
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']) },
|
||||
:proc_total => 'TEMPLATE/SIZE'
|
||||
}
|
||||
}
|
||||
|
||||
RESOURCES = ["VM", "IMAGE"]
|
||||
|
||||
def initialize()
|
||||
@client = OpenNebula::Client.new
|
||||
@usage = Hash.new
|
||||
end
|
||||
|
||||
def total(user_id, resource=nil, force=false)
|
||||
usage = Hash.new
|
||||
|
||||
if force
|
||||
resources = [resource] if RESOURCES.include?(resource)
|
||||
|
||||
resources.each{ |res|
|
||||
pool = get_pool(res, user_id)
|
||||
|
||||
base_xpath = "/#{res}_POOL/#{resource}"
|
||||
OneUsage.const_get("#{res}_USAGE".to_sym).each { |key, params|
|
||||
usage[key] ||= 0
|
||||
pool.each_xpath("#{base_xpath}/#{params[:xpath]}") { |elem|
|
||||
usage[key] += params[:count] ? 1 : elem.to_i
|
||||
}
|
||||
}
|
||||
|
||||
@usage[:user_id] ||= Hash.new
|
||||
@usage[:user_id].merge!(usage)
|
||||
}
|
||||
else
|
||||
usage = get_usage(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
|
||||
|
||||
private
|
||||
|
||||
def get_usage(user_id)
|
||||
usage = @usage[:user_id]
|
||||
|
||||
unless usage
|
||||
usage = Hash.new
|
||||
|
||||
keys = VM_USAGE.keys + IMAGE_USAGE.keys
|
||||
keys.each { |key|
|
||||
usage[key] = 0
|
||||
}
|
||||
|
||||
@usage[:user_id] = usage
|
||||
end
|
||||
|
||||
usage
|
||||
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
|
@ -14,22 +14,17 @@
|
||||
# limitations under the License. #
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
require 'one_usage'
|
||||
require 'sequel'
|
||||
require 'base64'
|
||||
|
||||
# Quota functionality for auth driver. Stores in database limits for each
|
||||
# user and using OneUsage is able to retrieve resource usage from
|
||||
# OpenNebula daemon and check if it is below limits
|
||||
class Quota
|
||||
attr_accessor :defaults
|
||||
###########################################################################
|
||||
#Constants with paths to relevant files and defaults
|
||||
# Constants with paths to relevant files and defaults
|
||||
###########################################################################
|
||||
if !ENV["ONE_LOCATION"]
|
||||
VAR_LOCATION = "/var/lib/one"
|
||||
VAR_LOCATION = "/var/lib/one"
|
||||
else
|
||||
VAR_LOCATION = ENV["ONE_LOCATION"] + "/var"
|
||||
VAR_LOCATION = ENV["ONE_LOCATION"] + "/var"
|
||||
end
|
||||
|
||||
CONF = {
|
||||
@ -41,9 +36,10 @@ class Quota
|
||||
:storage => nil
|
||||
}
|
||||
}
|
||||
|
||||
TABLE_NAME = :quotas
|
||||
|
||||
###########################################################################
|
||||
# Schema for the USAGE and QUOTA tables
|
||||
###########################################################################
|
||||
DB_QUOTA_SCHEMA = {
|
||||
:cpu => Float,
|
||||
:memory => Integer,
|
||||
@ -51,30 +47,55 @@ class Quota
|
||||
:storage => Integer
|
||||
}
|
||||
|
||||
QUOTA_TABLE = :quotas
|
||||
USAGE_TABLE = :usage
|
||||
|
||||
# 'db' is a Sequel database where to store user limits and client
|
||||
# is OpenNebula::Client used to connect to OpenNebula daemon
|
||||
def initialize(conf={})
|
||||
# TBD merge with the conf file
|
||||
@conf=CONF
|
||||
###########################################################################
|
||||
# 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
|
||||
}
|
||||
}
|
||||
|
||||
@defaults=@conf[:defaults]
|
||||
IMAGE_USAGE = {
|
||||
:storage => {
|
||||
:proc_info => lambda {|template| File.size(template['PATH']) },
|
||||
:xpath => 'SIZE'
|
||||
}
|
||||
}
|
||||
|
||||
@db=Sequel.connect(@conf[:db])
|
||||
|
||||
create_table
|
||||
@table=@db[TABLE_NAME]
|
||||
|
||||
@one_usage=OneUsage.new
|
||||
end
|
||||
RESOURCES = ["VM", "IMAGE"]
|
||||
|
||||
###########################################################################
|
||||
# DB handling
|
||||
###########################################################################
|
||||
def initialize(conf={})
|
||||
# TBD merge with the conf file
|
||||
@conf=CONF
|
||||
|
||||
@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
|
||||
@db.create_table?(TABLE_NAME) do
|
||||
def create_table(table)
|
||||
@db.create_table?(table) do
|
||||
Integer :uid
|
||||
|
||||
DB_QUOTA_SCHEMA.each { |key,value|
|
||||
@ -87,38 +108,47 @@ class Quota
|
||||
end
|
||||
|
||||
# Adds new user limits
|
||||
def set(uid, quota={})
|
||||
def set(table, uid, quota={})
|
||||
data=quota.delete_if{|key,value| !DB_QUOTA_SCHEMA.keys.include?(key)}
|
||||
|
||||
quotas=@table.filter(:uid => uid)
|
||||
quotas=@db[table].filter(:uid => uid)
|
||||
|
||||
if quotas.first
|
||||
quotas.update(data)
|
||||
else
|
||||
@table.insert(data.merge!(:uid => uid))
|
||||
@db[table].insert(data.merge!(:uid => uid))
|
||||
end
|
||||
end
|
||||
|
||||
# Gets user limits
|
||||
def get(uid=nil)
|
||||
def get(table, uid=nil)
|
||||
if uid
|
||||
limit=@table.filter(:uid => uid).first
|
||||
limit=@db[table].filter(:uid => uid).first
|
||||
if limit
|
||||
limit
|
||||
else
|
||||
@conf[:defaults]
|
||||
end
|
||||
else
|
||||
@table.all
|
||||
@db[table].all
|
||||
end
|
||||
end
|
||||
|
||||
###########################################################################
|
||||
# Quota Client
|
||||
###########################################################################
|
||||
def set_quota(uid, quota={})
|
||||
set(QUOTA_TABLE, uid, quota)
|
||||
end
|
||||
|
||||
def get_quota(uid=nil)
|
||||
get(QUOTA_TABLE, uid)
|
||||
end
|
||||
|
||||
###########################################################################
|
||||
# Authorization
|
||||
###########################################################################
|
||||
|
||||
def check_request(user_id, request)
|
||||
def authorize(user_id, request)
|
||||
obj, template_or_id, op, owner, pub, acl_eval = request.split(':')
|
||||
|
||||
if acl_eval == 0
|
||||
@ -137,9 +167,9 @@ class Quota
|
||||
end
|
||||
|
||||
def check_quotas(user_id, obj, template)
|
||||
info = @one_usage.get_resources(obj, template)
|
||||
total = @one_usage.total(obj, user_id)
|
||||
quota = get(user_id)
|
||||
info = get_resources(obj, template)
|
||||
total = get_usage(obj, user_id)
|
||||
quota = get_quota(user_id)
|
||||
|
||||
msg = ""
|
||||
info.each { |quota_name, quota_requested|
|
||||
@ -164,5 +194,63 @@ class Quota
|
||||
(obj == "IMAGE" && op == "CREATE") ||
|
||||
(obj == "TEMPLATE" && op == "INSTANTIATE")
|
||||
end
|
||||
end
|
||||
|
||||
###########################################################################
|
||||
# Usage
|
||||
###########################################################################
|
||||
def get_usage(user_id, resource=nil, force=false)
|
||||
usage = Hash.new
|
||||
|
||||
if force
|
||||
if RESOURCES.include?(resource)
|
||||
resources = [resource]
|
||||
else
|
||||
resources = RESOURCES
|
||||
end
|
||||
|
||||
resources.each{ |res|
|
||||
pool = get_pool(res, user_id)
|
||||
|
||||
base_xpath = "/#{res}_POOL/#{resource}"
|
||||
Quota.const_get("#{res}_USAGE".to_sym).each { |key, params|
|
||||
usage[key] ||= 0
|
||||
pool.each_xpath("#{base_xpath}/#{params[:xpath]}") { |elem|
|
||||
usage[key] += params[:count] ? 1 : elem.to_i
|
||||
}
|
||||
}
|
||||
|
||||
set(USAGE_TABLE, user_id, usage)
|
||||
}
|
||||
else
|
||||
usage = get(USAGE_TABLE, 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
|
||||
|
Loading…
x
Reference in New Issue
Block a user