1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-06 12:58:18 +03:00

Merge branch 'feature-1099'

This commit is contained in:
Ruben S. Montero 2012-05-11 19:21:12 +02:00
commit 2fe5e591e8
19 changed files with 910 additions and 359 deletions

View File

@ -45,7 +45,8 @@ public:
int hid,
const string& hostname,
const string& vmm,
const string& vnm);
const string& vnm,
const string& vm_info);
~History(){};
@ -69,9 +70,8 @@ private:
// ----------------------------------------
// DataBase implementation variables
// ----------------------------------------
static const char * table;
static const char * db_names;
static const char * db_bootstrap;
@ -104,6 +104,8 @@ private:
MigrationReason reason;
string vm_info;
// -------------------------------------------------------------------------
// Non-persistent history fields
// -------------------------------------------------------------------------
@ -169,6 +171,23 @@ private:
*/
int select_cb(void *nil, int num, char **values, char **names);
/**
* Function to print the History object into a string in
* XML format, to be stored in the DB. It includes the VM template info
* @param xml the resulting XML string
* @return a reference to the generated string
*/
string& to_db_xml(string& xml) const;
/**
* Function to print the History object into a string in
* XML format. The VM info can be optionally included
* @param xml the resulting XML string
* @param database If it is true, the TEMPLATE element will be included
* @return a reference to the generated string
*/
string& to_xml(string& xml, bool database) const;
/**
* Rebuilds the object from an xml node
* @param node The xml node pointer

View File

@ -154,6 +154,47 @@ public:
*/
virtual int dump(ostringstream& oss, const string& where) = 0;
// -------------------------------------------------------------------------
// Function to generate dump filters
// -------------------------------------------------------------------------
/**
* Creates a filter for those objects (oids) or objects owned by a given
* group that an user can access based on the ACL rules
* @param uid the user id
* @param gid the group id
* @param auth_object object type
* @param all returns if the user can access all objects
* @param filter the resulting filter string
*/
static void acl_filter(int uid,
int gid,
PoolObjectSQL::ObjectType auth_object,
bool& all,
string& filter);
/**
* Creates a filter for the objects owned by a given user/group
* @param uid the user id
* @param gid the group id
* @param filter_flag query type (ALL, MINE, GROUP)
* @param all user can access all objects
* @param filter the resulting filter string
*/
static void usr_filter(int uid,
int gid,
int filter_flag,
bool all,
const string& acl_str,
string& filter);
/**
* Creates a filter for a given set of objects based on their id
* @param start_id first id
* @param end_id last id
* @param filter the resulting filter string
*/
static void oid_filter(int start_id,
int end_id,
string& filter);
protected:
/**
@ -182,8 +223,23 @@ protected:
*
* @return 0 on success
*/
int dump(ostringstream& oss, const string& elem_name,
const char * table, const string& where);
int dump(ostringstream& oss,
const string& elem_name,
const char * table,
const string& where);
/**
* Dumps the output of the custom sql query into an xml
*
* @param oss The output stream to dump the xml contents
* @param root_elem_name Name of the root xml element name
* @param sql_query The SQL query to execute
*
* @return 0 on success
*/
int dump(ostringstream& oss,
const string& root_elem_name,
ostringstream& sql_query);
/* ---------------------------------------------------------------------- */
/* Interface to access the lastOID assigned by the pool */

View File

