1
0
mirror of https://github.com/OpenNebula/one.git synced 2024-12-31 17:17:40 +03:00

F #6341: Generic Quotas

- Generic quotas are defined and read from oned.conf (QUOTA_VM_ATTRIBUTE)
- Generic quotas react to the running mode (i.e. account only when the VM is
  running). For each quota oned also adds a RUNNIN_* metric
- one.system.config API call has been updated so every user can read
  quota configuration:
    . Sensitive information is hidden (***)
    . Oneadmin group has no longer access to sensitive information
      through the API
- CLI has been updated to render generic quotas
- onedb fsck fixes generic quotas reading the configuration from
  oned.conf

Other changes in this PR:
- Refactor Quota metrics to use std::vector instead of C array
Squashed commit of the following:
- New methods to Template and Attribute classes to render hidden
  attributes as "***"
- Update Quota calls to not include unneeded quotas

co-authored-by:Ruben S. Montero <rsmontero@opennebula.org>
This commit is contained in:
Pavel Czerný 2024-01-08 13:56:40 +01:00 committed by Ruben S. Montero
parent 863ed452f7
commit 442041fd07
No known key found for this signature in database
GPG Key ID: A0CEA6FA880A1D87
41 changed files with 722 additions and 267 deletions

View File

@ -81,6 +81,9 @@ public:
virtual void to_token(std::ostringstream& s) const = 0;
virtual void to_xml(std::ostringstream& s,
const std::map<std::string, std::set<std::string>> &hidden) const = 0;
/**
* Builds a new attribute from a string.
*/
@ -167,6 +170,9 @@ public:
* <attribute_name>attribute_value</attribute_name>
*
* @paran s the stream to write the attribute.
*
* NOTE: For Simple attributes hidden are in the form { "PORT". {} }
* A hidden attribute is rendered as ***
*/
void to_xml(std::ostringstream& s) const override
{
@ -175,6 +181,23 @@ public:
}
void to_xml(std::ostringstream& s,
const std::map<std::string, std::set<std::string>> &hidden) const override
{
s << "<" << attribute_name << ">";
if (hidden.find(attribute_name) != hidden.end() )
{
s << "***";
}
else
{
s << one_util::escape_xml(attribute_value);
}
s << "</"<< attribute_name << ">";
}
void to_json(std::ostringstream& s) const override
{
one_util::escape_json(attribute_value, s);
@ -422,9 +445,15 @@ public:
* ...
* <val_name_n>val_value_n</val_name_n>
* </attribute_name>
*
* NOTE: For Vector attributes hidden are in the form { "DB", { "USER", "PASSWD"} }
* A hidden attribute is rendered as ***
*/
void to_xml(std::ostringstream& s) const override;
void to_xml(std::ostringstream& s,
const std::map<std::string, std::set<std::string>> &hidden) const override;
void to_json(std::ostringstream& s) const override;
void to_token(std::ostringstream& s) const override;

View File

@ -98,6 +98,12 @@ public:
return va->to_token(s);
};
void to_xml(std::ostringstream& s,
const std::map<std::string, std::set<std::string>> &hidden) const override
{
return va->to_xml(s, hidden);
}
protected:
/**
* Creates the attribute with a reference to a VectorAttribute. The object

View File

@ -175,10 +175,20 @@ public:
* Gets an XML document with all of the configuration attributes
* @return the XML
*/
std::string get_configuration_xml() const
std::string get_configuration_xml(bool admin) const
{
std::string xml;
return config->to_xml(xml);
if (admin)
{
config->to_xml(xml);
}
else
{
config->to_xml_hidden(xml);
}
return xml;
};
protected:

View File

@ -30,7 +30,9 @@ public:
NebulaTemplate(const std::string& etc_location, const char * _conf_name,
const char * root_name)
: Template(false, '=', root_name)
, hidden_attributes{ { "DB", { "PASSWD" } } }
, hidden_attributes{
{"DB", {"BACKEND", "SERVER", "PORT", "USER", "PASSWD", "DB_NAME"}}
}
{
if (_conf_name[0] == '/')
{
@ -51,11 +53,13 @@ public:
std::string& to_str(std::string& str) const override;
std::string& to_xml_hidden(std::string& str) const;
protected:
/**
* Full path to the configuration file
*/
std::string conf_file;
std::string conf_file;
/**
* Defaults for the configuration file
@ -64,8 +68,8 @@ protected:
/**
* Hidden attributes, which shouldn't be displayed to non-admin users
* For Simple attributes use { "PORT". {} }
* For Vector attributes use { "DB", { "USER", "PASSWD"} }
* For Simple attributes use {"PORT", {}}
* For Vector attributes use {"DB", {"USER", "PASSWD"}}
*/
std::map<std::string, std::set<std::string>> hidden_attributes;

View File

@ -194,13 +194,11 @@ protected:
Quota(const char * quota_name,
const char * _template_name,
const char ** _metrics,
int _num_metrics,
const std::vector<std::string>& _metrics,
bool _is_default)
: Template(false, '=', quota_name),
template_name(_template_name),
metrics(_metrics),
num_metrics(_num_metrics),
is_default(_is_default){};
virtual ~Quota(){};
@ -225,12 +223,7 @@ protected:
/**
* The name of the quota metrics
*/
const char ** metrics;
/**
* Length
*/
int num_metrics;
const std::vector<std::string>& metrics;
/**
* Whether or not this is a default quota. Default quotas do not have usage,

View File

@ -40,7 +40,6 @@ public:
Quota("DATASTORE_QUOTA",
"DATASTORE",
DS_METRICS,
NUM_DS_METRICS,
is_default)
{};
@ -77,9 +76,7 @@ protected:
Quotas& default_quotas,
VectorAttribute **va) override;
static const char * DS_METRICS[];
static const int NUM_DS_METRICS;
static const std::vector<std::string> DS_METRICS;
};
#endif /*QUOTA_DATASTORE_H_*/

View File

@ -30,7 +30,7 @@
* 0 = unlimited, default if missing
*/
class QuotaImage : public Quota
class QuotaImage : public Quota
{
public:
@ -38,7 +38,6 @@ public:
Quota("IMAGE_QUOTA",
"IMAGE",
IMAGE_METRICS,
NUM_IMAGE_METRICS,
is_default)
{};
@ -75,9 +74,7 @@ protected:
Quotas& default_quotas,
VectorAttribute **va) override;
static const char * IMAGE_METRICS[];
static const int NUM_IMAGE_METRICS;
static const std::vector<std::string> IMAGE_METRICS;
};
#endif /*QUOTA_IMAGE_H_*/

View File

@ -30,11 +30,12 @@
*
* 0 = unlimited, default if missing
*/
class QuotaNetwork : public Quota
class QuotaNetwork : public Quota
{
public:
QuotaNetwork(bool is_default): Quota("NETWORK_QUOTA", "NETWORK", NET_METRICS,
NUM_NET_METRICS, is_default) {};
QuotaNetwork(bool is_default)
: Quota("NETWORK_QUOTA", "NETWORK", NET_METRICS, is_default)
{}
virtual ~QuotaNetwork(){};
@ -75,9 +76,7 @@ protected:
Quotas& default_quotas,
VectorAttribute **va) override;
static const char * NET_METRICS[];
static const int NUM_NET_METRICS;
static const std::vector<std::string> NET_METRICS;
private:
/**

View File

@ -41,7 +41,7 @@
* 0 = unlimited, default if missing
*/
class QuotaVirtualMachine : public Quota
class QuotaVirtualMachine : public Quota
{
public:
@ -49,7 +49,6 @@ public:
Quota("VM_QUOTA",
"VM",
VM_METRICS,
NUM_VM_METRICS,
is_default)
{};
@ -96,6 +95,27 @@ public:
*/
int get_quota(const std::string& id, VectorAttribute **va) override;
/**
* Add generic quota to metrics. It adds also RUNNING_ quota attribute
* @param metric Name of the quota metri
*
* @return 0 success, -1 if metric already exists
*/
static int add_metric_generic(const std::string& metric);
/**
* Return vector of generic quota metrics
*/
static const std::vector<std::string>& generic_metrics()
{
return VM_GENERIC;
}
/*
* Add RUNNING_ quotas for generic metrics present in the template
*/
static void add_running_quota_generic(Template& tmpl);
protected:
/**
@ -130,10 +150,8 @@ protected:
Quotas& default_quotas,
VectorAttribute **va) override;
static const char * VM_METRICS[];
static const int NUM_VM_METRICS;
static std::vector<std::string> VM_METRICS;
static std::vector<std::string> VM_GENERIC;
};
#endif /*QUOTA_VIRTUALMACHINE_H_*/

View File

@ -60,6 +60,11 @@ protected:
void request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att) override;
virtual void request_execute(int oid,
const std::string& templ,
int update_type,
RequestAttributes& att);
virtual int replace_template(PoolObjectSQL * object,
const std::string & tmpl,
const RequestAttributes &att,
@ -80,17 +85,6 @@ protected:
{
return 0;
}
/**
* Method for extra checks on specific objects
* @param obj to check conditions form update
* @param error return reason of error
* @return 0 on success
*/
virtual int extra_preconditions_check(PoolObjectSQL * obj, std::string& error)
{
return 0;
}
};
/* ------------------------------------------------------------------------- */
@ -164,21 +158,10 @@ protected:
return vmpool->update_search(vm);
}
int extra_preconditions_check(PoolObjectSQL * obj, std::string& error) override
{
auto vm = static_cast<VirtualMachine *>(obj);
// Check if the action is supported for imported VMs
if (vm->is_imported() &&
!vm->is_imported_action_supported(VMActions::UPDATE_ACTION))
{
error = "Action \"update\" is not supported for imported VMs";
return -1;
}
return 0;
}
void request_execute(int oid,
const std::string& templ,
int update_type,
RequestAttributes& att) override;
};
/* ------------------------------------------------------------------------- */

