diff --git a/src/cli/one_helper/oneacct_helper.rb b/src/cli/one_helper/oneacct_helper.rb index 55187c696d..4b102cde37 100644 --- a/src/cli/one_helper/oneacct_helper.rb +++ b/src/cli/one_helper/oneacct_helper.rb @@ -96,8 +96,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, END_TIME, USERFILTER, GROUP, HOST, XPATH, XML, JSON, SPLIT] + SHOWBACK_OPTIONS = [START_TIME, END_TIME, USERFILTER, GROUP, XML, JSON] ACCT_TABLE = CLIHelper::ShowTable.new("oneacct.yaml", nil) do column :UID, "User ID", :size=>4 do |d| @@ -153,6 +153,51 @@ class AcctHelper < OpenNebulaHelper::OneHelper default :VID, :HOSTNAME, :ACTION, :REASON, :START_TIME, :END_TIME, :MEMORY, :CPU, :NET_RX, :NET_TX end + # TODO: oneacct.yaml + SHOWBACK_TABLE = CLIHelper::ShowTable.new("nofile.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=>5 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 " @@ -185,4 +230,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 diff --git a/src/cli/oneacct b/src/cli/oneacct index f5774506af..fb0f4be52d 100755 --- a/src/cli/oneacct +++ b/src/cli/oneacct @@ -43,11 +43,11 @@ cmd = CommandParser::CmdParser.new(ARGV) do helper.set_client(options) end - option AcctHelper::ACCT_OPTIONS + CommandParser::OPTIONS + + command :acct, "Returns the accounting records", :options => + AcctHelper::ACCT_OPTIONS + CommandParser::OPTIONS + [OpenNebulaHelper::DESCRIBE, CLIHelper::LIST, CLIHelper::CSV_OPT] + - OpenNebulaHelper::CLIENT_OPTIONS + OpenNebulaHelper::CLIENT_OPTIONS do - main do if options[:describe] AcctHelper::ACCT_TABLE.describe_columns exit(0) @@ -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 @@ -140,4 +140,94 @@ cmd = CommandParser::CmdParser.new(ARGV) do exit_code 0 end end + + command :showback, "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_time = options[:start_time] ? options[:start_time].to_i : -1 + end_time = options[:end_time] ? options[:end_time].to_i : -1 + + common_opts = { + :start_time => start_time, + :end_time => end_time, + :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 + order_by[:order_by_1] = 'YEAR' + order_by[:order_by_2] = 'MONTH' + + 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 + data_hash.each do |user_id, value| + value['SHOWBACK_RECORDS']['SHOWBACK'].each do |l| + l['UID']=user_id + a << l + end + end + + cols = AcctHelper::SHOWBACK_TABLE.default_columns + AcctHelper::SHOWBACK_TABLE.default(:UID, *cols) + + AcctHelper::SHOWBACK_TABLE.show(a, options) + exit(0) + end + + if ( start_time != -1 or end_time != -1 ) + AcctHelper.print_start_end_time_header(start_time, end_time) + 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 end \ No newline at end of file diff --git a/src/oca/ruby/opennebula/virtual_machine_pool.rb b/src/oca/ruby/opennebula/virtual_machine_pool.rb index 38867c0eab..19e7e62354 100644 --- a/src/oca/ruby/opennebula/virtual_machine_pool.rb +++ b/src/oca/ruby/opennebula/virtual_machine_pool.rb @@ -164,28 +164,6 @@ module OpenNebula return @client.call(VM_POOL_METHODS[:monitoring], filter_flag) 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_time Start date and time to take into account, - # if no start_time is required use -1 - # @option params [Integer] :end_time End date and time to take into account, - # if no end_time is required use -1 - def showback_xml(filter_flag=INFO_ALL, options={}) - - filter_flag ||= INFO_ALL - options[:start_time] ||= -1 - options[:end_time] ||= -1 - - return @client.call(VM_POOL_METHODS[:showback], - filter_flag, - options[:start_time], - options[:end_time]) - end - # Processes all the history records, and stores the monthly cost for # each VM # @@ -324,6 +302,84 @@ 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_time Start date and time to take into account, + # if no start_time is required use -1 + # @option params [Integer] :end_time End date and time 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_time Start date and time to take into account, + # if no start_time is required use -1 + # @option params [Integer] :end_time End date and time 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 = "\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" + xml_str + end + private def build_accounting(filter_flag, options, &block) @@ -357,6 +413,36 @@ module OpenNebula acct_hash end + def build_showback(filter_flag, options, &block) + xml_str = @client.call(VM_POOL_METHODS[:showback], + filter_flag, + options[:start_time], + options[:end_time]) + + 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