@ -29,6 +29,16 @@ using namespace std;
class RequestManagerPoolInfoFilter: public Request
{
public:
/** Specify all objects the user has right to USE (-2) */
static const int ALL;
/** Specify user's objects in the pool (-3) */
static const int MINE;
/** Specify user's + group objects (-1) */
static const int MINE_GROUP;
protected:
RequestManagerPoolInfoFilter(const string& method_name,
const string& help,
@ -40,27 +50,26 @@ protected:
/* -------------------------------------------------------------------- */
/** Specify all objects the user has right to USE (-2) */
static const int ALL;
/** Specify user's objects in the pool (-3) */
static const int MINE;
/** Specify user's + group objects (-1) */
static const int MINE_GROUP;
/* -------------------------------------------------------------------- */
virtual void request_execute(
xmlrpc_c::paramList const& paramList, RequestAttributes& att);
/* -------------------------------------------------------------------- */
void dump(RequestAttributes& att,
void where_filter(RequestAttributes& att,
int filter_flag,
int start_id,
int end_id,
const string& and_clause,
const string& or_clause,
string& where_string);
/* -------------------------------------------------------------------- */
void dump(RequestAttributes& att,
int filter_flag,
int start_id,
int start_id,
int end_id,
const string& and_clause,
const string& and_clause,
const string& or_clause);
};
@ -98,6 +107,31 @@ public:
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
class VirtualMachinePoolAccounting : public RequestManagerPoolInfoFilter
{
public:
VirtualMachinePoolAccounting():
RequestManagerPoolInfoFilter("VirtualMachinePoolAccounting",
"Returns the virtual machine history records",
"A:siii")
{
Nebula& nd = Nebula::instance();
pool = nd.get_vmpool();
auth_object = PoolObjectSQL::VM;
};
~VirtualMachinePoolAccounting(){};
/* -------------------------------------------------------------------- */
void request_execute(
xmlrpc_c::paramList const& paramList, RequestAttributes& att);
};
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
class TemplatePoolInfo : public RequestManagerPoolInfoFilter
{
public:

View File

@ -122,7 +122,10 @@ public:
* @param xml the resulting XML string
* @return a reference to the generated string
*/
string& to_xml(string& xml) const;
string& to_xml(string& xml) const
{
return to_xml_extended(xml, 1);
}
/**
* Function to print the VirtualMachine object into a string in
@ -130,7 +133,10 @@ public:
* @param xml the resulting XML string
* @return a reference to the generated string
*/
string& to_xml_extended(string& xml) const;
string& to_xml_extended(string& xml) const
{
return to_xml_extended(xml, 2);
}
/**
* Rebuilds the object from an xml formatted string
@ -156,7 +162,7 @@ public:
/**
* Updates VM dynamic information (usage counters).
* @param _memory used by the VM (total)
* @param _memory Kilobytes used by the VM (total)
* @param _cpu used by the VM (rate)
* @param _net_tx transmitted bytes (total)
* @param _net_tx received bytes (total)
@ -199,7 +205,7 @@ public:
/**
* Sets the VM exit time
* @param _et VM exit time (when it arraived DONE/FAILED states)
* @param _et VM exit time (when it arrived DONE/FAILED states)
*/
void set_exit_time(time_t et)
{
@ -428,6 +434,22 @@ public:
history->stime=_stime;
};
/**
* Sets VM info (with monitoring info) in the history record
*/
void set_vm_info()
{
to_xml_extended(history->vm_info, 0);
};
/**
* Sets VM info (with monitoring info) in the previous history record
*/
void set_previous_vm_info()
{
to_xml_extended(previous_history->vm_info, 0);
};
/**
* Sets end time of a VM.
* @param _etime time when the VM finished
@ -757,7 +779,7 @@ private:
string deploy_id;
/**
* Memory in Megabytes used by the VM
* Memory in Kilobytes used by the VM
*/
int memory;
@ -767,12 +789,12 @@ private:
int cpu;
/**
* Network usage, transmitted Kilobytes
* Network usage, transmitted bytes
*/
int net_tx;
/**
* Network usage, received Kilobytes
* Network usage, received bytes
*/
int net_rx;
@ -916,10 +938,13 @@ private:
* Function that renders the VM in XML format optinally including
* extended information (all history records)
* @param xml the resulting XML string
* @param extended include additional info if true
* @param n_history Number of history records to include:
* 0: none
* 1: the last one
* 2: all
* @return a reference to the generated string
*/
string& to_xml_extended(string& xml, bool extended) const;
string& to_xml_extended(string& xml, int n_history) const;
protected:
@ -939,7 +964,7 @@ protected:
// *************************************************************************
// DataBase implementation
// *************************************************************************
static const char * table;
static const char * db_names;

View File

@ -143,8 +143,20 @@ public:
int dump(ostringstream& oss, const string& where)
{
return PoolSQL::dump(oss, "VM_POOL", VirtualMachine::table, where);
}
};
/**
* Dumps the VM accounting information in XML format. A filter can be also
* added to the query as well as a time frame.
* @param oss the output stream to dump the pool contents
* @param where filter for the objects, defaults to all
*
* @return 0 on success
*/
int dump_acct(ostringstream& oss,
const string& where,
int time_start,
int time_end);
private:
/**
* Factory method to produce VM objects

127
share/doc/xsd/acct.xsd Normal file
View File

@ -0,0 +1,127 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
targetNamespace="http://opennebula.org/XMLSchema" xmlns="http://opennebula.org/XMLSchema">
<xs:element name="HISTORY_RECORDS">
<xs:complexType>
<xs:sequence maxOccurs="1" minOccurs="1">
<xs:element ref="HISTORY" maxOccurs="unbounded" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="HISTORY">
<xs:complexType>
<xs:sequence>
<xs:element name="OID" type="xs:integer"/>
<xs:element name="SEQ" type="xs:integer"/>
<xs:element name="HOSTNAME" type="xs:string"/>
<xs:element name="HID" type="xs:integer"/>
<xs:element name="STIME" type="xs:integer"/>
<xs:element name="ETIME" type="xs:integer"/>
<xs:element name="VMMMAD" type="xs:string"/>
<xs:element name="VNMMAD" type="xs:string"/>
<xs:element name="PSTIME" type="xs:integer"/>
<xs:element name="PETIME" type="xs:integer"/>
<xs:element name="RSTIME" type="xs:integer"/>
<xs:element name="RETIME" type="xs:integer"/>
<xs:element name="ESTIME" type="xs:integer"/>
<xs:element name="EETIME" type="xs:integer"/>
<!-- REASON values:
NONE = 0 Normal termination
ERROR = 1 The VM ended in error
STOP_RESUME = 2 Stop/resume request
USER = 3 Migration request
CANCEL = 4 Cancel request
-->
<xs:element name="REASON" type="xs:integer"/>
<xs:element name="VM">
<xs:complexType>
<xs:sequence>
<xs:element name="ID" type="xs:integer"/>
<xs:element name="UID" type="xs:integer"/>
<xs:element name="GID" type="xs:integer"/>
<xs:element name="UNAME" type="xs:string"/>
<xs:element name="GNAME" type="xs:string"/>
<xs:element name="NAME" type="xs:string"/>
<xs:element name="PERMISSIONS" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:element name="OWNER_U" type="xs:integer"/>
<xs:element name="OWNER_M" type="xs:integer"/>
<xs:element name="OWNER_A" type="xs:integer"/>
<xs:element name="GROUP_U" type="xs:integer"/>
<xs:element name="GROUP_M" type="xs:integer"/>
<xs:element name="GROUP_A" type="xs:integer"/>
<xs:element name="OTHER_U" type="xs:integer"/>
<xs:element name="OTHER_M" type="xs:integer"/>
<xs:element name="OTHER_A" type="xs:integer"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="LAST_POLL" type="xs:integer"/>
<!-- STATE values,
see http://opennebula.org/_media/documentation:rel3.2:states-complete.png
INIT = 0
PENDING = 1
HOLD = 2
ACTIVE = 3 In this state, the Life Cycle Manager state is relevant
STOPPED = 4
SUSPENDED = 5
DONE = 6
FAILED = 7
-->
<xs:element name="STATE" type="xs:integer"/>
<!-- LCM_STATE values, this sub-state is relevant only when STATE is
ACTIVE (4)
LCM_INIT = 0
PROLOG = 1
BOOT = 2
RUNNING = 3
MIGRATE = 4
SAVE_STOP = 5
SAVE_SUSPEND = 6
SAVE_MIGRATE = 7
PROLOG_MIGRATE = 8
PROLOG_RESUME = 9
EPILOG_STOP = 10
EPILOG = 11
SHUTDOWN = 12
CANCEL = 13
FAILURE = 14
CLEANUP = 15
UNKNOWN = 16
-->
<xs:element name="LCM_STATE" type="xs:integer"/>
<xs:element name="RESCHED" type="xs:integer"/>
<xs:element name="STIME" type="xs:integer"/>
<xs:element name="ETIME" type="xs:integer"/>
<xs:element name="DEPLOY_ID" type="xs:string"/>
<!-- MEMORY consumption in kilobytes -->
<xs:element name="MEMORY" type="xs:integer"/>
<!-- Percentage of 1 CPU consumed (two fully consumed cpu is 200) -->
<xs:element name="CPU" type="xs:integer"/>
<!-- NET_TX: Sent bytes to the network -->
<xs:element name="NET_TX" type="xs:integer"/>
<!-- NET_RX: Received bytes from the network -->
<xs:element name="NET_RX" type="xs:integer"/>
<xs:element name="TEMPLATE" type="xs:anyType"/>
<xs:element name="HISTORY_RECORDS">
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@ -28,6 +28,7 @@
<xs:element name="DS_MAD" type="xs:string"/>
<xs:element name="TM_MAD" type="xs:string"/>
<xs:element name="BASE_PATH" type="xs:string"/>
<xs:element name="DISK_TYPE" type="xs:integer"/>
<xs:element name="CLUSTER_ID" type="xs:integer"/>
<xs:element name="CLUSTER" type="xs:string"/>
<xs:element name="IMAGES">

View File

@ -25,6 +25,7 @@
</xs:complexType>
</xs:element>
<xs:element name="TYPE" type="xs:integer"/>
<xs:element name="DISK_TYPE" type="xs:integer"/>
<xs:element name="PERSISTENT" type="xs:integer"/>
<xs:element name="REGTIME" type="xs:integer"/>
<xs:element name="SOURCE" type="xs:string"/>

View File

@ -26,14 +26,58 @@
</xs:complexType>
</xs:element>
<xs:element name="LAST_POLL" type="xs:integer"/>
<!-- STATE values,
see http://opennebula.org/_media/documentation:rel3.2:states-complete.png
INIT = 0
PENDING = 1
HOLD = 2
ACTIVE = 3 In this state, the Life Cycle Manager state is relevant
STOPPED = 4
SUSPENDED = 5
DONE = 6
FAILED = 7
-->
<xs:element name="STATE" type="xs:integer"/>
<!-- LCM_STATE values, this sub-state is relevant only when STATE is
ACTIVE (4)
LCM_INIT = 0
PROLOG = 1
BOOT = 2
RUNNING = 3
MIGRATE = 4
SAVE_STOP = 5
SAVE_SUSPEND = 6
SAVE_MIGRATE = 7
PROLOG_MIGRATE = 8
PROLOG_RESUME = 9
EPILOG_STOP = 10
EPILOG = 11
SHUTDOWN = 12
CANCEL = 13
FAILURE = 14
CLEANUP = 15
UNKNOWN = 16
-->
<xs:element name="LCM_STATE" type="xs:integer"/>
<xs:element name="RESCHED" type="xs:integer"/>
<xs:element name="STIME" type="xs:integer"/>
<xs:element name="ETIME" type="xs:integer"/>
<xs:element name="DEPLOY_ID" type="xs:string"/>
<!-- MEMORY consumption in kilobytes -->
<xs:element name="MEMORY" type="xs:integer"/>
<!-- Percentage of 1 CPU consumed (two fully consumed cpu is 200) -->
<xs:element name="CPU" type="xs:integer"/>
<!-- NET_TX: Sent bytes to the network -->
<xs:element name="NET_TX" type="xs:integer"/>
<!-- NET_RX: Received bytes from the network -->
<xs:element name="NET_RX" type="xs:integer"/>
<xs:element name="TEMPLATE" type="xs:anyType"/>
<xs:element name="HISTORY_RECORDS">
@ -42,21 +86,28 @@
<xs:element name="HISTORY" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="OID" type="xs:integer"/>
<xs:element name="SEQ" type="xs:integer"/>
<xs:element name="HOSTNAME" type="xs:string"/>
<xs:element name="VM_DIR" type="xs:string"/>
<xs:element name="HID" type="xs:integer"/>
<xs:element name="STIME" type="xs:integer"/>
<xs:element name="ETIME" type="xs:integer"/>
<xs:element name="VMMMAD" type="xs:string"/>
<xs:element name="VNMMAD" type="xs:string"/>
<xs:element name="TMMAD" type="xs:string"/>
<xs:element name="PSTIME" type="xs:integer"/>
<xs:element name="PETIME" type="xs:integer"/>
<xs:element name="RSTIME" type="xs:integer"/>
<xs:element name="RETIME" type="xs:integer"/>
<xs:element name="ESTIME" type="xs:integer"/>
<xs:element name="EETIME" type="xs:integer"/>
<!-- REASON values:
NONE = 0 Normal termination
ERROR = 1 The VM ended in error
STOP_RESUME = 2 Stop/resume request
USER = 3 Migration request
CANCEL = 4 Cancel request
-->
<xs:element name="REASON" type="xs:integer"/>
</xs:sequence>
</xs:complexType>

View File

@ -1,25 +1,20 @@
#!/usr/bin/env ruby
# --------------------------------------------------------------------------
# Copyright 2010-2012, C12G Labs S.L.
#
# This file is part of OpenNebula addons.
#
# OpenNebula addons are free software: you can redistribute it
# and/or modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation, either version 3 of
# the License, or the hope That it will be useful, but (at your
# option) any later version.
#
# OpenNebula addons are distributed in WITHOUT ANY WARRANTY;
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License
# along with OpenNebula addons. If not, see
# <http://www.gnu.org/licenses/>
# --------------------------------------------------------------------------
# -------------------------------------------------------------------------- #
# Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) #
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
# not use this file except in compliance with the License. You may obtain #
# a copy of the License at #
# #
# http://www.apache.org/licenses/LICENSE-2.0 #
# #
# Unless required by applicable law or agreed to in writing, software #
# distributed under the License is distributed on an "AS IS" BASIS, #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
# See the License for the specific language governing permissions and #
# limitations under the License. #
#--------------------------------------------------------------------------- #
ONE_LOCATION=ENV["ONE_LOCATION"]
@ -35,7 +30,6 @@ $: << RUBY_LIB_LOCATION+"/cli"
require 'rubygems'
require 'acct/oneacct'
require 'cli/one_helper'
require 'cli/command_parser'
require 'json'
@ -43,164 +37,171 @@ require 'json'
require 'optparse'
require 'optparse/time'
REG_DATE=/((\d{4})\/)?(\d\d?)(\/(\d\d?))?/
REG_TIME=/(\d\d?):(\d\d?)(:(\d\d?))?/
class AcctHelper
def format_vm(options=nil)
table = CLIHelper::ShowTable.new(nil, nil) do
column :VMID, "VM ID", :size=>4 do |d|
d[:vmid]
def initialize(client)
@client = client
end
=begin
List of <HISTORY> child elements
OID
SEQ
HOSTNAME
HID
STIME
ETIME
VMMMAD
VNMMAD
PSTIME
PETIME
RSTIME
RETIME
ESTIME
EETIME
REASON
=end
def list_history(data)
table = CLIHelper::ShowTable.new(nil, self) do
column :VID, "Virtual Machine ID", :size=>4 do |d|
d["OID"]
end
column :MEMORY, "Consumed memory", :right, :size=>8 do |d|
OpenNebulaHelper.unit_to_str(
d[:slices].first[:mem]*1024,
{})
column :SEQ, "History record sequence number", :size=>3 do |d|
d["SEQ"]
end
column :CPU, "Group of the User", :right, :size=>8 do |d|
d[:slices].first[:cpu]
column :HOSTNAME, "Host name", :size=>15 do |d|
d["HOSTNAME"]
end
column :NETRX, "Group of the User", :right, :size=>10 do |d|
OpenNebulaHelper.unit_to_str(
d[:network][:net_rx].to_i/1024.0,
{})
column :REASON, "VM state change reason", :size=>4 do |d|
VirtualMachine.get_reason d["REASON"]
end
column :NETTX, "Group of the User", :right, :size=>10 do |d|
OpenNebulaHelper.unit_to_str(
d[:network][:net_tx].to_i/1024.0,
{})
column :START_TIME, "Start time", :size=>14 do |d|
OpenNebulaHelper.time_to_str(d['STIME'])
end
column :TIME, "Group of the User", :right, :size=>15 do |d|
OpenNebulaHelper.period_to_str(d[:time])
column :END_TIME, "End time", :size=>14 do |d|
OpenNebulaHelper.time_to_str(d['ETIME'])
end
default :VMID, :MEMORY, :CPU, :NETRX, :NETTX, :TIME
column :MEMORY, "Assigned memory", :right, :size=>6 do |d|
OpenNebulaHelper.unit_to_str(d["VM/TEMPLATE/MEMORY"].to_i, {}, 'M')
end
column :CPU, "Number of CPUs", :right, :size=>3 do |d|
d["VM/TEMPLATE/CPU"]
end
column :NET_RX, "Data received from the network", :right, :size=>6 do |d|
# NET is measured in bytes, unit_to_str expects KBytes
OpenNebulaHelper.unit_to_str(d["VM/NET_RX"].to_i / 1024.0, {})
end
column :NET_TX, "Data sent to the network", :right, :size=>6 do |d|
# NET is measured in bytes, unit_to_str expects KBytes
OpenNebulaHelper.unit_to_str(d["VM/NET_TX"].to_i / 1024.0, {})
end
default :VID, :HOSTNAME, :REASON, :START_TIME, :END_TIME, :MEMORY, :CPU, :NET_RX, :NET_TX
end
table
table.show(data)
end
def list_vms(data)
format_vm().show(data)
end
public
def list_users(xml_info, options=nil)
def list_users(filters)
a=gen_accounting(filters)
xmldoc = XMLElement.new
xmldoc.initialize_xml(xml_info, 'HISTORY_RECORDS')
a.each do |user, data|
uids = xmldoc.retrieve_elements('HISTORY/VM/UID')
if uids.nil?
puts "No records found."
exit 0
end
uids.uniq!
history_elems = []
uids.each do |uid|
CLIHelper.scr_bold
CLIHelper.scr_underline
puts "# User #{user}"
# TODO: username?
puts "# User #{uid} "
CLIHelper.scr_restore
puts
vms=data[:vms].map do |k, v|
v
end
history_elems.clear
self.list_vms(vms)
vm_ids = xmldoc.retrieve_elements("HISTORY/VM[UID=#{uid}]/ID")
vm_ids.uniq!
puts
puts
vm_ids.each do |vid|
end
end
def gen_accounting(filters)
acct=AcctClient.new(filters)
acct.account()
end
def gen_json(filters)
begin
require 'json'
rescue LoadError
STDERR.puts "JSON gem is needed to give the result in this format"
exit(-1)
end
acct=gen_accounting(filters)
acct.to_json
end
def xml_tag(tag, value)
"<#{tag}>#{value}</#{tag}>\n"
end
def gen_xml(filters)
acct=gen_accounting(filters)
xml=""
acct.each do |user, data|
xml<<"<user id=\"#{user}\">\n"
data[:vms].each do |vmid, vm|
xml<<" <vm id=\"#{vmid}\">\n"
xml<<" "<<xml_tag(:name, vm[:name])
xml<<" "<<xml_tag(:time, vm[:time])
xml<<" "<<xml_tag(:cpu, vm[:slices].first[:cpu])
xml<<" "<<xml_tag(:mem, vm[:slices].first[:mem])
xml<<" "<<xml_tag(:net_rx, vm[:network][:net_rx])
xml<<" "<<xml_tag(:net_tx, vm[:network][:net_tx])
vm[:slices].each do |slice|
xml<<" <slice seq=\"#{slice[:seq]}\">\n"
slice.each do |key, value|
xml<<" "<<xml_tag(key, value)
end
xml<<" </slice>\n"
if ( options[:split] )
history_elems.clear
end
xml<<" </vm>\n"
xmldoc.each("HISTORY[OID=#{vid}]") do |history|
history_elems << history
end
if ( options[:split] )
list_history(history_elems)
puts
end
end
xml<<"</user>\n"
if ( !options[:split] )
list_history(history_elems)
puts
end
end
xml
end
end
@options=Hash.new
options = Hash.new
@options[:format]=:table
options[:format] = :table
opts=OptionParser.new do |opts|
opts = OptionParser.new do |opts|
opts.on('-s', '--start TIME', Time,
'Start date and time to take into account') do |ext|
@options[:start]=ext
options[:start]=ext
end
opts.on("-e", "--end TIME", Time,
"End date and time" ) do |ext|
@options[:end]=ext
options[:end]=ext
end
# TODO: Allow username
opts.on("-u", "--user user", Integer,
"User id to make accounting" ) do |ext|
@options[:user]=ext.to_i
options[:user]=ext.to_i
end
opts.on("-j", "--json",
"Output in json format" ) do |ext|
@options[:format]=:json
options[:format]=:json
end
opts.on("-x", "--xml",
"Output in xml format" ) do |ext|
@options[:format]=:xml
options[:format]=:xml
end
opts.on("--split",
"Split the output in a table for each VM" ) do |ext|
options[:split]=ext
end
opts.on()
@ -215,27 +216,68 @@ rescue OptionParser::ParseError => e
end
acct_helper=AcctHelper.new
client = OpenNebula::Client.new
acct_helper = AcctHelper.new(client)
time_start = -1
time_end = -1
filter_flag = VirtualMachinePool::INFO_ALL
time_start = options[:start].to_i if options[:start]
time_end = options[:end].to_i if options[:end]
filter_flag = options[:user].to_i if options[:user]
filters=Hash.new
ret = client.call("vmpool.accounting",
filter_flag,
time_start,
time_end)
filters[:start]=@options[:start].to_i if @options[:start]
filters[:end]=@options[:end].to_i if @options[:end]
filters[:user]=@options[:user].to_i if @options[:user]
case @options[:format]
when :table
acct_helper.list_users(filters)
when :json
puts acct_helper.gen_json(filters)
when :xml
puts acct_helper.gen_xml(filters)
if OpenNebula.is_error?(ret)
puts ret.message
exit -1
end
case options[:format]
when :table
if ( time_start != -1 or time_end != -1 )
print "Showing active history records from "
CLIHelper.scr_bold
if ( time_start != -1 )
print Time.at(time_start).to_s
else
print "-"
end
CLIHelper.scr_restore
print " to "
CLIHelper.scr_bold
if ( time_end != -1 )
print Time.at(time_end).to_s
else
print "-"
end
CLIHelper.scr_restore
puts
puts
end
acct_helper.list_users(ret, options)
when :xml
puts ret
when :json
xmldoc = XMLElement.new
xmldoc.initialize_xml(ret, 'HISTORY_RECORDS')
puts xmldoc.to_hash.to_json
end

View File

@ -615,6 +615,7 @@ void LifeCycleManager::clean_up_vm(VirtualMachine * vm)
vmpool->update(vm);
vm->set_etime(the_time);
vm->set_vm_info();
vm->set_reason(History::USER);
vm->get_requirements(cpu,mem,disk);
@ -650,6 +651,7 @@ void LifeCycleManager::clean_up_vm(VirtualMachine * vm)
vmpool->update_history(vm);
vm->set_previous_etime(the_time);
vm->set_previous_vm_info();
vm->set_previous_running_etime(the_time);
vm->set_previous_reason(History::USER);
vmpool->update_previous_history(vm);
@ -680,6 +682,7 @@ void LifeCycleManager::clean_up_vm(VirtualMachine * vm)
vmpool->update_history(vm);
vm->set_previous_etime(the_time);
vm->set_previous_vm_info();
vm->set_previous_running_etime(the_time);
vm->set_previous_reason(History::USER);
vmpool->update_previous_history(vm);

View File

@ -49,6 +49,8 @@ void LifeCycleManager::save_success_action(int vid)
vm->set_previous_etime(the_time);
vm->set_previous_vm_info();
vm->set_previous_running_etime(the_time);
vm->set_previous_reason(History::USER);
@ -84,6 +86,8 @@ void LifeCycleManager::save_success_action(int vid)
vm->set_etime(the_time);
vm->set_vm_info();
vm->set_reason(History::STOP_RESUME);
vmpool->update_history(vm);
@ -162,6 +166,8 @@ void LifeCycleManager::save_failure_action(int vid)
vm->set_etime(the_time);
vm->set_vm_info();
vm->set_reason(History::ERROR);
vmpool->update_history(vm);
@ -172,6 +178,8 @@ void LifeCycleManager::save_failure_action(int vid)
vm->set_previous_etime(the_time);
vm->set_previous_vm_info();
vm->set_previous_running_etime(the_time);
vm->set_previous_reason(History::USER);
@ -251,6 +259,8 @@ void LifeCycleManager::deploy_success_action(int vid)
vm->set_previous_etime(the_time);
vm->set_previous_vm_info();
vm->set_previous_running_etime(the_time);
vm->set_previous_reason(History::USER);
@ -304,10 +314,14 @@ void LifeCycleManager::deploy_failure_action(int vid)
vm->set_etime(the_time);
vm->set_vm_info();
vm->set_reason(History::ERROR);
vm->set_previous_etime(the_time);
vm->set_previous_vm_info();
vm->set_previous_running_etime(the_time);
vm->set_previous_reason(History::USER);
@ -554,6 +568,8 @@ void LifeCycleManager::epilog_success_action(int vid)
vm->set_etime(the_time);
vm->set_vm_info();
vmpool->update_history(vm);
vm->get_requirements(cpu,mem,disk);
@ -727,6 +743,8 @@ void LifeCycleManager::monitor_suspend_action(int vid)
vm->set_etime(the_time);
vm->set_vm_info();
vm->set_reason(History::STOP_RESUME);
vmpool->update_history(vm);
@ -799,6 +817,8 @@ void LifeCycleManager::failure_action(VirtualMachine * vm)
vm->set_etime(the_time);
vm->set_vm_info();
vm->set_reason(History::ERROR);
vmpool->update_history(vm);

View File

@ -21,6 +21,7 @@
#include <algorithm>
#include "PoolSQL.h"
#include "RequestManagerPoolInfoFilter.h"
#include <errno.h>
@ -479,14 +480,8 @@ int PoolSQL::dump(ostringstream& oss,
const char * table,
const string& where)
{
int rc;
ostringstream cmd;
oss << "<" << elem_name << ">";
set_callback(static_cast<Callbackable::Callback>(&PoolSQL::dump_cb),
static_cast<void *>(&oss));
cmd << "SELECT body FROM " << table;
if ( !where.empty() )
@ -496,9 +491,26 @@ int PoolSQL::dump(ostringstream& oss,
cmd << " ORDER BY oid";
rc = db->exec(cmd, this);
return dump(oss, elem_name, cmd);
}
oss << "</" << elem_name << ">";
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int PoolSQL::dump(ostringstream& oss,
const string& root_elem_name,
ostringstream& sql_query)
{
int rc;
oss << "<" << root_elem_name << ">";
set_callback(static_cast<Callbackable::Callback>(&PoolSQL::dump_cb),
static_cast<void *>(&oss));
rc = db->exec(sql_query, this);
oss << "</" << root_elem_name << ">";
unset_callback();
@ -546,3 +558,120 @@ int PoolSQL::search(
return rc;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void PoolSQL::acl_filter(int uid,
int gid,
PoolObjectSQL::ObjectType auth_object,
bool& all,
string& filter)
{
filter.clear();
if ( uid == 0 || gid == 0 )
{
all = true;
return;
}
Nebula& nd = Nebula::instance();
AclManager* aclm = nd.get_aclm();
ostringstream acl_filter;
vector<int>::iterator it;
vector<int> oids;
vector<int> gids;
aclm->reverse_search(uid,
gid,
auth_object,
AuthRequest::USE,
all,
oids,
gids);
for ( it = oids.begin(); it < oids.end(); it++ )
{
acl_filter << " OR oid = " << *it;
}
for ( it = gids.begin(); it < gids.end(); it++ )
{
acl_filter << " OR gid = " << *it;
}
filter = acl_filter.str();
}
/* -------------------------------------------------------------------------- */
void PoolSQL::usr_filter(int uid,
int gid,
int filter_flag,
bool all,
const string& acl_str,
string& filter)
{
ostringstream uid_filter;
if ( filter_flag == RequestManagerPoolInfoFilter::MINE )
{
uid_filter << "uid = " << uid;
}
else if ( filter_flag == RequestManagerPoolInfoFilter::MINE_GROUP )
{
uid_filter << " uid = " << uid
<< " OR ( gid = " << gid << " AND group_u = 1 )";
}
else if ( filter_flag == RequestManagerPoolInfoFilter::ALL )
{
if (!all)
{
uid_filter << " uid = " << uid
<< " OR ( gid = " << gid << " AND group_u = 1 )"
<< " OR other_u = 1"
<< acl_str;
}
}
else
{
uid_filter << "uid = " << filter_flag;
if ( filter_flag != uid && !all )
{
uid_filter << " AND ("
<< " ( gid = " << gid << " AND group_u = 1)"
<< " OR other_u = 1"
<< acl_str
<< ")";
}
}
filter = uid_filter.str();
}
/* -------------------------------------------------------------------------- */
void PoolSQL::oid_filter(int start_id,
int end_id,
string& filter)
{
ostringstream idfilter;
if ( start_id != -1 )
{
idfilter << "oid >= " << start_id;
if ( end_id != -1 )
{
idfilter << " AND oid <= " << end_id;
}
}
filter = idfilter.str();
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -243,6 +243,7 @@ void RequestManager::register_xml_methods()
xmlrpc_c::methodPtr vm_migrate(new VirtualMachineMigrate());
xmlrpc_c::methodPtr vm_action(new VirtualMachineAction());
xmlrpc_c::methodPtr vm_savedisk(new VirtualMachineSaveDisk());
xmlrpc_c::methodPtr vm_pool_acct(new VirtualMachinePoolAccounting());
// VirtualNetwork Methods
xmlrpc_c::methodPtr vn_addleases(new VirtualNetworkAddLeases());
@ -348,6 +349,7 @@ void RequestManager::register_xml_methods()
RequestManagerRegistry.addMethod("one.vm.chmod", vm_chmod);
RequestManagerRegistry.addMethod("one.vmpool.info", vm_pool_info);
RequestManagerRegistry.addMethod("one.vmpool.accounting", vm_pool_acct);
/* VM Template related methods*/
RequestManagerRegistry.addMethod("one.template.update", template_update);

View File

@ -91,6 +91,46 @@ void VirtualMachinePoolInfo::request_execute(
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
void VirtualMachinePoolAccounting::request_execute(
xmlrpc_c::paramList const& paramList,
RequestAttributes& att)
{
int filter_flag = xmlrpc_c::value_int(paramList.getInt(1));
int time_start = xmlrpc_c::value_int(paramList.getInt(2));
int time_end = xmlrpc_c::value_int(paramList.getInt(3));
ostringstream oss;
string where;
int rc;
if ( filter_flag < MINE )
{
failure_response(XML_RPC_API,
request_error("Incorrect filter_flag",""),
att);
return;
}
where_filter(att, filter_flag, -1, -1, "", "", where);
rc = (static_cast<VirtualMachinePool *>(pool))->dump_acct(oss,
where,
time_start,
time_end);
if ( rc != 0 )
{
failure_response(INTERNAL,request_error("Internal Error",""), att);
return;
}
success_response(oss.str(), att);
return;
}
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
void HostPoolInfo::request_execute(
xmlrpc_c::paramList const& paramList,
RequestAttributes& att)
@ -141,6 +181,79 @@ void ClusterPoolInfo::request_execute(
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
void RequestManagerPoolInfoFilter::where_filter(
RequestAttributes& att,
int filter_flag,
int start_id,
int end_id,
const string& and_clause,
const string& or_clause,
string& filter_str)
{
bool empty = true;
bool all;
string acl_str;
string uid_str;
string oid_str;
ostringstream filter;
PoolSQL::acl_filter(att.uid, att.gid, auth_object, all, acl_str);
PoolSQL::usr_filter(att.uid, att.gid, filter_flag, all, acl_str, uid_str);
PoolSQL::oid_filter(start_id, end_id, oid_str);
// -------------------------------------------------------------------------
// Compound WHERE clause
// WHERE ( id_str ) AND ( uid_str ) AND ( and_clause ) OR ( or_clause )
// -------------------------------------------------------------------------
if (!oid_str.empty())
{
filter << "(" << oid_str << ")" ;
empty = false;
}
if (!uid_str.empty())
{
if (!empty)
{
filter << " AND ";
}
filter << "(" << uid_str << ")";
empty = false;
}
if (!and_clause.empty())
{
if (!empty)
{
filter << " AND ";
}
filter << "(" << and_clause << ")";
empty = false;
}
if (!or_clause.empty())
{
if (!empty)
{
filter << " OR ";
}
filter << "(" << or_clause << ")";
}
filter_str = filter.str();
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void RequestManagerPoolInfoFilter::dump(
RequestAttributes& att,
int filter_flag,
@ -149,20 +262,9 @@ void RequestManagerPoolInfoFilter::dump(
const string& and_clause,
const string& or_clause)
{
set<int>::iterator it;
ostringstream oss;
bool empty = true;
ostringstream where_string;
ostringstream uid_filter;
ostringstream id_filter;
string uid_str;
string acl_str;
string id_str;
int rc;
string where_string;
int rc;
if ( filter_flag < MINE )
{
@ -172,148 +274,15 @@ void RequestManagerPoolInfoFilter::dump(
return;
}
Nebula& nd = Nebula::instance();
AclManager* aclm = nd.get_aclm();
bool all;
vector<int> oids;
vector<int> gids;
where_filter(att,
filter_flag,
start_id,
end_id,
and_clause,
or_clause,
where_string);
// -------------------------------------------------------------------------
// User ID filter
// -------------------------------------------------------------------------
if ( att.uid == 0 || att.gid == 0 )
{
all = true;
}
else
{
ostringstream acl_filter;
vector<int>::iterator it;
aclm->reverse_search(att.uid,
att.gid,
auth_object,
AuthRequest::USE,
all,
oids,
gids);
for ( it = oids.begin(); it < oids.end(); it++ )
{
acl_filter << " OR oid = " << *it;
}
for ( it = gids.begin(); it < gids.end(); it++ )
{
acl_filter << " OR gid = " << *it;
}
acl_str = acl_filter.str();
}
switch ( filter_flag )
{
case MINE:
uid_filter << "uid = " << att.uid;
break;
case MINE_GROUP:
uid_filter << " uid = " << att.uid
<< " OR ( gid = " << att.gid << " AND group_u = 1 )";
break;
case ALL:
if (!all)
{
uid_filter << " uid = " << att.uid
<< " OR ( gid = " << att.gid << " AND group_u = 1 )"
<< " OR other_u = 1"
<< acl_str;
}
break;
default:
uid_filter << "uid = " << filter_flag;
if ( filter_flag != att.uid && !all )
{
uid_filter << " AND ("
<< " ( gid = " << att.gid << " AND group_u = 1)"
<< " OR other_u = 1"
<< acl_str
<< ")";
}
break;
}
uid_str = uid_filter.str();
// ------------------------------------------
// Resource ID filter
// ------------------------------------------
if ( start_id != -1 )
{
id_filter << "oid >= " << start_id;
if ( end_id != -1 )
{
id_filter << " AND oid <= " << end_id;
}
}
id_str = id_filter.str();
// ------------------------------------------
// Compound WHERE clause
// ------------------------------------------
// WHERE ( id_str ) AND ( uid_str ) AND ( and_clause ) OR ( or_clause )
if (!id_str.empty())
{
where_string << "(" << id_str << ")" ;
empty = false;
}
if (!uid_str.empty())
{
if (!empty)
{
where_string << " AND ";
}
where_string << "(" << uid_str << ")";
empty = false;
}
if (!and_clause.empty())
{
if (!empty)
{
where_string << " AND ";
}
where_string << "(" << and_clause << ")";
empty = false;
}
if (!or_clause.empty())
{
if (!empty)
{
where_string << " OR ";
}
where_string << "(" << or_clause << ")";
}
// ------------------------------------------
// Get the pool
// ------------------------------------------
rc = pool->dump(oss,where_string.str());
rc = pool->dump(oss, where_string);
if ( rc != 0 )
{
@ -325,4 +294,3 @@ void RequestManagerPoolInfoFilter::dump(
return;
}

View File

@ -25,10 +25,11 @@
const char * History::table = "history";
const char * History::db_names = "vid, seq, body";
const char * History::db_names = "vid, seq, body, stime, etime";
const char * History::db_bootstrap = "CREATE TABLE IF NOT EXISTS "
"history (vid INTEGER, seq INTEGER, body TEXT, PRIMARY KEY(vid,seq))";
"history (vid INTEGER, seq INTEGER, body TEXT, "
"stime INTEGER, etime INTEGER,PRIMARY KEY(vid,seq))";
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
@ -51,7 +52,8 @@ History::History(
running_etime(0),
epilog_stime(0),
epilog_etime(0),
reason(NONE){};
reason(NONE),
vm_info("<VM/>"){};
/* -------------------------------------------------------------------------- */
@ -61,7 +63,8 @@ History::History(
int _hid,
const string& _hostname,
const string& _vmm,
const string& _vnm):
const string& _vnm,
const string& _vm_info):
oid(_oid),
seq(_seq),
hostname(_hostname),
@ -76,7 +79,8 @@ History::History(
running_etime(0),
epilog_stime(0),
epilog_etime(0),
reason(NONE)
reason(NONE),
vm_info(_vm_info)
{
non_persistent_data();
};
@ -149,7 +153,7 @@ int History::insert_replace(SqlDB *db, bool replace)
return 0;
}
sql_xml = db->escape_str(to_xml(xml_body).c_str());
sql_xml = db->escape_str(to_db_xml(xml_body).c_str());
if ( sql_xml == 0 )
{
@ -168,7 +172,9 @@ int History::insert_replace(SqlDB *db, bool replace)
oss << " INTO " << table << " ("<< db_names <<") VALUES ("
<< oid << ","
<< seq << ","
<< "'" << sql_xml << "')";
<< "'" << sql_xml << "',"
<< stime << ","
<< etime << ")";
rc = db->exec(oss);
@ -259,11 +265,26 @@ ostream& operator<<(ostream& os, const History& history)
/* -------------------------------------------------------------------------- */
string& History::to_xml(string& xml) const
{
return to_xml(xml, false);
}
/* -------------------------------------------------------------------------- */
string& History::to_db_xml(string& xml) const
{
return to_xml(xml, true);
}
/* -------------------------------------------------------------------------- */
string& History::to_xml(string& xml, bool database) const
{
ostringstream oss;
oss <<
"<HISTORY>" <<
"<OID>" << oid << "</OID>" <<
"<SEQ>" << seq << "</SEQ>" <<
"<HOSTNAME>" << hostname << "</HOSTNAME>"<<
"<HID>" << hid << "</HID>" <<
@ -277,7 +298,14 @@ string& History::to_xml(string& xml) const
"<RETIME>" << running_etime << "</RETIME>"<<
"<ESTIME>" << epilog_stime << "</ESTIME>"<<
"<EETIME>" << epilog_etime << "</EETIME>"<<
"<REASON>" << reason << "</REASON>"<<
"<REASON>" << reason << "</REASON>";
if ( database )
{
oss << vm_info;
}
oss <<
"</HISTORY>";
xml = oss.str();

View File

@ -735,6 +735,7 @@ void VirtualMachine::add_history(
{
ostringstream os;
int seq;
string vm_xml;
if (history == 0)
{
@ -747,12 +748,15 @@ void VirtualMachine::add_history(
previous_history = history;
}
to_xml_extended(vm_xml, 0);
history = new History(oid,
seq,
hid,
hostname,
vmm_mad,
vnm_mad);
vnm_mad,
vm_xml);
history_records.push_back(history);
};
@ -763,18 +767,22 @@ void VirtualMachine::add_history(
void VirtualMachine::cp_history()
{
History * htmp;
string vm_xml;
if (history == 0)
{
return;
}
to_xml_extended(vm_xml, 0);
htmp = new History(oid,
history->seq + 1,
history->hid,
history->hostname,
history->vmm_mad_name,
history->vnm_mad_name);
history->vnm_mad_name,
vm_xml);
previous_history = history;
history = htmp;
@ -788,18 +796,22 @@ void VirtualMachine::cp_history()
void VirtualMachine::cp_previous_history()
{
History * htmp;
string vm_xml;
if ( previous_history == 0 || history == 0)
{
return;
}
to_xml_extended(vm_xml, 0);
htmp = new History(oid,
history->seq + 1,
previous_history->hid,
previous_history->hostname,
previous_history->vmm_mad_name,
previous_history->vnm_mad_name);
previous_history->vnm_mad_name,
vm_xml);
previous_history = history;
history = htmp;
@ -1470,26 +1482,11 @@ error_yy:
pthread_mutex_unlock(&lex_mutex);
return -1;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
string& VirtualMachine::to_xml(string& xml) const
{
return to_xml_extended(xml,false);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
string& VirtualMachine::to_xml_extended(string& xml) const
{
return to_xml_extended(xml,true);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
string& VirtualMachine::to_xml_extended(string& xml, bool extended) const
string& VirtualMachine::to_xml_extended(string& xml, int n_history) const
{
string template_xml;
string history_xml;
@ -1517,11 +1514,11 @@ string& VirtualMachine::to_xml_extended(string& xml, bool extended) const
<< "<NET_RX>" << net_rx << "</NET_RX>"
<< obj_template->to_xml(template_xml);
if ( hasHistory() )
if ( hasHistory() && n_history > 0 )
{
oss << "<HISTORY_RECORDS>";
if ( extended )
if ( n_history == 2 )
{
for (unsigned int i=0; i < history_records.size(); i++)
{

View File

@ -266,3 +266,37 @@ int VirtualMachinePool::get_pending(
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualMachinePool::dump_acct(ostringstream& oss,
const string& where,
int time_start,
int time_end)
{
ostringstream cmd;
cmd << "SELECT " << History::table << ".body FROM " << History::table
<< " INNER JOIN " << VirtualMachine::table
<< " WHERE vid=oid";
if ( !where.empty() )
{
cmd << " AND " << where;
}
if ( time_start != -1 || time_end != -1 )
{
if ( time_start != -1 )
{
cmd << " AND (etime > " << time_start << " OR etime = 0)";
}
if ( time_end != -1 )
{
cmd << " AND stime < " << time_end;
}
}
cmd << " GROUP BY vid,seq";
return PoolSQL::dump(oss, "HISTORY_RECORDS", cmd);
};

View File

@ -546,8 +546,10 @@ void VirtualMachineManagerDriver::protocol(
}
vm->update_info(memory,cpu,net_tx,net_rx);
vm->set_vm_info();
vmpool->update(vm);
vmpool->update_history(vm);
if (state != '-' &&
(vm->get_lcm_state() == VirtualMachine::RUNNING ||