mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-08 20:58:17 +03:00
Merge branch 'feature-3264'
Conflicts: src/sunstone/public/js/plugins/templates-tab.js src/vmm_mad/remotes/vcenter/vcenter_driver.rb
This commit is contained in:
commit
036600bc74
@ -390,7 +390,7 @@ public:
|
||||
*/
|
||||
static string local_db_version()
|
||||
{
|
||||
return "4.9.80";
|
||||
return "4.11.80";
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -84,6 +84,15 @@ namespace one_util
|
||||
const std::string& st,
|
||||
char delim,
|
||||
bool clean_empty=true);
|
||||
|
||||
/**
|
||||
* Creates a string from the given float, using fixed notation. If the
|
||||
* number has any decimals, they will be truncated to 2.
|
||||
*
|
||||
* @param num
|
||||
* @return
|
||||
*/
|
||||
std::string float_to_str(const float &num);
|
||||
};
|
||||
|
||||
#endif /* _NEBULA_UTIL_H_ */
|
||||
|
@ -82,6 +82,17 @@ public:
|
||||
*/
|
||||
int xpath(int& value, const char * xpath_expr, const int& def);
|
||||
|
||||
/**
|
||||
* Gets and sets a xpath attribute, if the attribute is not found a default
|
||||
* is used
|
||||
* @param value to set
|
||||
* @param xpath_expr of the xml element
|
||||
* @param def default value if the element is not found
|
||||
*
|
||||
* @return -1 if default was set
|
||||
*/
|
||||
int xpath(float& value, const char * xpath_expr, const float& def);
|
||||
|
||||
/**
|
||||
* Gets and sets a xpath attribute, if the attribute is not found a default
|
||||
* is used
|
||||
|
@ -207,15 +207,6 @@ protected:
|
||||
*/
|
||||
void cleanup_quota(const string& qid);
|
||||
|
||||
/**
|
||||
* Creates a string from the given float, using fixed notation. If the
|
||||
* number has any decimals, they will be truncated to 2.
|
||||
*
|
||||
* @param num
|
||||
* @return
|
||||
*/
|
||||
string float_to_str(const float &num);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Creates an empty quota based on the given attribute. The attribute va
|
||||
|
@ -151,6 +151,31 @@ public:
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
class VirtualMachinePoolShowback : public RequestManagerPoolInfoFilter
|
||||
{
|
||||
public:
|
||||
|
||||
VirtualMachinePoolShowback():
|
||||
RequestManagerPoolInfoFilter("VirtualMachinePoolShowback",
|
||||
"Returns the virtual machine showback records",
|
||||
"A:siiiii")
|
||||
{
|
||||
Nebula& nd = Nebula::instance();
|
||||
pool = nd.get_vmpool();
|
||||
auth_object = PoolObjectSQL::VM;
|
||||
};
|
||||
|
||||
~VirtualMachinePoolShowback(){};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
void request_execute(
|
||||
xmlrpc_c::paramList const& paramList, RequestAttributes& att);
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
class VirtualMachinePoolMonitoring : public RequestManagerPoolInfoFilter
|
||||
{
|
||||
public:
|
||||
|
@ -363,4 +363,29 @@ public:
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
class VirtualMachinePoolCalculateShowback : public RequestManagerVirtualMachine
|
||||
{
|
||||
public:
|
||||
|
||||
VirtualMachinePoolCalculateShowback():
|
||||
RequestManagerVirtualMachine("VirtualMachinePoolCalculateShowback",
|
||||
"Processes all the history records, and stores the monthly cost for each VM",
|
||||
"A:sii")
|
||||
{
|
||||
Nebula& nd = Nebula::instance();
|
||||
pool = nd.get_vmpool();
|
||||
auth_object = PoolObjectSQL::VM;
|
||||
};
|
||||
|
||||
~VirtualMachinePoolCalculateShowback(){};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
void request_execute(
|
||||
xmlrpc_c::paramList const& paramList, RequestAttributes& att);
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#endif
|
||||
|
@ -1517,10 +1517,12 @@ private:
|
||||
ostringstream oss_vm(VirtualMachine::db_bootstrap);
|
||||
ostringstream oss_monit(VirtualMachine::monit_db_bootstrap);
|
||||
ostringstream oss_hist(History::db_bootstrap);
|
||||
ostringstream oss_showback(VirtualMachine::showback_db_bootstrap);
|
||||
|
||||
rc = db->exec(oss_vm);
|
||||
rc += db->exec(oss_monit);
|
||||
rc += db->exec(oss_hist);
|
||||
rc += db->exec(oss_showback);
|
||||
|
||||
return rc;
|
||||
};
|
||||
@ -1714,6 +1716,12 @@ protected:
|
||||
|
||||
static const char * monit_db_bootstrap;
|
||||
|
||||
static const char * showback_table;
|
||||
|
||||
static const char * showback_db_names;
|
||||
|
||||
static const char * showback_db_bootstrap;
|
||||
|
||||
/**
|
||||
* Reads the Virtual Machine (identified with its OID) from the database.
|
||||
* @param db pointer to the db
|
||||
|
@ -230,6 +230,29 @@ public:
|
||||
int time_start,
|
||||
int time_end);
|
||||
|
||||
/**
|
||||
* Dumps the VM showback 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
|
||||
* @param start_month First month (+year) to include. January is 1.
|
||||
* Use -1 to unset
|
||||
* @param start_year First year (+month) to include. e.g. 2014.
|
||||
* Use -1 to unset
|
||||
* @param end_month Last month (+year) to include. January is 1.
|
||||
* Use -1 to unset
|
||||
* @param end_year Last year (+month) to include. e.g. 2014.
|
||||
* Use -1 to unset
|
||||
*
|
||||
* @return 0 on success
|
||||
*/
|
||||
int dump_showback(ostringstream& oss,
|
||||
const string& where,
|
||||
int start_month,
|
||||
int start_year,
|
||||
int end_month,
|
||||
int end_year);
|
||||
|
||||
/**
|
||||
* Dumps the VM monitoring information entries in XML format. A filter
|
||||
* can be also added to the query.
|
||||
@ -260,6 +283,28 @@ public:
|
||||
return dump_monitoring(oss, filter.str());
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes all the history records, and stores the monthly cost for each
|
||||
* VM
|
||||
* @param start_month First month (+year) to process. January is 1.
|
||||
* Use -1 to unset
|
||||
* @param start_year First year (+month) to process. e.g. 2014.
|
||||
* Use -1 to unset
|
||||
* @param end_month Last month (+year) to process. January is 1.
|
||||
* Use -1 to unset
|
||||
* @param end_year Last year (+month) to process. e.g. 2014.
|
||||
* Use -1 to unset
|
||||
* @param error_str Returns the error reason, if any
|
||||
*
|
||||
* @return 0 on success
|
||||
*/
|
||||
int calculate_showback(
|
||||
int start_month,
|
||||
int start_year,
|
||||
int end_month,
|
||||
int end_year,
|
||||
string &error_str);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Factory method to produce VM objects
|
||||
@ -279,6 +324,11 @@ private:
|
||||
* True or false whether to submit new VM on HOLD or not
|
||||
*/
|
||||
static bool _submit_on_hold;
|
||||
|
||||
/**
|
||||
* Callback used in calculate_showback
|
||||
*/
|
||||
int min_stime_cb(void * _min_stime, int num, char **values, char **names);
|
||||
};
|
||||
|
||||
#endif /*VIRTUAL_MACHINE_POOL_H_*/
|
||||
|
11
install.sh
11
install.sh
@ -591,6 +591,7 @@ BIN_FILES="src/nebula/oned \
|
||||
src/scheduler/src/sched/mm_sched \
|
||||
src/cli/onevm \
|
||||
src/cli/oneacct \
|
||||
src/cli/oneshowback \
|
||||
src/cli/onehost \
|
||||
src/cli/onevnet \
|
||||
src/cli/oneuser \
|
||||
@ -1180,7 +1181,8 @@ ONEDB_SHARED_MIGRATOR_FILES="src/onedb/shared/2.0_to_2.9.80.rb \
|
||||
src/onedb/shared/4.5.80_to_4.6.0.rb"
|
||||
|
||||
ONEDB_LOCAL_MIGRATOR_FILES="src/onedb/local/4.5.80_to_4.7.80.rb \
|
||||
src/onedb/local/4.7.80_to_4.9.80.rb"
|
||||
src/onedb/local/4.7.80_to_4.9.80.rb \
|
||||
src/onedb/local/4.9.80_to_4.11.80.rb"
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Configuration files for OpenNebula, to be installed under $ETC_LOCATION
|
||||
@ -1458,7 +1460,8 @@ CLI_BIN_FILES="src/cli/onevm \
|
||||
src/cli/onezone \
|
||||
src/cli/oneflow \
|
||||
src/cli/oneflow-template \
|
||||
src/cli/oneacct"
|
||||
src/cli/oneacct \
|
||||
src/cli/oneshowback"
|
||||
|
||||
CLI_CONF_FILES="src/cli/etc/onegroup.yaml \
|
||||
src/cli/etc/onehost.yaml \
|
||||
@ -1471,7 +1474,8 @@ CLI_CONF_FILES="src/cli/etc/onegroup.yaml \
|
||||
src/cli/etc/onedatastore.yaml \
|
||||
src/cli/etc/onecluster.yaml \
|
||||
src/cli/etc/onezone.yaml \
|
||||
src/cli/etc/oneacct.yaml"
|
||||
src/cli/etc/oneacct.yaml \
|
||||
src/cli/etc/oneshowback.yaml"
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Sunstone files
|
||||
@ -1802,6 +1806,7 @@ ONEFLOW_LIB_MODELS_FILES="src/flow/lib/models/role.rb \
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
MAN_FILES="share/man/oneacct.1.gz \
|
||||
share/man/oneshowback.1.gz \
|
||||
share/man/oneacl.1.gz \
|
||||
share/man/onehost.1.gz \
|
||||
share/man/oneimage.1.gz \
|
||||
|
@ -763,6 +763,8 @@ VM_RESTRICTED_ATTR = "DISK/WRITE_BYTES_SEC"
|
||||
VM_RESTRICTED_ATTR = "DISK/TOTAL_IOPS_SEC"
|
||||
VM_RESTRICTED_ATTR = "DISK/READ_IOPS_SEC"
|
||||
VM_RESTRICTED_ATTR = "DISK/WRITE_IOPS_SEC"
|
||||
VM_RESTRICTED_ATTR = "CPU_COST"
|
||||
VM_RESTRICTED_ATTR = "MEMORY_COST"
|
||||
|
||||
#VM_RESTRICTED_ATTR = "RANK"
|
||||
#VM_RESTRICTED_ATTR = "SCHED_RANK"
|
||||
|
@ -48,6 +48,7 @@ env.Man('econe-terminate-instances')
|
||||
env.Man('econe-upload')
|
||||
|
||||
env.Man('oneacct')
|
||||
env.Man('oneshowback')
|
||||
env.Man('oneacl')
|
||||
env.Man('onecluster')
|
||||
env.Man('onedatastore')
|
||||
|
50
share/man/oneshowback.1
Normal file
50
share/man/oneshowback.1
Normal file
@ -0,0 +1,50 @@
|
||||
.\" generated with Ronn/v0.7.3
|
||||
.\" http://github.com/rtomayko/ronn/tree/0.7.3
|
||||
.
|
||||
.TH "ONESHOWBACK" "1" "November 2014" "" "oneshowback(1) -- OpenNebula Showback Tool"
|
||||
.
|
||||
.SH "NAME"
|
||||
\fBoneshowback\fR
|
||||
.
|
||||
.SH "SYNOPSIS"
|
||||
\fBoneshowback\fR \fIcommand\fR [\fIoptions\fR]
|
||||
.
|
||||
.SH "OPTIONS"
|
||||
.
|
||||
.nf
|
||||
|
||||
\-s, \-\-start TIME First month of the data
|
||||
\-e, \-\-end TIME Last month of the data
|
||||
\-u, \-\-userfilter user User name or id to filter the results
|
||||
\-g, \-\-group group Group name or id to filter the results
|
||||
\-x, \-\-xml Show the resource in xml format
|
||||
\-j, \-\-json Show the resource in json format
|
||||
\-v, \-\-verbose Verbose mode
|
||||
\-h, \-\-help Show this message
|
||||
\-V, \-\-version Show version and copyright information
|
||||
\-\-describe Describe list columns
|
||||
\-l, \-\-list x,y,z Selects columns to display with list command
|
||||
\-\-csv Write table in csv format
|
||||
\-\-user name User name used to connect to OpenNebula
|
||||
\-\-password password Password to authenticate with OpenNebula
|
||||
\-\-endpoint endpoint URL of OpenNebula xmlrpc frontend
|
||||
.
|
||||
.fi
|
||||
.
|
||||
.SH "COMMANDS"
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
list Returns the showback records valid options: start_time, end_time, userfilter, group, xml, json, verbose, help, version, describe, list, csv, user, password, endpoint
|
||||
.
|
||||
.IP "\(bu" 4
|
||||
calculate Calculates the showback records valid options: start_time, end_time
|
||||
.
|
||||
.IP "" 0
|
||||
.
|
||||
.SH "ARGUMENT FORMATS"
|
||||
.
|
||||
.SH "LICENSE"
|
||||
OpenNebula 4\.10\.0 Copyright 2002\-2014, OpenNebula Project (OpenNebula\.org), C12G Labs
|
||||
.
|
||||
.P
|
||||
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
|
50
src/cli/etc/oneshowback.yaml
Normal file
50
src/cli/etc/oneshowback.yaml
Normal file
@ -0,0 +1,50 @@
|
||||
---
|
||||
:UID:
|
||||
:desc: User ID
|
||||
:size: 4
|
||||
|
||||
:USER_NAME:
|
||||
:desc: User name
|
||||
:size: 12
|
||||
|
||||
:GID:
|
||||
:desc: Group ID
|
||||
:size: 4
|
||||
|
||||
:GROUP_NAME:
|
||||
:desc: Group name
|
||||
:size: 12
|
||||
|
||||
:VM_ID:
|
||||
:desc: Virtual Machine ID
|
||||
:size: 6
|
||||
|
||||
:VM_NAME:
|
||||
:desc: Virtual Machine name
|
||||
:size: 12
|
||||
|
||||
:MONTH:
|
||||
:desc: Month
|
||||
:size: 5
|
||||
|
||||
:YEAR:
|
||||
:desc: Year
|
||||
:size: 5
|
||||
|
||||
:HOURS:
|
||||
:desc: Hours
|
||||
:size: 6
|
||||
|
||||
:COST:
|
||||
:desc: Cost
|
||||
:size: 15
|
||||
|
||||
:default:
|
||||
- :USER_NAME
|
||||
- :GROUP_NAME
|
||||
- :VM_ID
|
||||
- :VM_NAME
|
||||
- :MONTH
|
||||
- :YEAR
|
||||
- :HOURS
|
||||
- :COST
|
@ -18,19 +18,35 @@ require 'one_helper'
|
||||
require 'optparse/time'
|
||||
|
||||
class AcctHelper < OpenNebulaHelper::OneHelper
|
||||
START_TIME = {
|
||||
START_TIME_ACCT = {
|
||||
:name => "start_time",
|
||||
:short => "-s TIME",
|
||||
:large => "--start TIME" ,
|
||||
:description => "Start date and time to take into account",
|
||||
:description => "First day of the data to retrieve",
|
||||
:format => Time
|
||||
}
|
||||
|
||||
END_TIME = {
|
||||
END_TIME_ACCT = {
|
||||
:name => "end_time",
|
||||
:short => "-e TIME",
|
||||
:large => "--end TIME" ,
|
||||
:description => "End date and time",
|
||||
:description => "Last day of the data to retrieve",
|
||||
:format => Time
|
||||
}
|
||||
|
||||
START_TIME_SHOWBACK = {
|
||||
:name => "start_time",
|
||||
:short => "-s TIME",
|
||||
:large => "--start TIME" ,
|
||||
:description => "First month of the data",
|
||||
:format => Time
|
||||
}
|
||||
|
||||
END_TIME_SHOWBACK = {
|
||||
:name => "end_time",
|
||||
:short => "-e TIME",
|
||||
:large => "--end TIME" ,
|
||||
:description => "Last month of the data",
|
||||
:format => Time
|
||||
}
|
||||
|
||||
@ -95,8 +111,8 @@ class AcctHelper < OpenNebulaHelper::OneHelper
|
||||
:description => "Split the output in a table for each VM"
|
||||
}
|
||||
|
||||
ACCT_OPTIONS = [START_TIME, END_TIME, USERFILTER, GROUP, HOST, XPATH, XML, JSON, SPLIT]
|
||||
|
||||
ACCT_OPTIONS = [START_TIME_ACCT, END_TIME_ACCT, USERFILTER, GROUP, HOST, XPATH, XML, JSON, SPLIT]
|
||||
SHOWBACK_OPTIONS = [START_TIME_SHOWBACK, END_TIME_SHOWBACK, USERFILTER, GROUP, XML, JSON]
|
||||
|
||||
ACCT_TABLE = CLIHelper::ShowTable.new("oneacct.yaml", nil) do
|
||||
column :UID, "User ID", :size=>4 do |d|
|
||||
@ -152,6 +168,50 @@ class AcctHelper < OpenNebulaHelper::OneHelper
|
||||
default :VID, :HOSTNAME, :ACTION, :REASON, :START_TIME, :END_TIME, :MEMORY, :CPU, :NET_RX, :NET_TX
|
||||
end
|
||||
|
||||
SHOWBACK_TABLE = CLIHelper::ShowTable.new("oneshowback.yaml", nil) do
|
||||
column :UID, "User ID", :size=>4 do |d|
|
||||
d["UID"]
|
||||
end
|
||||
|
||||
column :USER_NAME, "User name", :left, :size=>12 do |d|
|
||||
d["UNAME"]
|
||||
end
|
||||
|
||||
column :GID, "Group ID", :size=>4 do |d|
|
||||
d["GID"]
|
||||
end
|
||||
|
||||
column :GROUP_NAME, "Group name", :left, :size=>12 do |d|
|
||||
d["GNAME"]
|
||||
end
|
||||
|
||||
column :VM_ID, "Virtual Machine ID", :size=>6 do |d|
|
||||
d["VMID"]
|
||||
end
|
||||
|
||||
column :VM_NAME, "Virtual Machine name", :left, :size=>12 do |d|
|
||||
d["VMNAME"]
|
||||
end
|
||||
|
||||
column :MONTH, "Month", :size=>5 do |d|
|
||||
d["MONTH"]
|
||||
end
|
||||
|
||||
column :YEAR, "Year", :size=>5 do |d|
|
||||
d["YEAR"]
|
||||
end
|
||||
|
||||
column :HOURS, "Hours", :size=>6 do |d|
|
||||
d["HOURS"]
|
||||
end
|
||||
|
||||
column :COST, "Cost", :size=>15 do |d|
|
||||
d["COST"]
|
||||
end
|
||||
|
||||
default :USER_NAME, :GROUP_NAME, :VM_ID, :VM_NAME, :MONTH, :YEAR, :HOURS, :COST
|
||||
end
|
||||
|
||||
def self.print_start_end_time_header(start_time, end_time)
|
||||
print "Showing active history records from "
|
||||
|
||||
@ -184,4 +244,12 @@ class AcctHelper < OpenNebulaHelper::OneHelper
|
||||
CLIHelper.scr_restore
|
||||
puts
|
||||
end
|
||||
|
||||
def self.print_month_header(year, month)
|
||||
CLIHelper.scr_bold
|
||||
CLIHelper.scr_underline
|
||||
puts "# Showback for #{month}/#{year}".ljust(80)
|
||||
CLIHelper.scr_restore
|
||||
puts
|
||||
end
|
||||
end
|
||||
|
@ -70,7 +70,7 @@ cmd = CommandParser::CmdParser.new(ARGV) do
|
||||
if options[:json] || options[:xml]
|
||||
xml_str = pool.accounting_xml(filter_flag, common_opts)
|
||||
if OpenNebula.is_error?(xml_str)
|
||||
puts acct_hash.message
|
||||
puts xml_str.message
|
||||
exit -1
|
||||
end
|
||||
|
||||
|
178
src/cli/oneshowback
Executable file
178
src/cli/oneshowback
Executable file
@ -0,0 +1,178 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
# -------------------------------------------------------------------------- #
|
||||
# Copyright 2002-2014, OpenNebula Project (OpenNebula.org), C12G Labs #
|
||||
# #
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
|
||||
# not use this file except in compliance with the License. You may obtain #
|
||||
# a copy of the License at #
|
||||
# #
|
||||
# http://www.apache.org/licenses/LICENSE-2.0 #
|
||||
# #
|
||||
# Unless required by applicable law or agreed to in writing, software #
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, #
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
|
||||
# See the License for the specific language governing permissions and #
|
||||
# limitations under the License. #
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
ONE_LOCATION=ENV["ONE_LOCATION"]
|
||||
|
||||
if !ONE_LOCATION
|
||||
RUBY_LIB_LOCATION="/usr/lib/one/ruby"
|
||||
else
|
||||
RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby"
|
||||
end
|
||||
|
||||
$: << RUBY_LIB_LOCATION
|
||||
$: << RUBY_LIB_LOCATION+"/cli"
|
||||
|
||||
require 'command_parser'
|
||||
require 'one_helper/oneacct_helper'
|
||||
|
||||
require 'json'
|
||||
|
||||
cmd = CommandParser::CmdParser.new(ARGV) do
|
||||
|
||||
@formats = Hash.new
|
||||
|
||||
usage "`oneshowback` <command> [<options>]"
|
||||
description ""
|
||||
version OpenNebulaHelper::ONE_VERSION
|
||||
|
||||
helper=OpenNebulaHelper::OneHelper.new
|
||||
|
||||
before_proc do
|
||||
helper.set_client(options)
|
||||
end
|
||||
|
||||
command :list, "Returns the showback records", :options =>
|
||||
AcctHelper::SHOWBACK_OPTIONS + CommandParser::OPTIONS +
|
||||
[OpenNebulaHelper::DESCRIBE, CLIHelper::LIST, CLIHelper::CSV_OPT] +
|
||||
OpenNebulaHelper::CLIENT_OPTIONS do
|
||||
|
||||
if options[:describe]
|
||||
AcctHelper::SHOWBACK_TABLE.describe_columns
|
||||
exit(0)
|
||||
end
|
||||
|
||||
filter_flag = (options[:userfilter] || VirtualMachinePool::INFO_ALL)
|
||||
|
||||
start_month = -1
|
||||
start_year = -1
|
||||
|
||||
if (options[:start_time])
|
||||
start_month = options[:start_time].month
|
||||
start_year = options[:start_time].year
|
||||
end
|
||||
|
||||
end_month = -1
|
||||
end_year = -1
|
||||
|
||||
if (options[:end_time])
|
||||
end_month = options[:end_time].month
|
||||
end_year = options[:end_time].year
|
||||
end
|
||||
|
||||
common_opts = {
|
||||
:start_month => start_month,
|
||||
:start_year => start_year,
|
||||
:end_month => end_month,
|
||||
:end_year => end_year,
|
||||
:group => options[:group],
|
||||
:xpath => options[:xpath]
|
||||
}
|
||||
|
||||
pool = OpenNebula::VirtualMachinePool.new(helper.client)
|
||||
|
||||
if options[:json] || options[:xml]
|
||||
xml_str = pool.showback_xml(filter_flag, common_opts)
|
||||
if OpenNebula.is_error?(xml_str)
|
||||
puts xml_str.message
|
||||
exit -1
|
||||
end
|
||||
|
||||
if options[:json]
|
||||
xmldoc = XMLElement.new
|
||||
xmldoc.initialize_xml(xml_str, 'SHOWBACK_RECORDS')
|
||||
|
||||
puts JSON.pretty_generate(xmldoc.to_hash)
|
||||
elsif options[:xml]
|
||||
puts xml_str
|
||||
end
|
||||
|
||||
exit_code 0
|
||||
else
|
||||
|
||||
order_by = Hash.new
|
||||
if !options[:csv]
|
||||
order_by[:order_by_1] = 'YEAR'
|
||||
order_by[:order_by_2] = 'MONTH'
|
||||
end
|
||||
|
||||
data_hash = pool.showback(filter_flag,
|
||||
common_opts.merge(order_by))
|
||||
if OpenNebula.is_error?(data_hash)
|
||||
puts data_hash.message
|
||||
exit -1
|
||||
end
|
||||
|
||||
if options[:csv]
|
||||
a = Array.new
|
||||
|
||||
if data_hash['SHOWBACK_RECORDS']
|
||||
a = data_hash['SHOWBACK_RECORDS']['SHOWBACK']
|
||||
end
|
||||
|
||||
AcctHelper::SHOWBACK_TABLE.show(a, options)
|
||||
exit(0)
|
||||
end
|
||||
|
||||
data_hash.each { |year, value|
|
||||
value.each { |month, showback_array|
|
||||
AcctHelper.print_month_header(year, month)
|
||||
|
||||
array = showback_array['SHOWBACK_RECORDS']['SHOWBACK']
|
||||
AcctHelper::SHOWBACK_TABLE.show(array, options)
|
||||
puts
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
exit_code 0
|
||||
end
|
||||
end
|
||||
|
||||
command :"calculate", "Calculates the showback records", :options =>
|
||||
[AcctHelper::START_TIME_SHOWBACK, AcctHelper::END_TIME_SHOWBACK] do
|
||||
|
||||
|
||||
start_month = -1
|
||||
start_year = -1
|
||||
|
||||
if (options[:start_time])
|
||||
start_month = options[:start_time].month
|
||||
start_year = options[:start_time].year
|
||||
end
|
||||
|
||||
end_month = -1
|
||||
end_year = -1
|
||||
|
||||
if (options[:end_time])
|
||||
end_month = options[:end_time].month
|
||||
end_year = options[:end_time].year
|
||||
end
|
||||
|
||||
rc = OpenNebula::VirtualMachinePool.new(helper.client).
|
||||
calculate_showback(start_month, start_year, end_month, end_year)
|
||||
|
||||
if OpenNebula.is_error?(rc)
|
||||
warn rc.message
|
||||
exit -1
|
||||
else
|
||||
puts rc
|
||||
exit_code 0
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -27,6 +27,7 @@
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <algorithm>
|
||||
#include <math.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -238,3 +239,24 @@ vector<string> one_util::split(const string& st, char delim, bool clean_empty)
|
||||
|
||||
return parts;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
string one_util::float_to_str(const float &num)
|
||||
{
|
||||
ostringstream oss;
|
||||
|
||||
if ( num == ceil(num) )
|
||||
{
|
||||
oss.precision(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
oss.precision(2);
|
||||
}
|
||||
|
||||
oss << fixed << num;
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
@ -25,9 +25,11 @@ module OpenNebula
|
||||
|
||||
|
||||
VM_POOL_METHODS = {
|
||||
:info => "vmpool.info",
|
||||
:monitoring => "vmpool.monitoring",
|
||||
:accounting => "vmpool.accounting"
|
||||
:info => "vmpool.info",
|
||||
:monitoring => "vmpool.monitoring",
|
||||
:accounting => "vmpool.accounting",
|
||||
:showback => "vmpool.showback",
|
||||
:calculate_showback => "vmpool.calculateshowback"
|
||||
}
|
||||
|
||||
# Constants for info queries (include/RequestManagerPoolInfoFilter.h)
|
||||
@ -162,6 +164,27 @@ module OpenNebula
|
||||
return @client.call(VM_POOL_METHODS[:monitoring], filter_flag)
|
||||
end
|
||||
|
||||
# Processes all the history records, and stores the monthly cost for
|
||||
# each VM
|
||||
#
|
||||
# @param [Integer] start_month First month (+year) to process. January is 1.
|
||||
# Use -1 to unset
|
||||
# @param [Integer] start_year First year (+month) to process. e.g. 2014.
|
||||
# Use -1 to unset
|
||||
# @param [Integer] end_month Last month (+year) to process. January is 1.
|
||||
# Use -1 to unset
|
||||
# @param [Integer] end_year Last year (+month) to process. e.g. 2014.
|
||||
# Use -1 to unset
|
||||
def calculate_showback(start_month, start_year, end_month, end_year)
|
||||
start_month ||= -1
|
||||
start_year ||= -1
|
||||
end_month ||= -1
|
||||
end_year ||= -1
|
||||
|
||||
return @client.call(VM_POOL_METHODS[:calculate_showback],
|
||||
start_month, start_year, end_month, end_year)
|
||||
end
|
||||
|
||||
# Retrieves the accounting data for all the VMs in the pool
|
||||
#
|
||||
# @param [Integer] filter_flag Optional filter flag to retrieve all or
|
||||
@ -283,6 +306,92 @@ module OpenNebula
|
||||
xml_str
|
||||
end
|
||||
|
||||
# Retrieves the showback data for all the VMs in the pool
|
||||
#
|
||||
# @param [Integer] filter_flag Optional filter flag to retrieve all or
|
||||
# part of the Pool. Possible values: INFO_ALL, INFO_GROUP, INFO_MINE
|
||||
# or user_id
|
||||
# @param [Hash] options
|
||||
# @option params [Integer] :start_year First month (+year) to take
|
||||
# into account, if no start time is required use -1
|
||||
# @option params [Integer] :start_month First year (+month) to take
|
||||
# into account, if no start time is required use -1
|
||||
# @option params [Integer] :end_year Last month (+year) to take
|
||||
# into account, if no end time is required use -1
|
||||
# @option params [Integer] :end_month Last year (+month) to take
|
||||
# into account, if no end time is required use -1
|
||||
# @option params [Integer] :group Group id to filter the results
|
||||
# @option params [String] :xpath Xpath expression to filter the results.
|
||||
# For example: SHOWBACK[COST>0]
|
||||
# @option params [String] :order_by_1 Xpath expression to group the
|
||||
# @option params [String] :order_by_2 Xpath expression to group the
|
||||
# returned hash. This will be the second level of the hash
|
||||
#
|
||||
# @return [Hash, OpenNebula::Error]
|
||||
# The first level hash uses the :order_by_1 values as keys, and
|
||||
# as value a Hash with the :order_by_2 values and the SHOWBACK_RECORDS
|
||||
def showback(filter_flag=INFO_ALL, options={})
|
||||
data_hash = Hash.new
|
||||
|
||||
rc = build_showback(filter_flag, options) do |record|
|
||||
hash = data_hash
|
||||
|
||||
if options[:order_by_1]
|
||||
id_1 = record[options[:order_by_1]]
|
||||
data_hash[id_1] ||= Hash.new
|
||||
|
||||
if options[:order_by_2]
|
||||
id_2 = record[options[:order_by_2]]
|
||||
data_hash[id_1][id_2] ||= Hash.new
|
||||
|
||||
hash = data_hash[id_1][id_2]
|
||||
else
|
||||
hash = data_hash[id_1]
|
||||
end
|
||||
end
|
||||
|
||||
hash["SHOWBACK_RECORDS"] ||= Hash.new
|
||||
hash["SHOWBACK_RECORDS"]["SHOWBACK"] ||= Array.new
|
||||
hash["SHOWBACK_RECORDS"]["SHOWBACK"] << record.to_hash['SHOWBACK']
|
||||
end
|
||||
|
||||
return rc if OpenNebula.is_error?(rc)
|
||||
|
||||
data_hash
|
||||
end
|
||||
|
||||
# Retrieves the showback data for all the VMs in the pool, in xml
|
||||
#
|
||||
# @param [Integer] filter_flag Optional filter flag to retrieve all or
|
||||
# part of the Pool. Possible values: INFO_ALL, INFO_GROUP, INFO_MINE
|
||||
# or user_id
|
||||
# @param [Hash] options
|
||||
# @option params [Integer] :start_year First month (+year) to take
|
||||
# into account, if no start time is required use -1
|
||||
# @option params [Integer] :start_month First year (+month) to take
|
||||
# into account, if no start time is required use -1
|
||||
# @option params [Integer] :end_year Last month (+year) to take
|
||||
# into account, if no end time is required use -1
|
||||
# @option params [Integer] :end_month Last year (+month) to take
|
||||
# into account, if no end time is required use -1
|
||||
# @option params [Integer] :group Group id to filter the results
|
||||
# @option params [String] :xpath Xpath expression to filter the results.
|
||||
# For example: SHOWBACK[COST>10]
|
||||
#
|
||||
# @return [String] the xml representing the showback data
|
||||
def showback_xml(filter_flag=INFO_ALL, options={})
|
||||
xml_str = "<SHOWBACK_RECORDS>\n"
|
||||
|
||||
rc = build_showback(filter_flag, options) do |showback|
|
||||
xml_str << showback.to_xml
|
||||
end
|
||||
|
||||
return rc if OpenNebula.is_error?(rc)
|
||||
|
||||
xml_str << "\n</SHOWBACK_RECORDS>"
|
||||
xml_str
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def build_accounting(filter_flag, options, &block)
|
||||
@ -316,6 +425,38 @@ module OpenNebula
|
||||
acct_hash
|
||||
end
|
||||
|
||||
def build_showback(filter_flag, options, &block)
|
||||
xml_str = @client.call(VM_POOL_METHODS[:showback],
|
||||
filter_flag,
|
||||
options[:start_month],
|
||||
options[:start_year],
|
||||
options[:end_month],
|
||||
options[:end_year])
|
||||
|
||||
return xml_str if OpenNebula.is_error?(xml_str)
|
||||
|
||||
xmldoc = XMLElement.new
|
||||
xmldoc.initialize_xml(xml_str, 'SHOWBACK_RECORDS')
|
||||
|
||||
xpath_array = Array.new
|
||||
xpath_array << "SHOWBACK[GID=#{options[:group]}]" if options[:group]
|
||||
xpath_array << options[:xpath] if options[:xpath]
|
||||
|
||||
if xpath_array.empty?
|
||||
xpath_str = "SHOWBACK"
|
||||
else
|
||||
xpath_str = xpath_array.join(' | ')
|
||||
end
|
||||
|
||||
data_hash = Hash.new
|
||||
|
||||
xmldoc.each(xpath_str) do |showback|
|
||||
block.call(showback)
|
||||
end
|
||||
|
||||
data_hash
|
||||
end
|
||||
|
||||
def info_filter(xml_method, who, start_id, end_id, state)
|
||||
return xmlrpc_info(xml_method, who, start_id, end_id, state)
|
||||
end
|
||||
|
42
src/onedb/local/4.9.80_to_4.11.80.rb
Normal file
42
src/onedb/local/4.9.80_to_4.11.80.rb
Normal file
@ -0,0 +1,42 @@
|
||||
# -------------------------------------------------------------------------- #
|
||||
# Copyright 2002-2014, OpenNebula Project (OpenNebula.org), C12G Labs #
|
||||
# #
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
|
||||
# not use this file except in compliance with the License. You may obtain #
|
||||
# a copy of the License at #
|
||||
# #
|
||||
# http://www.apache.org/licenses/LICENSE-2.0 #
|
||||
# #
|
||||
# Unless required by applicable law or agreed to in writing, software #
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, #
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
|
||||
# See the License for the specific language governing permissions and #
|
||||
# limitations under the License. #
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
require 'nokogiri'
|
||||
|
||||
module Migrator
|
||||
def db_version
|
||||
"4.11.80"
|
||||
end
|
||||
|
||||
def one_version
|
||||
"OpenNebula 4.11.80"
|
||||
end
|
||||
|
||||
def up
|
||||
|
||||
init_log_time()
|
||||
|
||||
########################################################################
|
||||
# Showback
|
||||
########################################################################
|
||||
|
||||
@db.run "CREATE TABLE vm_showback (vmid INTEGER, year INTEGER, month INTEGER, body MEDIUMTEXT, PRIMARY KEY(vmid, year, month));"
|
||||
|
||||
log_time()
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
@ -302,6 +302,9 @@ void RequestManager::register_xml_methods()
|
||||
xmlrpc_c::methodPtr vm_pool_acct(new VirtualMachinePoolAccounting());
|
||||
xmlrpc_c::methodPtr vm_pool_monitoring(new VirtualMachinePoolMonitoring());
|
||||
|
||||
xmlrpc_c::methodPtr vm_pool_showback(new VirtualMachinePoolShowback());
|
||||
xmlrpc_c::methodPtr vm_pool_calculate_showback(new VirtualMachinePoolCalculateShowback());
|
||||
|
||||
// VirtualNetwork Methods
|
||||
xmlrpc_c::methodPtr vn_add_ar(new VirtualNetworkAddAddressRange());
|
||||
xmlrpc_c::methodPtr vn_rm_ar(new VirtualNetworkRmAddressRange());
|
||||
@ -438,6 +441,8 @@ void RequestManager::register_xml_methods()
|
||||
RequestManagerRegistry.addMethod("one.vmpool.info", vm_pool_info);
|
||||
RequestManagerRegistry.addMethod("one.vmpool.accounting", vm_pool_acct);
|
||||
RequestManagerRegistry.addMethod("one.vmpool.monitoring", vm_pool_monitoring);
|
||||
RequestManagerRegistry.addMethod("one.vmpool.showback", vm_pool_showback);
|
||||
RequestManagerRegistry.addMethod("one.vmpool.calculateshowback", vm_pool_calculate_showback);
|
||||
|
||||
/* VM Template related methods*/
|
||||
RequestManagerRegistry.addMethod("one.template.update", template_update);
|
||||
|
@ -165,6 +165,50 @@ void VirtualMachinePoolAccounting::request_execute(
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void VirtualMachinePoolShowback::request_execute(
|
||||
xmlrpc_c::paramList const& paramList,
|
||||
RequestAttributes& att)
|
||||
{
|
||||
int filter_flag = xmlrpc_c::value_int(paramList.getInt(1));
|
||||
int start_month = xmlrpc_c::value_int(paramList.getInt(2));
|
||||
int start_year = xmlrpc_c::value_int(paramList.getInt(3));
|
||||
int end_month = xmlrpc_c::value_int(paramList.getInt(4));
|
||||
int end_year = xmlrpc_c::value_int(paramList.getInt(5));
|
||||
|
||||
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, "", "", false, false, false, where);
|
||||
|
||||
rc = (static_cast<VirtualMachinePool *>(pool))->dump_showback(oss,
|
||||
where,
|
||||
start_month,
|
||||
start_year,
|
||||
end_month,
|
||||
end_year);
|
||||
if ( rc != 0 )
|
||||
{
|
||||
failure_response(INTERNAL,request_error("Internal Error",""), att);
|
||||
return;
|
||||
}
|
||||
|
||||
success_response(oss.str(), att);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void VirtualMachinePoolMonitoring::request_execute(
|
||||
xmlrpc_c::paramList const& paramList,
|
||||
RequestAttributes& att)
|
||||
|
@ -2219,3 +2219,41 @@ void VirtualMachineRecover::request_execute(
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void VirtualMachinePoolCalculateShowback::request_execute(
|
||||
xmlrpc_c::paramList const& paramList,
|
||||
RequestAttributes& att)
|
||||
{
|
||||
int start_month = xmlrpc_c::value_int(paramList.getInt(1));
|
||||
int start_year = xmlrpc_c::value_int(paramList.getInt(2));
|
||||
int end_month = xmlrpc_c::value_int(paramList.getInt(3));
|
||||
int end_year = xmlrpc_c::value_int(paramList.getInt(4));
|
||||
|
||||
ostringstream oss;
|
||||
string where;
|
||||
int rc;
|
||||
string error_str;
|
||||
|
||||
if ( att.gid != 0 )
|
||||
{
|
||||
failure_response(AUTHORIZATION,
|
||||
authorization_error("Action reserved for group 0 only", att),
|
||||
att);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = (static_cast<VirtualMachinePool *>(pool))->calculate_showback(
|
||||
start_month, start_year, end_month, end_year, error_str);
|
||||
|
||||
if (rc != 0)
|
||||
{
|
||||
failure_response(AUTHORIZATION,
|
||||
request_error(error_str, ""),
|
||||
att);
|
||||
return;
|
||||
}
|
||||
|
||||
success_response("", att);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -26,6 +26,8 @@ enabled_tabs:
|
||||
enterprise-tab: true
|
||||
zones-tab: true
|
||||
autorefresh: true
|
||||
features:
|
||||
showback: true
|
||||
tabs:
|
||||
dashboard-tab:
|
||||
panel_tabs:
|
||||
@ -51,6 +53,8 @@ tabs:
|
||||
panel_tabs:
|
||||
user_info_tab: true
|
||||
user_quotas_tab: true
|
||||
user_accounting_tab: true
|
||||
user_showback_tab: true
|
||||
table_columns:
|
||||
- 0 # Checkbox
|
||||
- 1 # ID
|
||||
@ -74,7 +78,11 @@ tabs:
|
||||
User.delete: true
|
||||
groups-tab:
|
||||
panel_tabs:
|
||||
group_info_tab: true
|
||||
group_quotas_tab: true
|
||||
group_providers_tab: true
|
||||
group_accounting_tab: true
|
||||
group_shoback_tab: true
|
||||
table_columns:
|
||||
- 0 # Checkbox
|
||||
- 1 # ID
|
||||
|
@ -1,6 +1,8 @@
|
||||
provision_logo: images/one_small_logo.png
|
||||
enabled_tabs:
|
||||
provision-tab: true
|
||||
features:
|
||||
showback: true
|
||||
tabs:
|
||||
provision-tab:
|
||||
panel_tabs:
|
||||
|
@ -25,6 +25,8 @@ enabled_tabs:
|
||||
community-tab: false
|
||||
enterprise-tab: false
|
||||
autorefresh: true
|
||||
features:
|
||||
showback: true
|
||||
tabs:
|
||||
dashboard-tab:
|
||||
panel_tabs:
|
||||
@ -51,6 +53,8 @@ tabs:
|
||||
panel_tabs:
|
||||
user_info_tab: true
|
||||
user_quotas_tab: true
|
||||
user_accounting_tab: true
|
||||
user_showback_tab: true
|
||||
table_columns:
|
||||
- 0 # Checkbox
|
||||
- 1 # ID
|
||||
@ -73,7 +77,11 @@ tabs:
|
||||
User.delete: true
|
||||
groups-tab:
|
||||
panel_tabs:
|
||||
group_info_tab: true
|
||||
group_quotas_tab: true
|
||||
group_providers_tab: true
|
||||
group_accounting_tab: true
|
||||
group_shoback_tab: true
|
||||
table_columns:
|
||||
- 0 # Checkbox
|
||||
- 1 # ID
|
||||
|
@ -26,6 +26,8 @@ enabled_tabs:
|
||||
enterprise-tab: true
|
||||
zones-tab: true
|
||||
autorefresh: true
|
||||
features:
|
||||
showback: true
|
||||
tabs:
|
||||
dashboard-tab:
|
||||
panel_tabs:
|
||||
@ -51,6 +53,8 @@ tabs:
|
||||
panel_tabs:
|
||||
user_info_tab: true
|
||||
user_quotas_tab: true
|
||||
user_accounting_tab: true
|
||||
user_showback_tab: true
|
||||
table_columns:
|
||||
- 0 # Checkbox
|
||||
- 1 # ID
|
||||
@ -74,7 +78,11 @@ tabs:
|
||||
User.delete: true
|
||||
groups-tab:
|
||||
panel_tabs:
|
||||
group_info_tab: true
|
||||
group_quotas_tab: true
|
||||
group_providers_tab: true
|
||||
group_accounting_tab: true
|
||||
group_shoback_tab: true
|
||||
table_columns:
|
||||
- 0 # Checkbox
|
||||
- 1 # ID
|
||||
|
@ -1,6 +1,8 @@
|
||||
provision_logo: images/one_small_logo.png
|
||||
enabled_tabs:
|
||||
provision-tab: true
|
||||
features:
|
||||
showback: true
|
||||
tabs:
|
||||
provision-tab:
|
||||
panel_tabs:
|
||||
|
@ -391,6 +391,33 @@ class SunstoneServer < CloudServer
|
||||
return [200, rc.to_json]
|
||||
end
|
||||
|
||||
def get_vm_showback(options)
|
||||
pool = VirtualMachinePool.new(@client)
|
||||
|
||||
filter_flag = options[:userfilter] ? options[:userfilter].to_i : VirtualMachinePool::INFO_ALL
|
||||
start_month = options[:start_month] ? options[:start_month].to_i : -1
|
||||
start_year = options[:start_year] ? options[:start_year].to_i : -1
|
||||
end_month = options[:end_month] ? options[:end_month].to_i : -1
|
||||
end_year = options[:end_year] ? options[:end_year].to_i : -1
|
||||
|
||||
acct_options = {
|
||||
:start_month => start_month,
|
||||
:start_year => start_year,
|
||||
:end_month => end_month,
|
||||
:end_year => end_year,
|
||||
:group => options[:group]
|
||||
}
|
||||
|
||||
rc = pool.showback(filter_flag, acct_options)
|
||||
|
||||
if OpenNebula.is_error?(rc)
|
||||
error = Error.new(rc.message)
|
||||
return [500, error.to_json]
|
||||
end
|
||||
|
||||
return [200, rc.to_json]
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
|
@ -639,6 +639,31 @@ var OpenNebula = {
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
"showback": function(params, resource, path){
|
||||
var callback = params.success;
|
||||
var callback_error = params.error;
|
||||
var data = params.data;
|
||||
|
||||
var method = "showback";
|
||||
var request = OpenNebula.Helper.request(resource,method, data);
|
||||
|
||||
var url = path ? path : resource.toLowerCase() + "/showback";
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: "GET",
|
||||
data: data,
|
||||
dataType: "json",
|
||||
success: function(response){
|
||||
return callback ? callback(request, response) : null;
|
||||
},
|
||||
error: function(response){
|
||||
return callback_error ?
|
||||
callback_error(request, OpenNebula.Error(response)) : null;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
"Auth": {
|
||||
@ -1045,6 +1070,9 @@ var OpenNebula = {
|
||||
"accounting": function(params){
|
||||
OpenNebula.Action.accounting(params,OpenNebula.VM.resource);
|
||||
},
|
||||
"showback": function(params){
|
||||
OpenNebula.Action.showback(params,OpenNebula.VM.resource);
|
||||
}
|
||||
},
|
||||
|
||||
"Group": {
|
||||
|
@ -31,6 +31,7 @@ Config = {
|
||||
var enabled = config['view']['enabled_tabs'][tab_name];
|
||||
return enabled;
|
||||
},
|
||||
|
||||
"isTabActionEnabled": function(tab_name, action_name, panel_name){
|
||||
var enabled;
|
||||
if (panel_name) {
|
||||
@ -51,6 +52,14 @@ Config = {
|
||||
}
|
||||
},
|
||||
|
||||
"isFeatureEnabled": function(feature_name){
|
||||
if (config['view']['features'] && config['view']['features'][feature_name]) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
"tabTableColumns": function(tab_name){
|
||||
var columns = config['view']['tabs'][tab_name]['table_columns'];
|
||||
|
||||
@ -361,15 +370,6 @@ function setupConfigDialog() {
|
||||
});
|
||||
}
|
||||
|
||||
function tr(str){
|
||||
var tmp = locale[str];
|
||||
if ( tmp == null || tmp == "" ) {
|
||||
//console.debug("Missing translation: "+str);
|
||||
tmp = str;
|
||||
}
|
||||
return tmp;
|
||||
};
|
||||
|
||||
function updateUserConfigInfo(request,user_json) {
|
||||
var info = user_json.USER;
|
||||
|
||||
|
@ -734,10 +734,26 @@ function updateGroupInfo(request,group){
|
||||
content: '<div id="group_accounting"></div>'
|
||||
};
|
||||
|
||||
|
||||
Sunstone.updateInfoPanelTab("group_info_panel","group_info_tab",info_tab);
|
||||
Sunstone.updateInfoPanelTab("group_info_panel","group_quotas_tab",quotas_tab);
|
||||
Sunstone.updateInfoPanelTab("group_info_panel","group_providers_tab",providers_tab);
|
||||
Sunstone.updateInfoPanelTab("group_info_panel","group_accouning_tab",accounting_tab);
|
||||
Sunstone.updateInfoPanelTab("group_info_panel","group_accounting_tab",accounting_tab);
|
||||
|
||||
if (Config.isFeatureEnabled("showback")) {
|
||||
var showback_tab = {
|
||||
title: tr("Showback"),
|
||||
icon: "fa-money",
|
||||
content: '<div id="group_showback"></div>'
|
||||
};
|
||||
|
||||
Sunstone.updateInfoPanelTab("group_info_panel","group_showback_tab",showback_tab);
|
||||
|
||||
showbackGraphs(
|
||||
$("#group_showback","#group_info_panel"),
|
||||
{ fixed_group: info.ID });
|
||||
}
|
||||
|
||||
Sunstone.popUpInfoPanel("group_info_panel", 'groups-tab');
|
||||
|
||||
$("#add_rp_button", $("#group_info_panel")).click(function(){
|
||||
|
@ -825,9 +825,10 @@ var provision_user_info = '<div id="provision_user_info" class="hidden section_c
|
||||
'<div class="row">'+
|
||||
'<div class="large-12 large-centered columns">'+
|
||||
'<dl class="tabs text-center" data-tab style="width: 100%">'+
|
||||
'<dd class="active" style="width: 34%;"><a href="#provision_info_settings"><i class="fa fa-fw fa-lg fa-cogs"/> '+ tr("Settings") +'</a></dd>'+
|
||||
'<dd style="width: 33%;"><a href="#provision_info_acct"><i class="fa fa-fw fa-lg fa-bar-chart-o"/> '+ tr("Accounting") +'</a></dd>'+
|
||||
'<dd style="width: 33%;"><a href="#provision_info_quotas"><i class="fa fa-fw fa-lg fa-align-left"/> '+ tr("Quotas") +'</a></dd>'+
|
||||
'<dd class="active" style="width: '+ (Config.isFeatureEnabled("showback") ? '25%' : '33%')+';"><a href="#provision_info_settings"><i class="fa fa-fw fa-lg fa-cogs"/> '+ tr("Settings") +'</a></dd>'+
|
||||
(Config.isFeatureEnabled("showback") ? '<dd style="width: 25%;"><a href="#provision_info_showback"><i class="fa fa-fw fa-lg fa-money"/> '+ tr("Showback") +'</a></dd>' : '') +
|
||||
'<dd style="width: '+ (Config.isFeatureEnabled("showback") ? '25%' : '33%')+';"><a href="#provision_info_acct"><i class="fa fa-fw fa-lg fa-bar-chart-o"/> '+ tr("Accounting") +'</a></dd>'+
|
||||
'<dd style="width: '+ (Config.isFeatureEnabled("showback") ? '25%' : '33%')+';"><a href="#provision_info_quotas"><i class="fa fa-fw fa-lg fa-align-left"/> '+ tr("Quotas") +'</a></dd>'+
|
||||
'</dl>'+
|
||||
'<br>'+
|
||||
'</div>'+
|
||||
@ -839,6 +840,12 @@ var provision_user_info = '<div id="provision_user_info" class="hidden section_c
|
||||
'</div>'+
|
||||
'</div>'+
|
||||
'</div>'+
|
||||
(Config.isFeatureEnabled("showback") ? '<div class="content" id="provision_info_showback">'+
|
||||
'<div class="row">'+
|
||||
'<div id="provision_user_info_showback_div" class="large-12 large-centered columns">'+
|
||||
'</div>'+
|
||||
'</div>'+
|
||||
'</div>' : '')+
|
||||
'<div class="content" id="provision_info_quotas">'+
|
||||
'<div class="row">'+
|
||||
'<div id="provision_user_info_quotas_div" class="large-9 large-centered columns quotas">'+
|
||||
@ -1199,6 +1206,21 @@ var provision_manage_vdc = '<div id="provision_manage_vdc" class="hidden section
|
||||
'</div>'+
|
||||
'</div>'+
|
||||
'<br>'+
|
||||
(Config.isFeatureEnabled("showback") ? '<div class="row">'+
|
||||
'<div class="large-11 large-centered columns">'+
|
||||
'<h3 class="subheader text-right">'+
|
||||
'<span class="left">'+
|
||||
tr("VDC Showback")+
|
||||
'</span>'+
|
||||
'</h3>'+
|
||||
'</div>'+
|
||||
'</div>'+
|
||||
'<br>'+
|
||||
'<div class="row">'+
|
||||
'<div id="provision_info_vdc_group_showback" class="large-10 large-centered columns">'+
|
||||
'</div>'+
|
||||
'</div>'+
|
||||
'<br>' : '') +
|
||||
'<div class="row">'+
|
||||
'<div class="large-11 large-centered columns">'+
|
||||
'<h3 class="subheader text-right">'+
|
||||
@ -1899,10 +1921,10 @@ function generate_custom_attrs(context, custom_attrs) {
|
||||
}
|
||||
}
|
||||
|
||||
function generate_cardinality_selector(context, role_template) {
|
||||
function generate_cardinality_selector(context, role_template, template_json) {
|
||||
context.off();
|
||||
var min_vms = (role_template.min_vms||1);
|
||||
var max_vms = (role_template.max_vms||100);
|
||||
var max_vms = (role_template.max_vms||20);
|
||||
|
||||
context.html(
|
||||
'<br>'+
|
||||
@ -1922,33 +1944,60 @@ function generate_cardinality_selector(context, role_template) {
|
||||
'<div class="row">'+
|
||||
'<div class="large-12 columns">'+
|
||||
'<div class="row">'+
|
||||
'<div class="large-5 text-center columns">'+
|
||||
'<span class="cardinality_value" style="color: #777; font-size:60px">'+role_template.cardinality+'</span>'+
|
||||
'<div class="large-2 text-center columns">'+
|
||||
'<span class="cardinality_value" style="color: #777; font-size:40px">'+role_template.cardinality+'</span>'+
|
||||
'<br>'+
|
||||
'<span style="color: #999;">'+tr("VMs")+'</span>'+
|
||||
'</div>'+
|
||||
'<div class="large-7 columns">'+
|
||||
'<div class="cardinality_slider_div">'+
|
||||
'<span class="" style="color: #777;">'+tr("Change cardinality")+'</span>'+
|
||||
'<br>'+
|
||||
'<div class="range-slider radius cardinality_slider" data-slider data-options="start: 1; end: 50;">'+
|
||||
'<span class="range-slider-handle"></span>'+
|
||||
'<span class="range-slider-active-segment"></span>'+
|
||||
'<input type="hidden">'+
|
||||
'<div class="large-6 columns">'+
|
||||
'<div class="cardinality_slider_div">'+
|
||||
'<span class="" style="color: #777;">'+tr("Change cardinality")+'</span>'+
|
||||
'<br>'+
|
||||
'<div class="range-slider radius cardinality_slider" data-slider data-options="start: 1; end: 50;">'+
|
||||
'<span class="range-slider-handle"></span>'+
|
||||
'<span class="range-slider-active-segment"></span>'+
|
||||
'<input type="hidden">'+
|
||||
'</div>'+
|
||||
'<span class="left" style="color: #999;">'+min_vms+'</span>'+
|
||||
'<span class="right" style="color: #999;">'+max_vms+'</span>'+
|
||||
'</div>'+
|
||||
'<div class="cardinality_no_slider_div">'+
|
||||
'<br>'+
|
||||
'<br>'+
|
||||
'<span class="" style="color: #999;">'+tr("The cardinality for this role cannot be changed")+'</span>'+
|
||||
'</div>'+
|
||||
'<span class="left" style="color: #999;">'+min_vms+'</span>'+
|
||||
'<span class="right" style="color: #999;">'+max_vms+'</span>'+
|
||||
'</div>'+
|
||||
'<div class="cardinality_no_slider_div">'+
|
||||
'<div class="large-4 columns text-center provision_create_service_cost_div hidden">'+
|
||||
'<span class="cost_value" style="color: #777; font-size:40px"></span>'+
|
||||
'<br>'+
|
||||
'<br>'+
|
||||
'<span class="" style="color: #999;">'+tr("The cardinality for this role cannot be changed")+'</span>'+
|
||||
'</div>'+
|
||||
'<span style="color: #999;">'+tr("COST")+' / ' + tr("HOUR") + '</span>'+
|
||||
'</div>'+
|
||||
'</div>'+
|
||||
'</div>'+
|
||||
'</div>');
|
||||
|
||||
var capacity = template_json.VMTEMPLATE.TEMPLATE;
|
||||
var cost = 0;
|
||||
if (capacity.CPU_COST || capacity.MEMORY_COST && Config.isFeatureEnabled("showback")) {
|
||||
$(".provision_create_service_cost_div").show();
|
||||
|
||||
if (capacity.CPU && capacity.CPU_COST) {
|
||||
cost += capacity.CPU * capacity.CPU_COST
|
||||
$(".cost_value").data("CPU_COST", capacity.CPU_COST);
|
||||
}
|
||||
|
||||
if (capacity.MEMORY && capacity.MEMORY_COST) {
|
||||
cost += capacity.MEMORY * capacity.MEMORY_COST
|
||||
$(".cost_value").data("MEMORY_COST", capacity.MEMORY_COST);
|
||||
}
|
||||
|
||||
$(".provision_create_service_cost_div", context).data("cost", cost)
|
||||
var cost_value = cost*parseInt(role_template.cardinality);
|
||||
$(".cost_value").html(cost_value.toFixed(2));
|
||||
} else {
|
||||
$(".provision_create_service_cost_div").hide();
|
||||
}
|
||||
|
||||
if (max_vms > min_vms) {
|
||||
$( ".cardinality_slider", context).attr('data-options', 'start: '+min_vms+'; end: '+max_vms+';')
|
||||
context.foundation();
|
||||
@ -1959,9 +2008,9 @@ function generate_cardinality_selector(context, role_template) {
|
||||
|
||||
$( ".cardinality_slider", context).on('change', function(){
|
||||
$(".cardinality_value",context).html($(this).attr('data-slider'))
|
||||
var cost_value = $(".provision_create_service_cost_div", context).data("cost")*$(this).attr('data-slider');
|
||||
$(".cost_value").html(cost_value.toFixed(2));
|
||||
});
|
||||
|
||||
|
||||
} else {
|
||||
$( ".cardinality_slider_div", context).hide();
|
||||
$( ".cardinality_no_slider_div", context).show();
|
||||
@ -2000,18 +2049,23 @@ function generate_provision_instance_type_accordion(context, capacity) {
|
||||
'<div class="row">'+
|
||||
'<div class="large-12 large-centered columns">'+
|
||||
'<div class="row text-center">'+
|
||||
'<div class="large-6 columns">'+
|
||||
'<div class="large-4 columns">'+
|
||||
'<span class="cpu_value" style="color: #777; font-size:60px">'+capacity.CPU+'</span>'+
|
||||
'<br>'+
|
||||
'<span style="color: #999;">'+tr("CPU")+'</span>'+
|
||||
'</div>'+
|
||||
'<div class="large-6 columns">'+
|
||||
'<div class="large-4 columns">'+
|
||||
'<span class="memory_value" style="color: #777; font-size:60px">'+memory_value+'</span>'+
|
||||
' '+
|
||||
'<span class="memory_unit" style="color: #777; font-size:30px">'+memory_unit+'</span>'+
|
||||
'<br>'+
|
||||
'<span style="color: #999;">'+tr("MEMORY")+'</span>'+
|
||||
'</div>'+
|
||||
'<div class="large-4 columns provision_create_template_cost_div hidden">'+
|
||||
'<span class="cost_value" style="color: #777; font-size:60px"></span>'+
|
||||
'<br>'+
|
||||
'<span style="color: #999;">'+tr("COST")+' / ' + tr("HOUR") + '</span>'+
|
||||
'</div>'+
|
||||
'</div>'+
|
||||
'</div>'+
|
||||
'</div>'+
|
||||
@ -2054,6 +2108,25 @@ function generate_provision_instance_type_accordion(context, capacity) {
|
||||
'</div>'+
|
||||
'<br>');
|
||||
|
||||
var cost = 0;
|
||||
if (capacity.CPU_COST || capacity.MEMORY_COST && Config.isFeatureEnabled("showback")) {
|
||||
$(".provision_create_template_cost_div").show();
|
||||
|
||||
if (capacity.CPU && capacity.CPU_COST) {
|
||||
cost += capacity.CPU * capacity.CPU_COST
|
||||
$(".cost_value").data("CPU_COST", capacity.CPU_COST);
|
||||
}
|
||||
|
||||
if (capacity.MEMORY && capacity.MEMORY_COST) {
|
||||
cost += capacity.MEMORY * capacity.MEMORY_COST
|
||||
$(".cost_value").data("MEMORY_COST", capacity.MEMORY_COST);
|
||||
}
|
||||
|
||||
$(".cost_value").html(cost);
|
||||
} else {
|
||||
$(".provision_create_template_cost_div").hide();
|
||||
}
|
||||
|
||||
provision_instance_type_accordion_id += 1;
|
||||
|
||||
var provision_instance_types_datatable = $('.provision_instance_types_table', context).dataTable({
|
||||
@ -2146,6 +2219,20 @@ function generate_provision_instance_type_accordion(context, capacity) {
|
||||
$(".memory_value", context).html(memory_value);
|
||||
$(".memory_unit", context).html(memory_unit);
|
||||
|
||||
if (Config.isFeatureEnabled("showback")) {
|
||||
var cost = 0;
|
||||
|
||||
if ($(".cost_value").data("CPU_COST")) {
|
||||
cost += $(this).attr("cpu") * $(".cost_value").data("CPU_COST")
|
||||
}
|
||||
|
||||
if ($(".cost_value").data("MEMORY_COST")) {
|
||||
cost += $(this).attr("memory") * $(".cost_value").data("MEMORY_COST")
|
||||
}
|
||||
|
||||
$(".cost_value").html(cost);
|
||||
}
|
||||
|
||||
$('.accordion a', context).first().trigger("click");
|
||||
})
|
||||
|
||||
@ -2690,6 +2777,13 @@ function show_provision_user_info_callback(request, response) {
|
||||
$("#provision_user_info_acct_div"),
|
||||
{ fixed_user: info.ID,
|
||||
fixed_group_by: "vm" });
|
||||
|
||||
|
||||
if (Config.isFeatureEnabled("showback")) {
|
||||
showbackGraphs(
|
||||
$("#provision_user_info_showback_div"),
|
||||
{ fixed_user: info.ID});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2715,6 +2809,12 @@ function show_provision_group_info_callback(request, response) {
|
||||
{ fixed_group: info.ID,
|
||||
init_group_by: "user" });
|
||||
|
||||
if (Config.isFeatureEnabled("showback")) {
|
||||
showbackGraphs(
|
||||
$("#provision_info_vdc_group_showback", context),
|
||||
{ fixed_group: info.ID });
|
||||
}
|
||||
|
||||
$("#acct_placeholder", context).hide();
|
||||
}
|
||||
|
||||
@ -5010,6 +5110,9 @@ function setup_provision_user_info(context) {
|
||||
'<span class="provision_vdc_user_info_show_acct button medium radius" data-tooltip title="'+tr("User Accounting")+'" style="margin-right: 10px">'+
|
||||
'<i class="fa fa-bar-chart-o fa-lg"></i>'+
|
||||
'</span>'+
|
||||
(Config.isFeatureEnabled("showback") ? '<span class="provision_vdc_user_info_show_showback button medium radius" data-tooltip title="'+tr("User Showback")+'" style="margin-right: 10px">'+
|
||||
'<i class="fa fa-money fa-lg"></i>'+
|
||||
'</span>' : '') +
|
||||
'</li>'+
|
||||
'<li class="provision-bullet-item text-left">'+
|
||||
'</li>')
|
||||
@ -5146,6 +5249,21 @@ function setup_provision_user_info(context) {
|
||||
'</h2>')
|
||||
})
|
||||
|
||||
if (Config.isFeatureEnabled("showback")) {
|
||||
context.on("click", ".provision_vdc_user_info_show_showback", function(){
|
||||
$(".provision_vdc_info_container", context).html("");
|
||||
|
||||
showbackGraphs(
|
||||
$(".provision_vdc_info_container", context),
|
||||
{ fixed_user: $(".provision_info_vdc_user", context).attr("opennebula_id")});
|
||||
|
||||
$(".provision_vdc_info_container", context).prepend(
|
||||
'<h2 class="subheader">'+
|
||||
$(".provision_info_vdc_user", context).attr("uname") + ' ' + tr("Showback")+
|
||||
'</h2>')
|
||||
})
|
||||
};
|
||||
|
||||
context.on("click", ".provision_vdc_user_delete_confirm_button", function(){
|
||||
$(".provision_vdc_user_confirm_action", context).html(
|
||||
'<div data-alert class="alert-box secondary radius">'+
|
||||
@ -6294,26 +6412,17 @@ $(document).ready(function(){
|
||||
var template_id = role.vm_template;
|
||||
var role_html_id = "#provision_create_flow_role_"+index;
|
||||
|
||||
generate_cardinality_selector(
|
||||
$(".provision_cardinality_selector", context),
|
||||
role);
|
||||
|
||||
OpenNebula.Template.show({
|
||||
data : {
|
||||
id: template_id
|
||||
},
|
||||
success: function(request,template_json){
|
||||
var role_context = $(role_html_id)
|
||||
//var template_nic = template_json.VMTEMPLATE.TEMPLATE.NIC
|
||||
//var nics = []
|
||||
//if ($.isArray(template_nic))
|
||||
// nics = template_nic
|
||||
//else if (!$.isEmptyObject(template_nic))
|
||||
// nics = [template_nic]
|
||||
//
|
||||
//generate_provision_instance_type_accordion(
|
||||
// $(".provision_capacity_selector", role_context),
|
||||
// template_json.VMTEMPLATE.TEMPLATE);
|
||||
|
||||
generate_cardinality_selector(
|
||||
$(".provision_cardinality_selector", context),
|
||||
role,
|
||||
template_json);
|
||||
|
||||
if (template_json.VMTEMPLATE.TEMPLATE.USER_INPUTS) {
|
||||
generate_custom_attrs(
|
||||
|
@ -607,9 +607,24 @@ function updateUserInfo(request,user){
|
||||
content: '<div id="user_accounting"></div>'
|
||||
};
|
||||
|
||||
|
||||
Sunstone.updateInfoPanelTab("user_info_panel","user_info_tab",info_tab);
|
||||
Sunstone.updateInfoPanelTab("user_info_panel","user_quotas_tab",quotas_tab);
|
||||
Sunstone.updateInfoPanelTab("user_info_panel","user_accouning_tab",accounting_tab);
|
||||
Sunstone.updateInfoPanelTab("user_info_panel","user_accounting_tab",accounting_tab);
|
||||
|
||||
if (Config.isFeatureEnabled("showback")) {
|
||||
var showback_tab = {
|
||||
title: tr("Showback"),
|
||||
icon: "fa-money",
|
||||
content: '<div id="user_showback"></div>'
|
||||
};
|
||||
|
||||
Sunstone.updateInfoPanelTab("user_info_panel","user_showback_tab",showback_tab);
|
||||
|
||||
showbackGraphs(
|
||||
$("#user_showback","#user_info_panel"),
|
||||
{ fixed_user: info.ID });
|
||||
}
|
||||
//Sunstone.updateInfoPanelTab("user_info_panel","user_acct_tab",acct_tab);
|
||||
Sunstone.popUpInfoPanel("user_info_panel", 'users-tab');
|
||||
|
||||
|
@ -2304,13 +2304,15 @@ function printCapacity(vm_info){
|
||||
|
||||
html += '\
|
||||
<div class="row">\
|
||||
<div class="large-6 columns">\
|
||||
<div class="large-9 columns">\
|
||||
<table class="info_table dataTable extended_table">\
|
||||
<thead>\
|
||||
<tr>\
|
||||
<th>'+tr("CPU")+'</th>\
|
||||
<th>'+tr("VCPU")+'</th>\
|
||||
<th>'+tr("MEMORY")+'</th>\
|
||||
<th>'+tr("Cost / CPU")+'</th>\
|
||||
<th>'+tr("Cost / MByte")+'</th>\
|
||||
<th></th>\
|
||||
</tr>\
|
||||
</thead>\
|
||||
@ -2319,6 +2321,8 @@ function printCapacity(vm_info){
|
||||
<td id="cpu_info">' + vm_info.TEMPLATE.CPU + '</td>\
|
||||
<td id="vcpu_info">' + (vm_info.TEMPLATE.VCPU ? vm_info.TEMPLATE.VCPU : '-') + '</td>\
|
||||
<td id="memory_info" one_value="'+vm_info.TEMPLATE.MEMORY+'">' + humanize_size_from_mb(vm_info.TEMPLATE.MEMORY) + '</td>\
|
||||
<td id="cpu_cost_info">' + (vm_info.TEMPLATE.CPU_COST ? vm_info.TEMPLATE.CPU_COST : '-') + '</td>\
|
||||
<td id="memory_cost_info" >' + (vm_info.TEMPLATE.MEMORY_COST ? vm_info.TEMPLATE.MEMORY_COST : '-') + '</td>\
|
||||
<td>';
|
||||
|
||||
if (Config.isTabActionEnabled("vms-tab", "VM.resize")) {
|
||||
|
@ -47,6 +47,19 @@ var top_interval_ids = {};
|
||||
var QUOTA_LIMIT_DEFAULT = "-1";
|
||||
var QUOTA_LIMIT_UNLIMITED = "-2";
|
||||
|
||||
function tr(str){
|
||||
var tmp = locale[str];
|
||||
if ( tmp == null || tmp == "" ) {
|
||||
//console.debug("Missing translation: "+str);
|
||||
tmp = str;
|
||||
}
|
||||
return tmp;
|
||||
};
|
||||
var $months = new Array(
|
||||
tr("January"),tr("February"),tr("March"),tr("April"),tr("May"),
|
||||
tr("June"),tr("July"),tr("August"),tr("September"),tr("October"),
|
||||
tr("November"),tr("December"));
|
||||
|
||||
//Sunstone configuration is formed by predifined "actions", main tabs
|
||||
//and "info_panels". Each tab has "content" and "buttons". Each
|
||||
//"info_panel" has "tabs" with "content".
|
||||
@ -1202,11 +1215,7 @@ function pretty_time_runtime(time){
|
||||
|
||||
function _format_date(unix_timestamp) {
|
||||
var difference_in_seconds = (Math.round((new Date()).getTime() / 1000)) - unix_timestamp,
|
||||
current_date = new Date(unix_timestamp * 1000), minutes, hours,
|
||||
months = new Array(
|
||||
'January','February','March','April','May',
|
||||
'June','July','August','September','October',
|
||||
'November','December');
|
||||
current_date = new Date(unix_timestamp * 1000), minutes, hours;
|
||||
|
||||
if(difference_in_seconds < 60) {
|
||||
return difference_in_seconds + "s" + " ago";
|
||||
@ -1218,9 +1227,9 @@ function _format_date(unix_timestamp) {
|
||||
return hours + "h" + " ago";
|
||||
} else if (difference_in_seconds > 60*60*24){
|
||||
if(current_date.getYear() !== new Date().getYear())
|
||||
return current_date.getDay() + " " + months[current_date.getMonth()].substr(0,3) + " " + _fourdigits(current_date.getYear());
|
||||
return current_date.getDay() + " " + $months[current_date.getMonth()].substr(0,3) + " " + _fourdigits(current_date.getYear());
|
||||
else {
|
||||
return current_date.getDay() + " " + months[current_date.getMonth()].substr(0,3);
|
||||
return current_date.getDay() + " " + $months[current_date.getMonth()].substr(0,3);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4745,6 +4754,304 @@ function time_UTC(time){
|
||||
return d.getUTCFullYear() + '/' + (d.getUTCMonth()+1) + '/' + d.getUTCDate();
|
||||
}
|
||||
|
||||
|
||||
// div is a jQuery selector
|
||||
// The following options can be set:
|
||||
// fixed_user fix an owner user ID
|
||||
// fixed_group fix an owner group ID
|
||||
// init_group_by "user", "group", "vm". init the group-by selector
|
||||
// fixed_group_by "user", "group", "vm". set a fixed group-by selector
|
||||
function showbackGraphs(div, opt){
|
||||
|
||||
if(div.html() != ""){
|
||||
return false;
|
||||
}
|
||||
|
||||
div.html(
|
||||
'<div class="row">\
|
||||
<div id="showback_owner_container" class="left columns">\
|
||||
<label for="showback_owner">' + tr("Filter") + '</label>\
|
||||
<div class="row">\
|
||||
<div class="large-5 columns">\
|
||||
<select id="showback_owner" name="showback_owner">\
|
||||
<option value="showback_owner_all">' + tr("All") + '</option>\
|
||||
<option value="showback_owner_group">' + tr("Group") + '</option>\
|
||||
<option value="showback_owner_user">' + tr("User") + '</option>\
|
||||
</select>\
|
||||
</div>\
|
||||
<div class="large-7 columns">\
|
||||
<div id="showback_owner_select"/>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div id="showback_button_container" class="left columns">\
|
||||
<button class="button radius success right" id="showback_submit" type="button">'+tr("Get Showback")+'</button>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div id="showback_placeholder">\
|
||||
<div class="row">\
|
||||
<div class="large-8 large-centered columns">\
|
||||
<div class="text-center">\
|
||||
<span class="fa-stack fa-5x" style="color: #dfdfdf">\
|
||||
<i class="fa fa-cloud fa-stack-2x"></i>\
|
||||
<i class="fa fa-money fa-stack-1x fa-inverse"></i>\
|
||||
</span>\
|
||||
<div id="showback_no_data" class="hidden">\
|
||||
<br>\
|
||||
<p style="font-size: 18px; color: #999">'+
|
||||
tr("There are no showback records")+
|
||||
'</p>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div id="showback_content" class="hidden">\
|
||||
<div class="row showback_table">\
|
||||
<div class="large-12 columns graph_legend">\
|
||||
<h3 class="subheader">'+tr("Showback")+'</h3>\
|
||||
</div>\
|
||||
<div class="large-6 columns" style="overflow:auto">\
|
||||
<table id="showback_datatable" class="datatable twelve">\
|
||||
<thead>\
|
||||
<tr>\
|
||||
<th>dateint</th>\
|
||||
<th>'+tr("Year")+'</th>\
|
||||
<th>'+tr("Month")+'</th>\
|
||||
<th>'+tr("Date")+'</th>\
|
||||
<th>'+tr("Cost")+'</th>\
|
||||
</tr>\
|
||||
</thead>\
|
||||
<tbody id="tbody_showback_datatable">\
|
||||
</tbody>\
|
||||
</table>\
|
||||
<span class="label secondary radius showback_select_a_row">'+tr("Select a row to get detailed information of the month")+'</span>\
|
||||
</div>\
|
||||
<div class="large-6 columns">\
|
||||
<div class="large-12 columns centered graph" id="showback_graph" style="height: 200px;">\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="row showback_vms_table hidden">\
|
||||
<div class="large-12 columns graph_legend">\
|
||||
<h3 class="subheader" id="showback_vms_title">'+tr("VMs")+'</h3>\
|
||||
</div>\
|
||||
<div class="large-12 columns" style="overflow:auto">\
|
||||
<table id="showback_vms_datatable" class="datatable twelve">\
|
||||
<thead>\
|
||||
<tr>\
|
||||
<th>'+tr("ID")+'</th>\
|
||||
<th>'+tr("Name")+'</th>\
|
||||
<th>'+tr("Owner")+'</th>\
|
||||
<th>'+tr("Hours")+'</th>\
|
||||
<th>'+tr("Cost")+'</th>\
|
||||
</tr>\
|
||||
</thead>\
|
||||
<tbody id="tbody_showback_datatable">\
|
||||
</tbody>\
|
||||
</table>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>');
|
||||
|
||||
if (opt == undefined){
|
||||
opt = {};
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// VM owner: all, group, user
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
if (opt.fixed_user != undefined || opt.fixed_group != undefined){
|
||||
$("#showback_owner_container", div).hide();
|
||||
} else {
|
||||
$("select#showback_owner", div).change(function(){
|
||||
var value = $(this).val();
|
||||
|
||||
switch (value){
|
||||
case "showback_owner_all":
|
||||
$("#showback_owner_select", div).hide();
|
||||
break;
|
||||
|
||||
case "showback_owner_group":
|
||||
$("#showback_owner_select", div).show();
|
||||
insertSelectOptions("#showback_owner_select", div, "Group");
|
||||
break;
|
||||
|
||||
case "showback_owner_user":
|
||||
$("#showback_owner_select", div).show();
|
||||
insertSelectOptions("#showback_owner_select", div, "User", -1, false,
|
||||
'<option value="-1">'+tr("<< me >>")+'</option>');
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
showback_dataTable = $("#showback_datatable",div).dataTable({
|
||||
"bSortClasses" : false,
|
||||
"bDeferRender": true,
|
||||
"iDisplayLength": 6,
|
||||
"sDom": "t<'row collapse'<'small-12 columns'p>>",
|
||||
"aoColumnDefs": [
|
||||
{ "bVisible": false, "aTargets": [0,1,2]}
|
||||
]
|
||||
});
|
||||
|
||||
showback_dataTable.fnSort( [ [0, "desc"] ] );
|
||||
|
||||
showback_vms_dataTable = $("#showback_vms_datatable",div).dataTable({
|
||||
"bSortClasses" : false,
|
||||
"bDeferRender": true
|
||||
});
|
||||
|
||||
showback_dataTable.on("click", "tbody tr", function(){
|
||||
var cells = showback_dataTable.fnGetData(this);
|
||||
var year = cells[1];
|
||||
var month = cells[2];
|
||||
|
||||
showback_vms_dataTable.fnClearTable();
|
||||
showback_vms_dataTable.fnAddData(showback_dataTable.data("vms_per_date")[year][month].VMS)
|
||||
|
||||
$("#showback_vms_title", div).text($months[month-1] + " " + year + " " + tr("VMs"))
|
||||
$(".showback_vms_table", div).show();
|
||||
$(".showback_select_a_row", div).hide();
|
||||
})
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Submit request
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
$("#showback_submit", div).on("click", function(){
|
||||
var options = {};
|
||||
if (opt.fixed_user != undefined){
|
||||
options.userfilter = opt.fixed_user;
|
||||
} else if (opt.fixed_group != undefined){
|
||||
options.group = opt.fixed_group;
|
||||
} else {
|
||||
var select_val = $("#showback_owner_select .resource_list_select", div).val();
|
||||
|
||||
switch ($("select#showback_owner", div).val()){
|
||||
case "showback_owner_all":
|
||||
break;
|
||||
|
||||
case "showback_owner_group":
|
||||
if(select_val != ""){
|
||||
options.group = select_val;
|
||||
}
|
||||
break;
|
||||
|
||||
case "showback_owner_user":
|
||||
if(select_val != ""){
|
||||
options.userfilter = select_val;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
OpenNebula.VM.showback({
|
||||
// timeout: true,
|
||||
success: function(req, response){
|
||||
fillShowback(div, req, response);
|
||||
},
|
||||
error: onError,
|
||||
data: options
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
function fillShowback(div, req, response) {
|
||||
$("#showback_no_data", div).hide();
|
||||
|
||||
if(response.SHOWBACK_RECORDS == undefined){
|
||||
$("#showback_placeholder", div).show();
|
||||
$("#showback_content", div).hide();
|
||||
|
||||
$("#showback_no_data", div).show();
|
||||
return false;
|
||||
}
|
||||
|
||||
var vms_per_date = {};
|
||||
$.each(response.SHOWBACK_RECORDS.SHOWBACK, function(index, showback){
|
||||
if (vms_per_date[showback.YEAR] == undefined) {
|
||||
vms_per_date[showback.YEAR] = {}
|
||||
}
|
||||
|
||||
if (vms_per_date[showback.YEAR][showback.MONTH] == undefined) {
|
||||
vms_per_date[showback.YEAR][showback.MONTH] = {
|
||||
"VMS": [],
|
||||
"TOTAL": 0
|
||||
}
|
||||
}
|
||||
|
||||
vms_per_date[showback.YEAR][showback.MONTH].VMS.push([showback.VMID, showback.VMNAME, showback.UNAME, showback.HOURS, showback.COST]);
|
||||
vms_per_date[showback.YEAR][showback.MONTH].TOTAL += parseFloat(showback.COST);
|
||||
});
|
||||
|
||||
var series = []
|
||||
var showback_data = [];
|
||||
$.each(vms_per_date, function(year, months){
|
||||
$.each(months, function(month, value){
|
||||
series.push([(new Date(year, month-1)).getTime(), year, month, $months[month-1] + " " + year, value.TOTAL.toFixed(2)])
|
||||
showback_data.push([(new Date(year, month-1)), value.TOTAL.toFixed(2) ])
|
||||
})
|
||||
})
|
||||
|
||||
showback_dataTable.fnClearTable();
|
||||
if (series.length > 0) {
|
||||
showback_dataTable.data("vms_per_date", vms_per_date)
|
||||
showback_dataTable.fnAddData(series);
|
||||
}
|
||||
|
||||
var showback_plot_series = [];
|
||||
showback_plot_series.push(
|
||||
{
|
||||
label: tr("Showback"),
|
||||
data: showback_data
|
||||
});
|
||||
|
||||
var options = {
|
||||
// colors: [ "#cdebf5", "#2ba6cb", "#6f6f6f" ]
|
||||
colors: [ "#2ba6cb", "#707D85", "#AC5A62" ],
|
||||
legend: {
|
||||
show: false
|
||||
},
|
||||
xaxis : {
|
||||
mode: "time",
|
||||
color: "#efefef",
|
||||
size: 8,
|
||||
minTickSize: [1, "month"]
|
||||
},
|
||||
yaxis : {
|
||||
show: false
|
||||
},
|
||||
series: {
|
||||
bars: {
|
||||
show: true,
|
||||
lineWidth: 0,
|
||||
barWidth: 24 * 60 * 60 * 1000 * 20,
|
||||
fill: true,
|
||||
align: "left"
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
borderWidth: 1,
|
||||
borderColor: "#efefef",
|
||||
hoverable: true
|
||||
}
|
||||
//tooltip: true,
|
||||
//tooltipOpts: {
|
||||
// content: "%x"
|
||||
//}
|
||||
};
|
||||
|
||||
var showback_plot = $.plot($("#showback_graph", div), showback_plot_series, options);
|
||||
|
||||
$("#showback_placeholder", div).hide();
|
||||
$("#showback_content", div).show();
|
||||
}
|
||||
|
||||
// div is a jQuery selector
|
||||
// The following options can be set:
|
||||
// fixed_user fix an owner user ID
|
||||
|
@ -446,6 +446,13 @@ get '/vm/accounting' do
|
||||
@SunstoneServer.get_vm_accounting(params)
|
||||
end
|
||||
|
||||
##############################################################################
|
||||
# Showback
|
||||
##############################################################################
|
||||
|
||||
get '/vm/showback' do
|
||||
@SunstoneServer.get_vm_showback(params)
|
||||
end
|
||||
|
||||
##############################################################################
|
||||
# Marketplace
|
||||
|
@ -15,7 +15,7 @@
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#include "Quota.h"
|
||||
#include <math.h>
|
||||
#include "NebulaUtil.h"
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
@ -79,7 +79,7 @@ void Quota::add_to_quota(VectorAttribute * attr, const string& va_name, float nu
|
||||
|
||||
total += num;
|
||||
|
||||
attr->replace(va_name, float_to_str(total));
|
||||
attr->replace(va_name, one_util::float_to_str(total));
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
@ -395,7 +395,7 @@ int Quota::update_limits(
|
||||
return -1;
|
||||
}
|
||||
|
||||
quota->replace(metrics[i], float_to_str(limit_f));
|
||||
quota->replace(metrics[i], one_util::float_to_str(limit_f));
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -431,7 +431,7 @@ VectorAttribute * Quota::new_quota(VectorAttribute * va)
|
||||
return 0;
|
||||
}
|
||||
|
||||
limits.insert(make_pair(metrics[i], float_to_str(limit_f)));
|
||||
limits.insert(make_pair(metrics[i], one_util::float_to_str(limit_f)));
|
||||
limits.insert(make_pair(metrics_used, "0"));
|
||||
}
|
||||
|
||||
@ -444,24 +444,3 @@ VectorAttribute * Quota::new_quota(VectorAttribute * va)
|
||||
|
||||
return new VectorAttribute(template_name,limits);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
string Quota::float_to_str(const float &num)
|
||||
{
|
||||
ostringstream oss;
|
||||
|
||||
if ( num == ceil(num) )
|
||||
{
|
||||
oss.precision(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
oss.precision(2);
|
||||
}
|
||||
|
||||
oss << fixed << num;
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
@ -115,6 +115,16 @@ const char * VirtualMachine::monit_db_bootstrap = "CREATE TABLE IF NOT EXISTS "
|
||||
"vm_monitoring (vmid INTEGER, last_poll INTEGER, body MEDIUMTEXT, "
|
||||
"PRIMARY KEY(vmid, last_poll))";
|
||||
|
||||
|
||||
const char * VirtualMachine::showback_table = "vm_showback";
|
||||
|
||||
const char * VirtualMachine::showback_db_names = "vmid, year, month, body";
|
||||
|
||||
const char * VirtualMachine::showback_db_bootstrap =
|
||||
"CREATE TABLE IF NOT EXISTS vm_showback "
|
||||
"(vmid INTEGER, year INTEGER, month INTEGER, body MEDIUMTEXT, "
|
||||
"PRIMARY KEY(vmid, year, month))";
|
||||
|
||||
const char * VirtualMachine::NO_NIC_DEFAULTS[] = {"NETWORK_ID", "NETWORK",
|
||||
"NETWORK_UID", "NETWORK_UNAME"};
|
||||
|
||||
@ -326,6 +336,32 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
|
||||
obj_template->add("VCPU", ivalue);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Check the cost attributes
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
if ( user_obj_template->get("CPU_COST", fvalue) == true )
|
||||
{
|
||||
if ( fvalue < 0 )
|
||||
{
|
||||
goto error_cpu_cost;
|
||||
}
|
||||
|
||||
user_obj_template->erase("CPU_COST");
|
||||
obj_template->add("CPU_COST", fvalue);
|
||||
}
|
||||
|
||||
if ( user_obj_template->get("MEMORY_COST", fvalue) == true )
|
||||
{
|
||||
if ( fvalue < 0 )
|
||||
{
|
||||
goto error_memory_cost;
|
||||
}
|
||||
|
||||
user_obj_template->erase("MEMORY_COST");
|
||||
obj_template->add("MEMORY_COST", fvalue);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Check the OS attribute
|
||||
// ------------------------------------------------------------------------
|
||||
@ -448,6 +484,14 @@ error_memory:
|
||||
error_str = "MEMORY attribute must be a positive integer value.";
|
||||
goto error_common;
|
||||
|
||||
error_cpu_cost:
|
||||
error_str = "CPU_COST attribute must be a positive float or integer value.";
|
||||
goto error_common;
|
||||
|
||||
error_memory_cost:
|
||||
error_str = "MEMORY_COST attribute must be a positive float or integer value.";
|
||||
goto error_common;
|
||||
|
||||
error_os:
|
||||
error_defaults:
|
||||
error_name:
|
||||
|
@ -354,6 +354,49 @@ int VirtualMachinePool::dump_acct(ostringstream& oss,
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
int VirtualMachinePool::dump_showback(ostringstream& oss,
|
||||
const string& where,
|
||||
int start_month,
|
||||
int start_year,
|
||||
int end_month,
|
||||
int end_year)
|
||||
{
|
||||
ostringstream cmd;
|
||||
|
||||
cmd << "SELECT " << VirtualMachine::showback_table << ".body FROM "
|
||||
<< VirtualMachine::showback_table
|
||||
<< " INNER JOIN " << VirtualMachine::table
|
||||
<< " WHERE vmid=oid";
|
||||
|
||||
if ( !where.empty() )
|
||||
{
|
||||
cmd << " AND " << where;
|
||||
}
|
||||
|
||||
if ( (start_month != -1 && start_year != -1) ||
|
||||
(end_month != -1 && end_year != -1) )
|
||||
{
|
||||
if (start_month != -1 && start_year != -1)
|
||||
{
|
||||
cmd << " AND (year > " << start_year <<
|
||||
" OR (year = " << start_year << " AND month >= " << start_month << ") )";
|
||||
}
|
||||
|
||||
if (end_month != -1 && end_year != -1)
|
||||
{
|
||||
cmd << " AND (year < " << end_year <<
|
||||
" OR (year = " << end_year << " AND month <= " << end_month << ") )";
|
||||
}
|
||||
}
|
||||
|
||||
cmd << " ORDER BY year,month,vmid";
|
||||
|
||||
return PoolSQL::dump(oss, "SHOWBACK_RECORDS", cmd);
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
int VirtualMachinePool::clean_expired_monitoring()
|
||||
{
|
||||
if ( _monitor_expiration == 0 )
|
||||
@ -413,3 +456,415 @@ int VirtualMachinePool::dump_monitoring(
|
||||
|
||||
return PoolSQL::dump(oss, "MONITORING_DATA", cmd);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
int VirtualMachinePool::min_stime_cb(void * _min_stime, int num, char **values, char **names)
|
||||
{
|
||||
if ( num == 0 || values == 0 || values[0] == 0 )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
*static_cast<int*>(_min_stime) = atoi(values[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#ifdef SBDEBUG
|
||||
static string put_time(tm tmp_tm)
|
||||
{
|
||||
ostringstream oss;
|
||||
|
||||
oss << tmp_tm.tm_mday << "/" << tmp_tm.tm_mon+1 << "/" << tmp_tm.tm_year+1900
|
||||
<< " " << tmp_tm.tm_hour << ":" << tmp_tm.tm_min << ":" << tmp_tm.tm_sec;
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
static string put_time(time_t t)
|
||||
{
|
||||
tm tmp_tm = *localtime(&t);
|
||||
return put_time(tmp_tm);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
int VirtualMachinePool::calculate_showback(
|
||||
int start_month,
|
||||
int start_year,
|
||||
int end_month,
|
||||
int end_year,
|
||||
string &error_str)
|
||||
{
|
||||
vector<xmlNodePtr> nodes;
|
||||
vector<xmlNodePtr>::iterator node_it;
|
||||
|
||||
vector<time_t> showback_slots;
|
||||
vector<time_t>::iterator slot_it;
|
||||
|
||||
// map<vid, map<month, pair<total_cost, n_hours> > >
|
||||
map<int, map<time_t, pair<float,float> > > vm_cost;
|
||||
map<int, map<time_t, pair<float, float> > >::iterator vm_it;
|
||||
map<time_t, pair<float,float> >::iterator vm_month_it;
|
||||
|
||||
VirtualMachine* vm;
|
||||
|
||||
int rc;
|
||||
ostringstream oss;
|
||||
ostringstream body;
|
||||
char * sql_body;
|
||||
|
||||
tm tmp_tm;
|
||||
int vid;
|
||||
int h_stime;
|
||||
int h_etime;
|
||||
float cpu_cost;
|
||||
float mem_cost;
|
||||
float cpu;
|
||||
int mem;
|
||||
|
||||
#ifdef SBDEBUG
|
||||
ostringstream debug;
|
||||
time_t debug_t_0 = time(0);
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Set start and end times for the window to process
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
tzset();
|
||||
|
||||
time_t start_time = time(0);
|
||||
time_t end_time = time(0);
|
||||
|
||||
if (start_month != -1 && start_year != -1)
|
||||
{
|
||||
// First day of the given month
|
||||
tmp_tm.tm_sec = 0;
|
||||
tmp_tm.tm_min = 0;
|
||||
tmp_tm.tm_hour = 0;
|
||||
tmp_tm.tm_mday = 1;
|
||||
tmp_tm.tm_mon = start_month - 1;
|
||||
tmp_tm.tm_year = start_year - 1900;
|
||||
tmp_tm.tm_isdst = -1;
|
||||
|
||||
start_time = mktime(&tmp_tm);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set start time to the lowest stime from the history records
|
||||
|
||||
set_callback(static_cast<Callbackable::Callback>(&VirtualMachinePool::min_stime_cb),
|
||||
static_cast<void *>(&start_time));
|
||||
|
||||
oss << "SELECT MIN(stime) FROM " << History::table;
|
||||
|
||||
rc = db->exec(oss, this);
|
||||
|
||||
unset_callback();
|
||||
}
|
||||
|
||||
if (end_month != -1 && end_year != -1)
|
||||
{
|
||||
// First day of the next month
|
||||
tmp_tm.tm_sec = 0;
|
||||
tmp_tm.tm_min = 0;
|
||||
tmp_tm.tm_hour = 0;
|
||||
tmp_tm.tm_mday = 1;
|
||||
tmp_tm.tm_mon = end_month;
|
||||
tmp_tm.tm_year = end_year - 1900;
|
||||
tmp_tm.tm_isdst = -1;
|
||||
|
||||
time_t end_time_tmp = mktime(&tmp_tm);
|
||||
|
||||
if (end_time_tmp < end_time)
|
||||
{
|
||||
end_time = end_time_tmp;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Get accounting history records
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
oss.str("");
|
||||
rc = dump_acct(oss, "", start_time, end_time);
|
||||
|
||||
ObjectXML xml(oss.str());
|
||||
|
||||
#ifdef SBDEBUG
|
||||
time_t debug_t_1 = time(0);
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Create the monthly time slots
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// Reset stime to 1st of month, 00:00
|
||||
localtime_r(&start_time, &tmp_tm);
|
||||
|
||||
tmp_tm.tm_sec = 0;
|
||||
tmp_tm.tm_min = 0;
|
||||
tmp_tm.tm_hour = 0;
|
||||
tmp_tm.tm_mday = 1;
|
||||
tmp_tm.tm_isdst = -1;
|
||||
|
||||
time_t tmp_t = mktime(&tmp_tm);
|
||||
|
||||
while(tmp_t < end_time)
|
||||
{
|
||||
showback_slots.push_back(tmp_t);
|
||||
|
||||
tmp_tm.tm_sec = 0;
|
||||
tmp_tm.tm_min = 0;
|
||||
tmp_tm.tm_hour = 0;
|
||||
tmp_tm.tm_mday = 1;
|
||||
tmp_tm.tm_mon++;
|
||||
tmp_tm.tm_isdst = -1;
|
||||
|
||||
tmp_t = mktime(&tmp_tm);
|
||||
}
|
||||
|
||||
// Extra slot that won't be used. Is needed only to calculate the time
|
||||
// for the second-to-last slot
|
||||
showback_slots.push_back(end_time);
|
||||
|
||||
#ifdef SBDDEBUG
|
||||
for ( slot_it = showback_slots.begin(); slot_it != showback_slots.end(); slot_it++ )
|
||||
{
|
||||
debug.str("");
|
||||
debug << "Slot: " << put_time(*slot_it);
|
||||
NebulaLog::log("SHOWBACK", Log::DEBUG, debug);
|
||||
}
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Process the history records
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
rc = xml.get_nodes("/HISTORY_RECORDS/HISTORY", nodes);
|
||||
|
||||
for ( node_it = nodes.begin(); node_it != nodes.end(); node_it++ )
|
||||
{
|
||||
ObjectXML history(*node_it);
|
||||
|
||||
history.xpath(vid, "/HISTORY/OID", -1);
|
||||
|
||||
history.xpath(h_stime, "/HISTORY/STIME", 0);
|
||||
history.xpath(h_etime, "/HISTORY/ETIME", 0);
|
||||
|
||||
history.xpath(cpu, "/HISTORY/VM/TEMPLATE/CPU", 0);
|
||||
history.xpath(mem, "/HISTORY/VM/TEMPLATE/MEMORY", 0);
|
||||
|
||||
history.xpath(cpu_cost, "/HISTORY/VM/TEMPLATE/CPU_COST", 0);
|
||||
history.xpath(mem_cost, "/HISTORY/VM/TEMPLATE/MEMORY_COST", 0);
|
||||
|
||||
#ifdef SBDDEBUG
|
||||
int seq;
|
||||
history.xpath(seq, "/HISTORY/SEQ", -1);
|
||||
|
||||
debug.str("");
|
||||
debug << "VM " << vid << " SEQ " << seq << endl
|
||||
<< "h_stime " << h_stime << endl
|
||||
<< "h_etime " << h_etime << endl
|
||||
<< "cpu_cost " << cpu_cost << endl
|
||||
<< "mem_cost " << mem_cost << endl
|
||||
<< "cpu " << cpu << endl
|
||||
<< "mem " << mem;
|
||||
|
||||
NebulaLog::log("SHOWBACK", Log::DEBUG, debug);
|
||||
#endif
|
||||
|
||||
for ( slot_it = showback_slots.begin(); slot_it != showback_slots.end()-1; slot_it++ )
|
||||
{
|
||||
time_t t = *slot_it;
|
||||
time_t t_next = *(slot_it+1);
|
||||
|
||||
if( (h_etime > t || h_etime == 0) &&
|
||||
(h_stime != 0 && h_stime <= t_next) ) {
|
||||
|
||||
time_t stime = t;
|
||||
if(h_stime != 0){
|
||||
stime = (t < h_stime) ? h_stime : t; //max(t, h_stime);
|
||||
}
|
||||
|
||||
time_t etime = t_next;
|
||||
if(h_etime != 0){
|
||||
etime = (t_next < h_etime) ? t_next : h_etime; //min(t_next, h_etime);
|
||||
}
|
||||
|
||||
float n_hours = difftime(etime, stime) / 60 / 60;
|
||||
|
||||
float cost = 0;
|
||||
|
||||
cost += cpu_cost * cpu * n_hours;
|
||||
cost += mem_cost * mem * n_hours;
|
||||
|
||||
// Add to vm time slot.
|
||||
map<time_t, pair<float,float> >& totals = vm_cost[vid];
|
||||
|
||||
if(totals.count(t) == 0)
|
||||
{
|
||||
totals[t] = make_pair(0,0);
|
||||
}
|
||||
|
||||
totals[t].first += cost;
|
||||
totals[t].second += n_hours;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xml.free_nodes(nodes);
|
||||
|
||||
#ifdef SBDEBUG
|
||||
time_t debug_t_2 = time(0);
|
||||
#endif
|
||||
|
||||
// Write to DB
|
||||
|
||||
oss.str("");
|
||||
oss << "REPLACE INTO " << VirtualMachine::showback_table
|
||||
<< " ("<< VirtualMachine::showback_db_names <<") VALUES ";
|
||||
|
||||
int n_entries = 0;
|
||||
|
||||
for ( vm_it = vm_cost.begin(); vm_it != vm_cost.end(); vm_it++ )
|
||||
{
|
||||
map<time_t, pair<float,float> >& totals = vm_it->second;
|
||||
|
||||
for ( vm_month_it = totals.begin(); vm_month_it != totals.end(); vm_month_it++ )
|
||||
{
|
||||
int vmid = vm_it->first;
|
||||
|
||||
vm = get(vmid, true);
|
||||
|
||||
int uid = 0;
|
||||
int gid = 0;
|
||||
string uname = "";
|
||||
string gname = "";
|
||||
string vmname = "";
|
||||
|
||||
if (vm != 0)
|
||||
{
|
||||
uid = vm->get_uid();
|
||||
gid = vm->get_gid();
|
||||
|
||||
uname = vm->get_uname();
|
||||
gname = vm->get_gname();
|
||||
|
||||
vmname = vm->get_name();
|
||||
|
||||
vm->unlock();
|
||||
}
|
||||
|
||||
localtime_r(&vm_month_it->first, &tmp_tm);
|
||||
|
||||
body.str("");
|
||||
|
||||
string cost = one_util::float_to_str(vm_month_it->second.first);
|
||||
string hours = one_util::float_to_str(vm_month_it->second.second);
|
||||
|
||||
body << "<SHOWBACK>"
|
||||
<< "<VMID>" << vmid << "</VMID>"
|
||||
<< "<VMNAME>" << vmname << "</VMNAME>"
|
||||
<< "<UID>" << uid << "</UID>"
|
||||
<< "<GID>" << gid << "</GID>"
|
||||
<< "<UNAME>" << uname << "</UNAME>"
|
||||
<< "<GNAME>" << gname << "</GNAME>"
|
||||
<< "<YEAR>" << tmp_tm.tm_year + 1900 << "</YEAR>"
|
||||
<< "<MONTH>" << tmp_tm.tm_mon + 1 << "</MONTH>"
|
||||
<< "<COST>" << cost << "</COST>"
|
||||
<< "<HOURS>" << hours << "</HOURS>"
|
||||
<< "</SHOWBACK>";
|
||||
|
||||
sql_body = db->escape_str(body.str().c_str());
|
||||
|
||||
if ( sql_body == 0 )
|
||||
{
|
||||
error_str = "Error creating XML body.";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (n_entries == 0)
|
||||
{
|
||||
oss.str("");
|
||||
oss << "REPLACE INTO " << VirtualMachine::showback_table
|
||||
<< " ("<< VirtualMachine::showback_db_names <<") VALUES ";
|
||||
}
|
||||
else
|
||||
{
|
||||
oss << ",";
|
||||
}
|
||||
|
||||
oss << " (" << vm_it->first << ","
|
||||
<< tmp_tm.tm_year + 1900 << ","
|
||||
<< tmp_tm.tm_mon + 1 << ","
|
||||
<< "'" << sql_body << "')";
|
||||
|
||||
db->free_str(sql_body);
|
||||
|
||||
n_entries++;
|
||||
|
||||
// To avoid the oss to grow indefinitely, flush contents
|
||||
if (n_entries == 1000)
|
||||
{
|
||||
rc = db->exec(oss);
|
||||
|
||||
if (rc != 0)
|
||||
{
|
||||
error_str = "Error writing to DB.";
|
||||
return -1;
|
||||
}
|
||||
|
||||
n_entries = 0;
|
||||
}
|
||||
|
||||
#ifdef SBDDEBUG
|
||||
debug.str("");
|
||||
|
||||
debug << "VM " << vm_it->first
|
||||
<< " cost for Y " << tmp_tm.tm_year + 1900
|
||||
<< " M " << tmp_tm.tm_mon + 1
|
||||
<< " COST " << cost << " €"
|
||||
<< " HOURS " << hours;
|
||||
|
||||
NebulaLog::log("SHOWBACK", Log::DEBUG, debug);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (n_entries > 0)
|
||||
{
|
||||
rc = db->exec(oss);
|
||||
|
||||
if (rc != 0)
|
||||
{
|
||||
error_str = "Error writing to DB.";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SBDEBUG
|
||||
time_t debug_t_3 = time(0);
|
||||
|
||||
debug.str("");
|
||||
debug << "Time to dump acct to mem: " << debug_t_1 - debug_t_0;
|
||||
NebulaLog::log("SHOWBACK", Log::DEBUG, debug);
|
||||
|
||||
debug.str("");
|
||||
debug << "Time to process numbers: " << debug_t_2 - debug_t_1;
|
||||
NebulaLog::log("SHOWBACK", Log::DEBUG, debug);
|
||||
|
||||
debug.str("");
|
||||
debug << "Time to write to db: " << debug_t_3 - debug_t_2;
|
||||
NebulaLog::log("SHOWBACK", Log::DEBUG, debug);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -188,6 +188,39 @@ int ObjectXML::xpath(int& value, const char * xpath_expr, const int& def)
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
int ObjectXML::xpath(float& value, const char * xpath_expr, const float& def)
|
||||
{
|
||||
vector<string> values;
|
||||
int rc = 0;
|
||||
|
||||
values = (*this)[xpath_expr];
|
||||
|
||||
if (values.empty() == true)
|
||||
{
|
||||
value = def;
|
||||
rc = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
istringstream iss;
|
||||
|
||||
iss.str(values[0]);
|
||||
|
||||
iss >> dec >> value;
|
||||
|
||||
if (iss.fail() == true)
|
||||
{
|
||||
value = def;
|
||||
rc = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
int ObjectXML::xpath(unsigned int& value, const char * xpath_expr,
|
||||
const unsigned int& def)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user