View File

@ -182,13 +182,21 @@ public:
* ...
* </template>
* The name of the root element is set when the Template object is created
* @param xml string that hold the xml template representation
* @return a reference to the generated string
*
* Hidden attributes are defined as a map, where
* - Simple attributes use an empty set { "PORT", {} }
* - Vector attributes use a set of hidden subattributes { "DB", { "USER", "PASSWD"} }
*
* @param xml string that hold the xml template representation
*
* @return a reference to the generated string
*/
std::string& to_xml(std::string& xml) const;
std::string& to_xml(std::string& xml, const std::string& extra) const;
std::string& to_xml(std::string& xml, const std::map<std::string, std::set<std::string>>& hidden) const;
std::string& to_json(std::string& xml) const;
std::string& to_token(std::string& xml) const;

View File

@ -940,6 +940,15 @@ public:
return std::make_unique<VirtualMachineTemplate>(*obj_template);
}
/**
* Returns a copy of the VirtualMachine User Template
* @return A copy of the VirtualMachine User Template
*/
std::unique_ptr<VirtualMachineTemplate> clone_user_template() const
{
return std::make_unique<VirtualMachineTemplate>(*user_obj_template);
}
/**
* This function replaces the *user template*.
* @param tmpl_str new contents
@ -967,10 +976,10 @@ public:
* @param name of the attribute
* @param value of the attribute
*/
void get_user_template_attribute(const std::string& name,
std::string& value) const
template<typename T>
bool get_user_template_attribute(const std::string& name, T& value) const
{
user_obj_template->get(name, value);
return user_obj_template->get(name, value);
}
/**
@ -1052,12 +1061,18 @@ public:
*/
bool is_pinned() const;
/**
* @return true if Virtual Machine is in state, when running quota applies
*/
bool is_running_quota() const;
/**
* Fill a template only with the necessary attributes to update the quotas
* @param qtmpl template that will be filled
* @param only_running true to not add CPU, MEMORY and VMS counters
* @param basic_quota true to add basic quota attributes (from Template and User template)
* @param running_quota true to add RUNNING_ quota attributes (for Template and User Template)
*/
void get_quota_template(VirtualMachineTemplate& qtmpl, bool only_running);
void get_quota_template(VirtualMachineTemplate& quota_tmpl, bool basic_quota, bool running_quota);
// ------------------------------------------------------------------------
// Virtual Machine Disks

View File

@ -873,6 +873,15 @@ DEFAULT_VDC_CLUSTER_HOST_ACL = "MANAGE"
DEFAULT_VDC_CLUSTER_NET_ACL = "USE"
DEFAULT_VDC_CLUSTER_DATASTORE_ACL = "USE"
#*******************************************************************************
# Generic VM Quotas Configuration
#*******************************************************************************
# The following attributes may be limited by quotas. Use any numeric attribute
# from Template or User Template
#*******************************************************************************
#QUOTA_VM_ATTRIBUTE = "VCPU"
#*******************************************************************************
# Restricted Attributes Configuration
#*******************************************************************************

View File

@ -328,7 +328,7 @@ class OneGroupHelper < OpenNebulaHelper::OneHelper
default_quotas = elem
}
helper = OneQuotaHelper.new
helper = OneQuotaHelper.new(@client)
helper.format_quota(group_hash['GROUP'], default_quotas, group.id)
end
end

View File

@ -75,6 +75,10 @@ class OneQuotaHelper
#-----------------------------------------------------------------------
EOT
def initialize(client = nil)
@client=client
end
# Edits the quota template of a resource
# @param [XMLElement] resource to get the current info from
# @param [String] path to the new contents. If nil a editor will be
@ -207,6 +211,8 @@ class OneQuotaHelper
vm_quotas = [qh['VM_QUOTA']['VM']].flatten
generic_quotas = get_generic_quotas
# This initializes the VM quotas for users/groups that don't have any
# resource usage yet. It not applied to oneamdin
if vm_quotas[0].nil? && resource_id.to_i != 0
@ -228,6 +234,13 @@ class OneQuotaHelper
"SYSTEM_DISK_SIZE" => limit,
"SYSTEM_DISK_SIZE_USED" => "0"
}]
generic_quotas.each do |q|
vm_quotas[0][q] = limit
vm_quotas[0]["#{q}_USED"] = "0"
vm_quotas[0]["RUNNING_#{q}"] = limit
vm_quotas[0]["RUNNING_#{q}_USED"] = "0"
end
end
if !vm_quotas[0].nil?
@ -378,6 +391,55 @@ class OneQuotaHelper
puts
end
if !generic_quotas.empty? && !vm_quotas[0].nil?
CLIHelper.print_header(str_h1 % "VMS GENERIC QUOTAS",false)
size = [80 / generic_quotas.length - 1, 18].min
CLIHelper::ShowTable.new(nil, self) do
generic_quotas.each do |elem|
column elem.to_sym, "", :right, :size=>size do |d|
if !d.nil?
limit = d[elem]
limit = helper.get_default_limit(
limit, "VM_QUOTA/VM/#{elem}")
if limit == LIMIT_UNLIMITED
"%6s / -" % [d["#{elem}_USED"]]
else
"%6s / %6s" % [d["#{elem}_USED"], limit]
end
end
end
end
end.show(vm_quotas, {})
puts
CLIHelper.print_header(str_h1 % "VMS GENERIC RUNNING QUOTAS",false)
size = [80 / generic_quotas.length - 1, 18].min
CLIHelper::ShowTable.new(nil, self) do
generic_quotas.each do |q|
elem = "RUNNING_#{q}"
column elem.to_sym, "", :right, :size=>size do |d|
if !d.nil?
limit = d[elem]
limit = helper.get_default_limit(
limit, "VM_QUOTA/VM/#{elem}")
if limit == LIMIT_UNLIMITED
"%6s / -" % [d["#{elem}_USED"]]
else
"%6s / %6s" % [d["#{elem}_USED"], limit]
end
end
end
end
end.show(vm_quotas, {})
puts
end
CLIHelper.print_header(str_h1 % "DATASTORE USAGE & QUOTAS",false)
puts
@ -503,4 +565,17 @@ class OneQuotaHelper
return limit
end
private
def get_generic_quotas
conf = OpenNebula::System.new(@client).get_configuration
return [] if OpenNebula.is_error?(conf)
conf.retrieve_elements('/OPENNEBULA_CONFIGURATION/QUOTA_VM_ATTRIBUTE')
rescue StandardError
[]
end
end

View File

@ -613,7 +613,7 @@ class OneUserHelper < OpenNebulaHelper::OneHelper
default_quotas = elem
}
helper = OneQuotaHelper.new
helper = OneQuotaHelper.new(@client)
helper.format_quota(user_hash['USER'], default_quotas, user.id)
end

View File

@ -80,6 +80,38 @@ void VectorAttribute::to_xml(ostringstream &oss) const
oss << "</"<< name() << ">";
}
void VectorAttribute::to_xml(ostringstream &oss,
const std::map<std::string, std::set<std::string>> &hidden) const
{
oss << "<" << name() << ">";
auto hidden_it = hidden.find(name());
for (auto it=attribute_value.begin(); it!=attribute_value.end(); it++)
{
if ( it->first.empty())
{
continue;
}
oss << "<" << it->first << ">";
if (hidden_it != hidden.end() &&
hidden_it->second.find(it->first) != hidden_it->second.end())
{
oss << "***";
}
else
{
oss << one_util::escape_xml(it->second);
}
oss << "</" << it->first << ">";
}
oss << "</"<< name() << ">";
}
void VectorAttribute::to_json(std::ostringstream& s) const
{
if ( attribute_value.empty() )

View File

@ -76,7 +76,7 @@ int DispatchManager::deploy(unique_ptr<VirtualMachine> vm,
uid = vm->get_uid();
gid = vm->get_gid();
vm->get_quota_template(quota_tmpl, true);
vm->get_quota_template(quota_tmpl, false, true);
}
lcm->trigger_deploy(vid);
@ -152,7 +152,7 @@ int DispatchManager::import(unique_ptr<VirtualMachine> vm, const RequestAttribut
uid = vm->get_uid();
gid = vm->get_gid();
vm->get_quota_template(quota_tmpl, true);
vm->get_quota_template(quota_tmpl, false, true);
do_quotas = true;
}
@ -290,23 +290,9 @@ void DispatchManager::free_vm_resources(unique_ptr<VirtualMachine> vm,
int vrid = -1;
unsigned int port;
auto quota_tmpl = vm->clone_template();
VirtualMachineTemplate quota_tmpl;
if ( (vm->get_state() == VirtualMachine::ACTIVE) ||
(vm->get_state() == VirtualMachine::PENDING) ||
(vm->get_state() == VirtualMachine::HOLD) )
{
std::string memory, cpu;
quota_tmpl->get("MEMORY", memory);
quota_tmpl->get("CPU", cpu);
quota_tmpl->add("RUNNING_MEMORY", memory);
quota_tmpl->add("RUNNING_CPU", cpu);
quota_tmpl->add("RUNNING_VMS", 1);
}
quota_tmpl->add("VMS", 1);
vm->get_quota_template(quota_tmpl, true, vm->is_running_quota());
vm->release_network_leases();
@ -370,7 +356,7 @@ void DispatchManager::free_vm_resources(unique_ptr<VirtualMachine> vm,
vm.reset(); //force unlock of vm mutex
Quotas::vm_del(uid, gid, quota_tmpl.get());
Quotas::vm_del(uid, gid, &quota_tmpl);
if ( !ds_quotas.empty() )
{
@ -1240,7 +1226,7 @@ int DispatchManager::delete_recreate(unique_ptr<VirtualMachine> vm,
if ( do_quotas )
{
vm->get_quota_template(quota_tmpl, true);
vm->get_quota_template(quota_tmpl, false, true);
}
break;

View File

@ -43,7 +43,7 @@ void DispatchManager::trigger_suspend_success(int vid)
{
VirtualMachineTemplate quota_tmpl;
vm->get_quota_template(quota_tmpl, true);
vm->get_quota_template(quota_tmpl, false, true);
vm->set_state(VirtualMachine::SUSPENDED);
@ -96,7 +96,7 @@ void DispatchManager::trigger_stop_success(int vid)
{
VirtualMachineTemplate quota_tmpl;
vm->get_quota_template(quota_tmpl, true);
vm->get_quota_template(quota_tmpl, false, true);
vm->set_state(VirtualMachine::STOPPED);
@ -151,7 +151,9 @@ void DispatchManager::trigger_undeploy_success(int vid)
{
VirtualMachineTemplate quota_tmpl;
vm->get_quota_template(quota_tmpl, true);
// Bug: From the LCM state we don't know if we undeploy from RUNNING or POWEROFF
// state. In first case we should remove RUNNING_* quotas, in the second not
vm->get_quota_template(quota_tmpl, false, vm->is_running_quota());
vm->set_state(VirtualMachine::UNDEPLOYED);
@ -214,7 +216,7 @@ void DispatchManager::trigger_poweroff_success(int vid)
{
VirtualMachineTemplate quota_tmpl;
vm->get_quota_template(quota_tmpl, true);
vm->get_quota_template(quota_tmpl, false, vm->is_running_quota());
vm->set_state(VirtualMachine::POWEROFF);

View File

@ -202,9 +202,7 @@ void LifeCycleManager::trigger_stop(int vid, const RequestAttributes& ra)
vm->get_template_attribute("MEMORY", memory);
vm->get_template_attribute("CPU", cpu);
quota_tmpl.add("RUNNING_MEMORY", memory);
quota_tmpl.add("RUNNING_CPU", cpu);
quota_tmpl.add("RUNNING_VMS", 1);
vm->get_quota_template(quota_tmpl, false, true);
vm->set_state(VirtualMachine::ACTIVE);
vm->set_state(VirtualMachine::EPILOG_STOP);
@ -220,7 +218,7 @@ void LifeCycleManager::trigger_stop(int vid, const RequestAttributes& ra)
//----------------------------------------------------
tm->trigger_epilog_stop(vm.get());
// Add running quota, it will be removed in DM::stop_success
vm.reset();
Quotas::vm_add(quota_uid, quota_gid, &quota_tmpl);
@ -465,9 +463,7 @@ void LifeCycleManager::trigger_shutdown(int vid, bool hard,
(vm->get_state() == VirtualMachine::STOPPED) ||
(vm->get_state() == VirtualMachine::UNDEPLOYED))
{
quota_tmpl.add("RUNNING_MEMORY", memory);
quota_tmpl.add("RUNNING_CPU", cpu);
quota_tmpl.add("RUNNING_VMS", 1);
vm->get_quota_template(quota_tmpl, false, true);
}
auto lcm_state = vm->get_lcm_state();
@ -639,9 +635,7 @@ void LifeCycleManager::trigger_undeploy(int vid, bool hard,
vm->get_template_attribute("MEMORY", memory);
vm->get_template_attribute("CPU", cpu);
quota_tmpl.add("RUNNING_MEMORY", memory);
quota_tmpl.add("RUNNING_CPU", cpu);
quota_tmpl.add("RUNNING_VMS", 1);
vm->get_quota_template(quota_tmpl, false, true);
vm->set_state(VirtualMachine::ACTIVE);
vm->set_state(VirtualMachine::EPILOG_UNDEPLOY);

View File

@ -1226,7 +1226,7 @@ void LifeCycleManager::trigger_monitor_poweron(int vid)
vmpool->update(vm.get());
vm->get_quota_template(quota_tmpl, true);
vm->get_quota_template(quota_tmpl, false, true);
vm.reset();
@ -1512,7 +1512,6 @@ void LifeCycleManager::trigger_snapshot_create_failure(int vid)
Template quota_tmpl;
quota_tmpl.set(snap);
quota_tmpl.replace("VMS", 0);
Quotas::quota_del(Quotas::VM, vm_uid, vm_gid, &quota_tmpl);
}
@ -2622,7 +2621,7 @@ void LifeCycleManager::trigger_resize_failure(int vid)
deltas.add("MEMORY", nmem - omem);
deltas.add("CPU", ncpu - ocpu);
deltas.add("VMS", 0);
deltas.add("VCPU", nvcpu - ovcpu);
auto state = vm->get_state();
@ -2632,6 +2631,7 @@ void LifeCycleManager::trigger_resize_failure(int vid)
{
deltas.add("RUNNING_MEMORY", nmem - omem);
deltas.add("RUNNING_CPU", ncpu - ocpu);
deltas.add("RUNNING_VCPU", nvcpu - ovcpu);
}
vm->resize(ocpu, omem, ovcpu, error);

View File

@ -62,7 +62,7 @@ public:
msg.type(MonitorDriverMessages::START_MONITOR);
msg.oid(oid);
msg.payload(format_message(host_xml + ns.get_configuration_xml()));
msg.payload(format_message(host_xml + ns.get_configuration_xml(true)));
write(msg);
}
@ -74,7 +74,7 @@ public:
msg.type(MonitorDriverMessages::STOP_MONITOR);
msg.oid(oid);
msg.payload(format_message(host_xml + ns.get_configuration_xml()));
msg.payload(format_message(host_xml + ns.get_configuration_xml(true)));
write(msg);
}

View File

@ -614,6 +614,24 @@ void Nebula::start(bool bootstrap_only)
ssl_util::SSLMutex::initialize();
// -----------------------------------------------------------
// Generic Quotas
// -----------------------------------------------------------
{
vector<const SingleAttribute *> qouta_vm_attrs;
nebula_configuration->get("QUOTA_VM_ATTRIBUTE", qouta_vm_attrs);
for (const auto* quota : qouta_vm_attrs)
{
if (QuotaVirtualMachine::add_metric_generic(quota->value()) != 0)
{
NebulaLog::warn("ONE", "Unable to add QUOTA_VM_ATTRIBUTE " + quota->value()
+ ", it already exists");
}
}
}
// -----------------------------------------------------------
//Managers
// -----------------------------------------------------------

View File

@ -171,6 +171,51 @@ EOT
end
end
def read_config
begin
# Suppress augeas require warning message
$VERBOSE = nil
gem 'augeas', '~> 0.6'
require 'augeas'
rescue Gem::LoadError
STDERR.puts(
'Augeas gem is not installed, run `gem install ' \
'augeas -v \'0.6\'` to install it'
)
exit(-1)
end
work_file_dir = File.dirname(ONED_CONF)
work_file_name = File.basename(ONED_CONF)
aug = Augeas.create(:no_modl_autoload => true,
:no_load => true,
:root => work_file_dir,
:loadpath => ONED_CONF)
aug.clear_transforms
aug.transform(:lens => 'Oned.lns', :incl => work_file_name)
aug.context = "/files/#{work_file_name}"
aug.load
@generic_quotas = []
i = 0
loop do
i += 1
quota = aug.get("QUOTA_VM_ATTRIBUTE[#{i}]")
break if quota.nil?
@generic_quotas << quota.chomp('"').reverse.chomp('"').reverse
end
rescue StandardError => e
STDERR.puts "Unable to parse oned.conf: #{e}"
exit(-1)
end
########################################################################
# Acl
########################################################################

View File

@ -56,7 +56,9 @@ module OneDBFsck
# VM quotas
query = "SELECT body FROM vm_pool WHERE #{filter} AND state<>6"
resources = { :cpu => 'CPU', :mem => 'MEMORY', :vms => 'VMS' }
resources = { :CPU => 'CPU', :MEMORY => 'MEMORY', :VMS => 'VMS' }
@generic_quotas.each {|q| resources[q] = q }
vm_elem = calculate_vm_quotas(doc, query, resource, resources)
@ -95,9 +97,11 @@ module OneDBFsck
query = "SELECT body FROM vm_pool WHERE #{filter} AND #{running_states}"
resources = { :cpu => 'RUNNING_CPU',
:mem => 'RUNNING_MEMORY',
:vms => 'RUNNING_VMS' }
resources = { :CPU => 'RUNNING_CPU',
:MEMORY => 'RUNNING_MEMORY',
:VMS => 'RUNNING_VMS' }
@generic_quotas.each {|q| resources[q] = "RUNNING_#{q}" }
calculate_vm_quotas(doc, query, resource, resources)
end
@ -344,12 +348,12 @@ module OneDBFsck
oid = doc.root.at_xpath('ID').text.to_i
cpu_used = 0
mem_used = 0
vms_used = 0
cpu = resources[:cpu]
mem = resources[:mem]
vms = resources[:vms]
cpu = resources[:CPU]
vms = resources[:VMS]
quotas = {}
resources.each {|_, q| quotas[q] = 0 }
@db.fetch(query) do |vm_row|
vmdoc = nokogiri_doc(vm_row[:body], 'vm_pool')
@ -359,11 +363,17 @@ module OneDBFsck
cpu_used += (e.text.to_f * 100).to_i
end
vmdoc.root.xpath('TEMPLATE/MEMORY').each do |e|
mem_used += e.text.to_i
resources.each do |att_name, quota_name|
next if [:CPU, :VMS].include?(att_name)
value = vmdoc.root.at_xpath("TEMPLATE/#{att_name}") ||
vmdoc.root.at_xpath("USER_TEMPLATE/#{att_name}")
value = value.text unless value.nil?
quotas[quota_name] += value.to_i
end
vms_used += 1
quotas[vms] += 1
end
vm_elem = nil
@ -375,14 +385,10 @@ module OneDBFsck
vm_quota = doc.root.add_child(doc.create_element('VM_QUOTA'))
vm_elem = vm_quota.add_child(doc.create_element('VM'))
vm_elem.add_child(doc.create_element(cpu)).content = '-1'
vm_elem.add_child(doc.create_element("#{cpu}_USED")).content = '0'
vm_elem.add_child(doc.create_element(mem)).content = '-1'
vm_elem.add_child(doc.create_element("#{mem}_USED")).content = '0'
vm_elem.add_child(doc.create_element(vms)).content = '-1'
vm_elem.add_child(doc.create_element("#{vms}_USED")).content = '0'
resources.each do |_, quota_name|
vm_elem.add_child(doc.create_element(quota_name)).content = '-1'
vm_elem.add_child(doc.create_element("#{quota_name}_USED")).content = '0'
end
system_disk_e = doc.create_element('SYSTEM_DISK_SIZE')
system_disk_used_e = doc.create_element('SYSTEM_DISK_SIZE_USED')
@ -408,20 +414,16 @@ module OneDBFsck
e.content = cpu_used_str
end
vm_elem.xpath("#{mem}_USED").each do |e|
next if e.text == mem_used.to_s
resources.each do |att_name, quota_name|
next if att_name == :CPU
log_error("#{resource} #{oid} quotas: #{mem}_USED has " \
"#{e.text} \tis\t#{mem_used}")
e.content = mem_used.to_s
end
vm_elem.xpath("#{quota_name}_USED").each do |e|
next if e.text.to_i == quotas[quota_name].to_i
vm_elem.xpath("#{vms}_USED").each do |e|
next if e.text == vms_used.to_s
log_error("#{resource} #{oid} quotas: #{vms}_USED has " \
"#{e.text} \tis\t#{vms_used}")
e.content = vms_used.to_s
log_error("#{resource} #{oid} quotas: #{quota_name}_USED has " \
"#{e.text} \tis\t#{quotas[quota_name]}")
e.content = quotas[quota_name].to_s
end
end
vm_elem

View File

@ -483,6 +483,8 @@ class OneDB
time0 = Time.now
@backend.read_config
result = @backend.fsck
if !result

View File

@ -129,6 +129,8 @@ bool VirtualMachineAllocate::allocate_authorization(
aux_tmpl.add("RUNNING_VMS", 1);
aux_tmpl.add("VMS", 1);
QuotaVirtualMachine::add_running_quota_generic(aux_tmpl);
if ( quota_authorization(&aux_tmpl, Quotas::VIRTUALMACHINE, att) == false )
{
return false;
@ -372,6 +374,8 @@ error_drop_vm:
tmpl_back.add("RUNNING_VMS", 1);
tmpl_back.add("VMS", 1);
QuotaVirtualMachine::add_running_quota_generic(tmpl_back);
quota_rollback(&tmpl_back, Quotas::VIRTUALMACHINE, att);
VirtualMachineDisks::extended_info(att.uid, &tmpl_back);

View File

@ -39,8 +39,6 @@ unique_ptr<PoolObjectSQL> RequestManagerChown::get_and_quota(
int old_uid;
int old_gid;
std::string memory, cpu;
auto object = pool->get_ro<PoolObjectSQL>(oid);
if ( object == nullptr )
@ -63,23 +61,9 @@ unique_ptr<PoolObjectSQL> RequestManagerChown::get_and_quota(
return 0;
}
auto tmpl = vm->clone_template();
auto tmpl = std::make_unique<VirtualMachineTemplate>();
if ( (vm->get_state() == VirtualMachine::ACTIVE) ||
(vm->get_state() == VirtualMachine::PENDING) ||
(vm->get_state() == VirtualMachine::CLONING) ||
(vm->get_state() == VirtualMachine::CLONING_FAILURE) ||
(vm->get_state() == VirtualMachine::HOLD) )
{
vm->get_template_attribute("MEMORY", memory);
vm->get_template_attribute("CPU", cpu);
tmpl->add("RUNNING_MEMORY", memory);
tmpl->add("RUNNING_CPU", cpu);
tmpl->add("RUNNING_VMS", 1);
}
tmpl->add("VMS", 1);
vm->get_quota_template(*tmpl, true, vm->is_running_quota());
VirtualMachineDisks::image_ds_quotas(tmpl.get(), ds_quotas);

View File

@ -38,15 +38,9 @@ void SystemVersion::request_execute(xmlrpc_c::paramList const& paramList,
void SystemConfig::request_execute(xmlrpc_c::paramList const& paramList,
RequestAttributes& att)
{
if ( att.gid != GroupPool::ONEADMIN_ID )
{
att.resp_msg = "The oned configuration can only be retrieved by users "
"in the oneadmin group";
failure_response(AUTHORIZATION, att);
return;
}
success_response(Nebula::instance().get_configuration_xml(), att);
//bool is_admin = att.gid == GroupPool::ONEADMIN_ID;
//Do not send sensitive configuration data over the wire
success_response(Nebula::instance().get_configuration_xml(false), att);
return;
}

View File

@ -63,8 +63,6 @@ void RequestManagerUpdateTemplate::request_execute(
xmlrpc_c::paramList const& paramList,
RequestAttributes& att)
{
int rc;
int oid = xmlrpc_c::value_int(paramList.getInt(1));
string tmpl = xmlrpc_c::value_string(paramList.getString(2));
@ -87,6 +85,18 @@ void RequestManagerUpdateTemplate::request_execute(
return;
}
request_execute(oid, tmpl, update_type, att);
}
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
void RequestManagerUpdateTemplate::request_execute(int oid,
const std::string& tmpl,
int update_type,
RequestAttributes& att)
{
int rc;
auto object = pool->get<PoolObjectSQL>(oid);
@ -97,13 +107,6 @@ void RequestManagerUpdateTemplate::request_execute(
return;
}
if (extra_preconditions_check(object.get(), att.resp_msg))
{
failure_response(ACTION, att);
return;
}
if (update_type == 0)
{
rc = replace_template(object.get(), tmpl, att, att.resp_msg);
@ -126,8 +129,129 @@ void RequestManagerUpdateTemplate::request_execute(
extra_updates(object.get());
success_response(oid, att);
}
return;
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
void VirtualMachineUpdateTemplate::request_execute(int oid,
const std::string& tmpl,
int update_type,
RequestAttributes& att)
{
int rc;
auto vm = pool->get<VirtualMachine>(oid);
if ( vm == nullptr )
{
att.resp_id = oid;
failure_response(NO_EXISTS, att);
return;
}
// Check if the action is supported for imported VMs
if (vm->is_imported() && !vm->is_imported_action_supported(VMActions::UPDATE_ACTION))
{
att.resp_msg = "Action \"update\" is not supported for imported VMs";
failure_response(ACTION, att);
return;
}
// Apply generic quota deltas
auto new_tmpl = make_unique<VirtualMachineTemplate>(false,'=',"USER_TEMPLATE");
if ( new_tmpl->parse_str_or_xml(tmpl, att.resp_msg) != 0 )
{
failure_response(ACTION, att);
return;
}
if ( update_type == 1 ) //append mode
{
auto user_tmpl = vm->clone_user_template();
user_tmpl->merge(new_tmpl.get());
new_tmpl.swap(user_tmpl);
}
// Compute quota deltas (only generic quota may appear in User template)
bool do_quotas = false;
for ( const string& metric : QuotaVirtualMachine::generic_metrics())
{
float value_new, value_old;
bool exists_old = vm->get_user_template_attribute(metric, value_old);
bool exists_new = new_tmpl->get(metric, value_new);
if ( exists_old || exists_new )
{
float delta = value_new - value_old;
new_tmpl->replace(metric, delta);
do_quotas |= delta != 0;
}
}
if (vm->is_running_quota())
{
QuotaVirtualMachine::add_running_quota_generic(*new_tmpl);
}
RequestAttributes att_quota(att);
att_quota.uid = vm->get_uid();
att_quota.gid = vm->get_gid();
vm.reset();
if ( do_quotas )
{
if (!quota_authorization(new_tmpl.get(), Quotas::VIRTUALMACHINE, att_quota, att.resp_msg))
{
failure_response(ACTION, att);
return;
}
}
vm = pool->get<VirtualMachine>(oid);
if (update_type == 0)
{
rc = replace_template(vm.get(), tmpl, att, att.resp_msg);
}
else //if (update_type == 1)
{
rc = append_template(vm.get(), tmpl, att, att.resp_msg);
}
if ( rc != 0 )
{
vm.reset();
if (do_quotas)
{
quota_rollback(new_tmpl.get(), Quotas::VIRTUALMACHINE, att_quota);
}
att.resp_msg = "Cannot update template. " + att.resp_msg;
failure_response(INTERNAL, att);
return;
}
pool->update(vm.get());
extra_updates(vm.get());
success_response(oid, att);
}
/* ------------------------------------------------------------------------- */

View File

@ -238,6 +238,8 @@ Request::ErrorCode VMTemplateInstantiate::request_execute(int id, const string&
extended_tmpl.add("RUNNING_VMS", 1);
extended_tmpl.add("VMS", 1);
QuotaVirtualMachine::add_running_quota_generic(extended_tmpl);
if (quota_authorization(&extended_tmpl, Quotas::VIRTUALMACHINE, att,
att.resp_msg) == false)
{

View File

@ -517,18 +517,11 @@ Request::ErrorCode VirtualMachineAction::request_execute(RequestAttributes& att,
rc = dm->suspend(vid, att, error);
break;
case VMActions::RESUME_ACTION:
// Generate quota information for resume action
vm->get_template_attribute("MEMORY", memory);
vm->get_template_attribute("CPU", cpu);
quota_tmpl.add("RUNNING_MEMORY", memory);
quota_tmpl.add("RUNNING_CPU", cpu);
quota_tmpl.add("RUNNING_VMS", 1);
vm->get_quota_template(quota_tmpl, false, true);
att_aux.uid = vm->get_uid();
att_aux.gid = vm->get_gid();
if (!quota_authorization(&quota_tmpl, Quotas::VIRTUALMACHINE, att_aux, att.resp_msg))
{
return ACTION;
@ -1876,8 +1869,6 @@ Request::ErrorCode VirtualMachineAttach::request_execute(int id,
VirtualMachineTemplate deltas(tmpl);
VirtualMachineDisks::extended_info(att.uid, &deltas);
deltas.add("VMS", 0);
if (quota_resize_authorization(&deltas, att_quota, vm_perms) == false)
{
att.resp_msg = std::move(att_quota.resp_msg);
@ -1980,7 +1971,7 @@ void VirtualMachineResize::request_execute(xmlrpc_c::paramList const& paramList,
float ncpu, ocpu, dcpu;
long nmemory, omemory, dmemory;
int nvcpu, ovcpu;
int nvcpu, ovcpu, dvcpu;
bool update_running_quota;
Template deltas;
@ -2109,15 +2100,18 @@ void VirtualMachineResize::request_execute(xmlrpc_c::paramList const& paramList,
}
dcpu = ncpu - ocpu;
dvcpu = nvcpu - ovcpu;
dmemory = nmemory - omemory;
deltas.add("MEMORY", dmemory);
deltas.add("CPU", dcpu);
deltas.add("VCPU", dvcpu);
if (update_running_quota)
{
deltas.add("RUNNING_MEMORY", dmemory);
deltas.add("RUNNING_CPU", dcpu);
deltas.add("RUNNING_VCPU", dvcpu);
}
if (quota_resize_authorization(&deltas, att, vm_perms) == false)
@ -2203,7 +2197,6 @@ Request::ErrorCode VirtualMachineSnapshotCreate::request_execute(RequestAttribut
Template quota_tmpl;
quota_tmpl.set(snap);
quota_tmpl.add("VMS", 0);
RequestAttributes att_quota(vm_perms.uid, vm_perms.gid, att);

View File

@ -87,6 +87,14 @@ void NebulaTemplate::set_conf_single(const std::string& attr,
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
std::string& NebulaTemplate::to_xml_hidden(std::string& str) const
{
return Template::to_xml(str, hidden_attributes);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
std::string& NebulaTemplate::to_str(std::string& str) const
{
ostringstream os;
@ -96,6 +104,7 @@ std::string& NebulaTemplate::to_str(std::string& str) const
string s;
auto hidden_it = hidden_attributes.find(it->first);
if (hidden_it != hidden_attributes.end())
{
if (it->second->type() == Attribute::SIMPLE)

View File

@ -371,6 +371,24 @@ string& Template::to_xml(string& xml) const
return xml;
}
string& Template::to_xml(string& xml, const std::map<std::string, std::set<std::string>> &hidden) const
{
ostringstream oss;
oss << "<" << xml_root << ">";
for ( auto it = attributes.begin(); it!=attributes.end(); it++)
{
it->second->to_xml(oss, hidden);
}
oss << "</" << xml_root << ">";
xml = oss.str();
return xml;
}
string& Template::to_xml(string& xml, const string& extra) const
{
ostringstream oss;

View File

@ -178,13 +178,11 @@ bool Quota::check_quota(const string& qid,
{
map<string, string> values;
for (int i=0; i < num_metrics; i++)
for (const string& metric : metrics)
{
string metrics_used = metrics[i];
string metrics_used = metric + "_USED";
metrics_used += "_USED";
values.insert(make_pair(metrics[i], DEFAULT_STR));
values.insert(make_pair(metric, DEFAULT_STR));
values.insert(make_pair(metrics_used, "0"));
}
@ -201,27 +199,25 @@ bool Quota::check_quota(const string& qid,
// -------------------------------------------------------------------------
// Check the quotas for each usage request
// -------------------------------------------------------------------------
for (int i=0; i < num_metrics; i++)
for (const string& metric : metrics)
{
string metrics_used = metrics[i];
string metrics_used = metric + "_USED";
metrics_used += "_USED";
auto it = usage_req.find(metrics[i]);
auto it = usage_req.find(metric);
if (it == usage_req.end())
{
continue;
}
q->vector_value(metrics[i], limit);
q->vector_value(metric, limit);
q->vector_value(metrics_used, usage);
if ( limit == DEFAULT )
{
if ( default_q != 0 )
{
default_q->vector_value(metrics[i], limit);
default_q->vector_value(metric, limit);
}
else
{
@ -235,7 +231,7 @@ bool Quota::check_quota(const string& qid,
{
ostringstream oss;
oss << "limit of " << limit << " reached for " << metrics[i]
oss << "limit of " << limit << " reached for " << metric
<< " quota in " << template_name;
if ( !qid.empty() )
@ -252,13 +248,11 @@ bool Quota::check_quota(const string& qid,
// -------------------------------------------------------------------------
// Add resource usage to quotas
// -------------------------------------------------------------------------
for (int i=0; i < num_metrics; i++)
for (const string& metric : metrics)
{
string metrics_used = metrics[i];
string metrics_used = metric + "_USED";
metrics_used += "_USED";
auto it = usage_req.find(metrics[i]);
auto it = usage_req.find(metric);
if (it == usage_req.end())
{
@ -288,13 +282,13 @@ void Quota::add_quota(const string& qid, map<string, float>& usage_req)
return;
}
for (int i=0; i < num_metrics; i++)
for (const string& metric : metrics)
{
string metrics_used = metrics[i];
string metrics_used = metric;
metrics_used += "_USED";
auto it = usage_req.find(metrics[i]);
auto it = usage_req.find(metric);
if (it == usage_req.end())
{
@ -322,13 +316,11 @@ void Quota::del_quota(const string& qid, map<string, float>& usage_req)
return;
}
for (int i=0; i < num_metrics; i++)
for (const string& metric : metrics)
{
string metrics_used = metrics[i];
string metrics_used = metric + "_USED";
metrics_used += "_USED";
auto it = usage_req.find(metrics[i]);
auto it = usage_req.find(metric);
if (it == usage_req.end())
{
@ -370,13 +362,11 @@ void Quota::cleanup_quota(const string& qid)
implicit_limit = DEFAULT;
}
for (int i=0; i < num_metrics; i++)
for (const string& metric : metrics)
{
string metrics_used = metrics[i];
string metrics_used = metric + "_USED";
metrics_used += "_USED";
q->vector_value(metrics[i], limit);
q->vector_value(metric, limit);
q->vector_value(metrics_used, usage);
if ( usage != 0 || limit != implicit_limit )
@ -399,9 +389,9 @@ int Quota::update_limits(
{
float limit_f;
for (int i=0; i < num_metrics; i++)
for (const string& metric : metrics)
{
const string& limit = va->vector_value_str(metrics[i], limit_f);
const string& limit = va->vector_value_str(metric, limit_f);
if (limit.empty())
{
@ -425,7 +415,7 @@ int Quota::update_limits(
return -1;
}
quota->replace(metrics[i], one_util::float_to_str(limit_f));
quota->replace(metric, one_util::float_to_str(limit_f));
}
return 0;
@ -440,13 +430,11 @@ VectorAttribute * Quota::new_quota(const VectorAttribute * va)
float limit_f;
for (int i=0; i < num_metrics; i++)
for (const string& metric : metrics)
{
string metrics_used = metrics[i];
string metrics_used = metric + "_USED";
metrics_used += "_USED";
const string& limit = va->vector_value_str(metrics[i], limit_f);
const string& limit = va->vector_value_str(metric, limit_f);
if (limit.empty())
{
@ -469,7 +457,7 @@ VectorAttribute * Quota::new_quota(const VectorAttribute * va)
return 0;
}
limits.insert(make_pair(metrics[i], one_util::float_to_str(limit_f)));
limits.insert(make_pair(metric, one_util::float_to_str(limit_f)));
limits.insert(make_pair(metrics_used, "0"));
}

View File

@ -22,9 +22,7 @@ using namespace std;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
const char * QuotaDatastore::DS_METRICS[] = {"SIZE", "IMAGES"};
const int QuotaDatastore::NUM_DS_METRICS = 2;
const std::vector<std::string> QuotaDatastore::DS_METRICS = {"SIZE", "IMAGES"};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -22,9 +22,7 @@ using namespace std;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
const char * QuotaImage::IMAGE_METRICS[] = {"RVMS"};
const int QuotaImage::NUM_IMAGE_METRICS = 1;
const std::vector<std::string> QuotaImage::IMAGE_METRICS = {"RVMS"};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -23,9 +23,7 @@ using namespace std;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
const char * QuotaNetwork::NET_METRICS[] = {"LEASES"};
const int QuotaNetwork::NUM_NET_METRICS = 1;
const std::vector<std::string> QuotaNetwork::NET_METRICS = {"LEASES"};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -24,10 +24,10 @@ using namespace std;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
const char * QuotaVirtualMachine::VM_METRICS[] = {"VMS", "RUNNING_VMS", "CPU",
std::vector<std::string> QuotaVirtualMachine::VM_METRICS = {"VMS", "RUNNING_VMS", "CPU",
"RUNNING_CPU", "MEMORY", "RUNNING_MEMORY", "SYSTEM_DISK_SIZE"};
const int QuotaVirtualMachine::NUM_VM_METRICS = 7;
std::vector<std::string> QuotaVirtualMachine::VM_GENERIC;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
@ -101,6 +101,20 @@ bool QuotaVirtualMachine::check(Template * tmpl,
vm_request.insert(make_pair("RUNNING_VMS", running_vms));
}
for (const auto& metric : VM_GENERIC)
{
float generic_quota;
if ( tmpl->get(metric, generic_quota) )
{
vm_request.insert(make_pair(metric, generic_quota));
}
if ( tmpl->get("RUNNING_" + metric, generic_quota) )
{
vm_request.insert(make_pair("RUNNING_" + metric, generic_quota));
}
}
return check_quota("", vm_request, default_quotas, error);
}
@ -149,6 +163,20 @@ void QuotaVirtualMachine::add(Template * tmpl)
vm_request.insert(make_pair("SYSTEM_DISK_SIZE", size));
for (const auto& metric : VM_GENERIC)
{
float generic_quota;
if ( tmpl->get(metric, generic_quota) )
{
vm_request.insert(make_pair(metric, generic_quota));
}
if ( tmpl->get("RUNNING_" + metric, generic_quota) )
{
vm_request.insert(make_pair("RUNNING_" + metric, generic_quota));
}
}
add_quota("", vm_request);
}
@ -199,12 +227,58 @@ void QuotaVirtualMachine::del(Template * tmpl)
vm_request.insert(make_pair("SYSTEM_DISK_SIZE", size));
for (const auto& metric : VM_GENERIC)
{
float generic_quota;
if ( tmpl->get(metric, generic_quota) )
{
vm_request.insert(make_pair(metric, generic_quota));
}
if ( tmpl->get("RUNNING_" + metric, generic_quota) )
{
vm_request.insert(make_pair("RUNNING_" + metric, generic_quota));
}
}
del_quota("", vm_request);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int QuotaVirtualMachine::add_metric_generic(const std::string& metric)
{
if (std::find(VM_METRICS.begin(), VM_METRICS.end(), metric) != VM_METRICS.end())
{
return -1;
}
VM_METRICS.push_back(metric);
VM_METRICS.push_back("RUNNING_" + metric);
VM_GENERIC.push_back(metric);
return 0;
}
/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */
void QuotaVirtualMachine::add_running_quota_generic(Template& tmpl)
{
for (const string& metric : VM_GENERIC)
{
string value;
if (tmpl.get(metric, value))
{
tmpl.add("RUNNING_" + metric, value);
}
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int QuotaVirtualMachine::get_default_quota(
const string& id,
Quotas& default_quotas,
@ -261,5 +335,19 @@ bool QuotaVirtualMachine::update(Template * tmpl,
vm_request.insert(make_pair("SYSTEM_DISK_SIZE", delta_size));
}
for (const auto& metric : VM_GENERIC)
{
float generic_quota;
if ( tmpl->get(metric, generic_quota) )
{
vm_request.insert(make_pair(metric, generic_quota));
}
if ( tmpl->get("RUNNING_" + metric, generic_quota) )
{
vm_request.insert(make_pair("RUNNING_" + metric, generic_quota));
}
}
return check_quota("", vm_request, default_quotas, error);
}

View File

@ -3950,28 +3950,56 @@ void VirtualMachine::decrypt()
/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */
void VirtualMachine::get_quota_template(VirtualMachineTemplate& quota_tmpl,
bool only_running)
bool VirtualMachine::is_running_quota() const
{
if ((state == VirtualMachine::PENDING) ||
(state == VirtualMachine::CLONING) ||
(state == VirtualMachine::CLONING_FAILURE) ||
(state == VirtualMachine::HOLD) ||
((state == VirtualMachine::ACTIVE &&
(lcm_state != VirtualMachine::HOTPLUG_SAVEAS_POWEROFF &&
lcm_state != VirtualMachine::HOTPLUG_SAVEAS_SUSPENDED &&
lcm_state != VirtualMachine::DISK_SNAPSHOT_POWEROFF &&
lcm_state != VirtualMachine::DISK_SNAPSHOT_REVERT_POWEROFF &&
lcm_state != VirtualMachine::DISK_SNAPSHOT_DELETE_POWEROFF &&
lcm_state != VirtualMachine::DISK_SNAPSHOT_SUSPENDED &&
lcm_state != VirtualMachine::DISK_SNAPSHOT_DELETE_SUSPENDED &&
lcm_state != VirtualMachine::DISK_RESIZE_POWEROFF &&
lcm_state != VirtualMachine::DISK_RESIZE_UNDEPLOYED &&
lcm_state != VirtualMachine::HOTPLUG_NIC_POWEROFF &&
lcm_state != VirtualMachine::HOTPLUG_SAVEAS_UNDEPLOYED &&
lcm_state != VirtualMachine::HOTPLUG_SAVEAS_STOPPED ))))
return (state == VirtualMachine::PENDING) ||
(state == VirtualMachine::CLONING) ||
(state == VirtualMachine::CLONING_FAILURE) ||
(state == VirtualMachine::HOLD) ||
((state == VirtualMachine::ACTIVE &&
(lcm_state != VirtualMachine::HOTPLUG_SAVEAS_POWEROFF &&
lcm_state != VirtualMachine::HOTPLUG_SAVEAS_SUSPENDED &&
lcm_state != VirtualMachine::DISK_SNAPSHOT_POWEROFF &&
lcm_state != VirtualMachine::DISK_SNAPSHOT_REVERT_POWEROFF &&
lcm_state != VirtualMachine::DISK_SNAPSHOT_DELETE_POWEROFF &&
lcm_state != VirtualMachine::DISK_SNAPSHOT_SUSPENDED &&
lcm_state != VirtualMachine::DISK_SNAPSHOT_DELETE_SUSPENDED &&
lcm_state != VirtualMachine::DISK_RESIZE_POWEROFF &&
lcm_state != VirtualMachine::DISK_RESIZE_UNDEPLOYED &&
lcm_state != VirtualMachine::HOTPLUG_NIC_POWEROFF &&
lcm_state != VirtualMachine::HOTPLUG_SAVEAS_UNDEPLOYED &&
lcm_state != VirtualMachine::HOTPLUG_SAVEAS_STOPPED &&
lcm_state != VirtualMachine::HOTPLUG_PROLOG_POWEROFF &&
lcm_state != VirtualMachine::HOTPLUG_EPILOG_POWEROFF )));
}
/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */
void VirtualMachine::get_quota_template(VirtualMachineTemplate& quota_tmpl,
bool basic_quota, bool running_quota)
{
if (basic_quota)
{
std::string memory, cpu;
quota_tmpl.replace("VMS", 1);
for (const string& metric : QuotaVirtualMachine::generic_metrics())
{
string value;
// Use value from user template, if it's not already added from template
if (user_obj_template->get(metric, value))
{
quota_tmpl.replace(metric, value);
}
}
quota_tmpl.merge(obj_template.get());
}
if (running_quota)
{
string memory, cpu;
get_template_attribute("MEMORY", memory);
get_template_attribute("CPU", cpu);
@ -3980,11 +4008,17 @@ void VirtualMachine::get_quota_template(VirtualMachineTemplate& quota_tmpl,
quota_tmpl.add("RUNNING_CPU", cpu);
quota_tmpl.add("RUNNING_VMS", 1);
if (!only_running)
for (const string& metric : QuotaVirtualMachine::generic_metrics())
{
quota_tmpl.add("MEMORY", memory);
quota_tmpl.add("CPU", cpu);
quota_tmpl.add("VMS", 1);
string value;
if (obj_template->get(metric, value))
{
quota_tmpl.add("RUNNING_" + metric, value);
}
else if (user_obj_template->get(metric, value))
{
quota_tmpl.add("RUNNING_" + metric, value);
}
}
}
}

View File

@ -476,7 +476,6 @@ void VirtualMachineDisk::resize_quotas(long long new_size, Template& ds_deltas,
delta_disk->replace("TYPE", "FS");
delta_disk->replace("SIZE", delta_size);
vm_deltas.add("VMS", 0);
vm_deltas.set(delta_disk);
}
}