diff --git a/src/acct/accounting.rb b/src/acct/accounting.rb
new file mode 100644
index 0000000000..b8f3e3e9df
--- /dev/null
+++ b/src/acct/accounting.rb
@@ -0,0 +1,112 @@
+module OneWatch
+ require 'watch_helper'
+
+ class Accounting
+ def initialize(client)
+ @client = client
+ @active_vms = Array.new
+ end
+
+ def insert(hash)
+ @ptimestamp = @timestamp
+ @timestamp = generate_timestamp
+
+ new_active_vms = Array.new
+ last_active_vm = @active_vms.empty? ? -1 : @active_vms.last
+
+ if (vmpool_hash = hash['VM_POOL']) && !vmpool_hash.empty?
+ [vmpool_hash['VM']].flatten.each { |vm|
+ vm_id = vm['ID'].to_i
+
+ if vm['STATE'] == 3
+ new_active_vms << vm_id
+ end
+
+ # ACTIVE VMs (including those that are stopped in this step)
+ # in the last step and NEW VMs
+ if @active_vms.include?(vm_id) || vm['STATE'].to_i == 3
+ insert_vm(vm)
+ @active_vms.delete(vm_id)
+ else
+ # DONE/STOP VMs and non ACTIVE in the last step
+ next
+ end
+ }
+ end
+
+ # DONE VMs that were ACTIVE in the last step
+ @active_vms.each { |id|
+ vm = OpenNebula::VirtualMachine.new_with_id(id, @client)
+ vm.info
+
+ vm_hash = vm.to_hash
+ insert_vm(vm_hash)
+ }
+
+ # DONE VMs that did not exist in the last step
+ vmpool = OpenNebula::VirtualMachinePool.new(@client)
+ vmpool.info(-2, last_active_vm, -1, 6)
+ done_hash = vmpool.to_hash
+ if (done_vm_hash = done_hash['VM_POOL']) && !done_vm_hash.empty?
+ [done_vm_hash['VM']].flatten.each { |vm|
+ insert_vm(vm)
+ }
+ end
+
+ # Upate the active VMs
+ @active_vms = new_active_vms.sort
+ end
+
+ private
+
+ def generate_timestamp
+ Time.now.to_i
+ end
+
+ def insert_register(vm, register, history)
+ if register && register.seq == history['SEQ'].to_i
+ register.update_from_history(history)
+ else
+ reg = WatchHelper::Register.create_from_history(history)
+ vm.add_register(reg)
+ end
+ end
+
+ def update_history(vm, vm_sql)
+ last_register = vm_sql.registers.last
+ seq = last_register ? last_register.seq : 0
+
+ if hr = vm['HISTORY_RECORDS']
+ unless hr['HISTORY'].instance_of?(Array)
+ if hr['HISTORY']['SEQ'] == seq
+ # The VM has not moved from the Host
+ insert_register(vm_sql, last_register, hr['HISTORY'])
+ return
+ else
+ # Get the full HISTORY
+ vm = OpenNebula::VirtualMachine.new_with_id(vm['ID'], @client)
+ vm.info
+
+ vm_hash = vm.to_hash['VM']
+ hr = vm_hash['HISTORY_RECORDS']
+
+ # Insert a new entry for each new history record
+ [hr['HISTORY']].flatten.each { |history|
+ if history['SEQ'].to_i < seq
+ next
+ else
+ insert_register(vm_sql, last_register, history)
+ end
+ }
+ end
+ end
+ end
+ end
+
+ def insert_vm(vm)
+ vm_sql = WatchHelper::Vm.info(vm)
+ update_history(vm, vm_sql)
+ end
+ end
+end
+
diff --git a/src/acct/examples/acct_client.rb b/src/acct/examples/acct_client.rb
new file mode 100644
index 0000000000..565f3de816
--- /dev/null
+++ b/src/acct/examples/acct_client.rb
@@ -0,0 +1,75 @@
+require 'watch_helper'
+
+class AcctClient
+ def prolog_time(t1, t2, opts={})
+ times(t1, t2, opts) { |reg|
+ calculate_time(t1, t2, reg.pstime, reg.petime)
+ }
+ end
+
+ def running_time(t1, t2, opts={})
+ # TBD Suspened VMs
+
+ times(t1, t2, opts) { |reg|
+ calculate_time(t1, t2, reg.rstime, reg.retime)
+ }
+ end
+
+ def epilog_time(t1, t2, opts={})
+ times(t1, t2, opts) { |reg|
+ calculate_time(t1, t2, reg.estime, reg.eetime)
+ }
+ end
+
+ private
+
+ def times(t1, t2, opts={}, &block)
+ time = 0
+
+ vms = filter_vms(opts)
+
+ if vms && !vms.empty?
+ vms.each { |vm|
+ vm.registers.each { |reg|
+ time += block.call(reg)
+ }
+ }
+ end
+
+ time
+ end
+
+ def calculate_time(t1, t2, stime, etime)
+ if etime < t1 && etime != 0
+ return 0
+ elsif stime < t2 && stime != 0
+ if etime < t2 && etime != 0
+ e = etime
+ else
+ e = t2
+ end
+
+ s = stime > t1 ? stime : t1
+ return e - s
+ end
+
+ return 0
+ end
+
+ def filter_vms(opts={})
+ opts ||= {}
+
+ if opts[:uid]
+ vms = WatchHelper::Vm.filter(:uid=>opts[:uid])
+ elsif opts[:gid]
+ vms = WatchHelper::Vm.filter(:gid=>opts[:gid])
+ elsif opts[:hid]
+ vms = WatchHelper::Vm.filter(
+ :registers=>WatchHelper::Register.filter(:hid => opts[:hid]))
+ elsif opts[:vmid]
+ vms = WatchHelper::Vm.filter(:id=>opts[:vmid])
+ else
+ vms = WatchHelper::Vm
+ end
+ end
+end
diff --git a/src/acct/monitoring.rb b/src/acct/monitoring.rb
new file mode 100644
index 0000000000..673335e92c
--- /dev/null
+++ b/src/acct/monitoring.rb
@@ -0,0 +1,42 @@
+module OneWatch
+ require 'watch_helper'
+
+ class Monitoring
+ def insert(hash)
+ timestamp = generate_timestamp
+
+ if (pool_hash = hash["#{resource}_POOL"]) && !pool_hash.empty?
+ [pool_hash["#{resource}"]].flatten.each { |elem|
+ sql = sql_elem(elem)
+ sql.add_share(elem, timestamp)
+ }
+ end
+ end
+
+ private
+
+ def generate_timestamp
+ Time.now.to_i
+ end
+ end
+
+ class VmMonitoring < Monitoring
+ def resource
+ 'VM'
+ end
+
+ def sql_elem(elem)
+ WatchHelper::Vm.info(elem)
+ end
+ end
+
+ class HostMonitoring < Monitoring
+ def resource
+ 'HOST'
+ end
+
+ def sql_elem(elem)
+ WatchHelper::Host.info(elem)
+ end
+ end
+end
\ No newline at end of file
diff --git a/src/acct/test/1Vm1His.rb b/src/acct/test/1Vm1His.rb
new file mode 100644
index 0000000000..e1af738d60
--- /dev/null
+++ b/src/acct/test/1Vm1His.rb
@@ -0,0 +1,333 @@
+require 'helper/test_helper.rb'
+
+describe "1 Vm 1 History" do
+ before(:each) do
+ clean_db
+
+ @mock_client = MockClient.new
+ @accounting = OneWatch::Accounting.new(@mock_client)
+
+ @watch_client = AcctClient.new
+
+ @db = WatchHelper::DB
+ check_lines(0,0)
+ end
+
+ it "Prolog testing" do
+ ts1 = 100
+ @accounting.set_mock_timestamp(ts1)
+
+ @accounting.insert(create_vmpool_hash)
+ check_lines(0,0)
+
+ ts2 = 200
+ @accounting.set_mock_timestamp(ts2)
+
+ values = {
+ :uid => 2,
+ :gid => 4,
+ :history => [
+ :hid => 7,
+ :pstime => 150,
+ :petime => 0,
+ :rstime => 0,
+ :retime => 0,
+ :estime => 0,
+ :eetime => 0,
+ :reason => 0
+ ]
+ }
+
+ @mock_client.add_vm(1, values)
+
+ @accounting.insert(create_vmpool_hash)
+ check_lines(1,1)
+
+ history = values[:history].first
+ sum = ts2 - history[:pstime]
+
+ warn "* T1 PSTIME T2"
+ @watch_client.prolog_time(ts1, ts2).to_i.should eql(sum)
+ warn " - By User"
+ @watch_client.prolog_time(ts1, ts2, :uid => 2).to_i.should eql(sum)
+ warn " - By Host"
+ @watch_client.prolog_time(ts1, ts2, :hid => 7).to_i.should eql(sum)
+ warn " - By Vm"
+ @watch_client.prolog_time(ts1, ts2, :vmid => 1).to_i.should eql(sum)
+
+ warn " - Non existent User"
+ @watch_client.prolog_time(ts1, ts2, :uid => 555).to_i.should eql(0)
+ warn " - Non existent Host"
+ @watch_client.prolog_time(ts1, ts2, :hid => 555).to_i.should eql(0)
+ warn " - Non existent Vm"
+ @watch_client.prolog_time(ts1, ts2, :vmid => 555).to_i.should eql(0)
+
+ warn "* PSTIME T1 T2"
+ @watch_client.prolog_time(160, ts2).to_i.should eql(sum-10)
+ warn "* T1 PSTIME T2-10"
+ @watch_client.prolog_time(ts1, ts2-10).to_i.should eql(sum-10)
+ warn "* T1 T2 PSTIME"
+ @watch_client.prolog_time(110, 130).to_i.should eql(0)
+
+ warn "* Non Epilog time"
+ @watch_client.epilog_time(ts1, ts2).to_i.should eql(0)
+ warn "* Non Running time"
+ @watch_client.running_time(ts1, ts2).to_i.should eql(0)
+
+ ts3 = 300
+ @accounting.set_mock_timestamp(ts2)
+
+ values = {
+ :uid => 2,
+ :gid => 4,
+ :history => [
+ :hid => 7,
+ :pstime => 150,
+ :petime => 240,
+ :rstime => 0,
+ :retime => 0,
+ :estime => 0,
+ :eetime => 0,
+ :reason => 0
+ ]
+ }
+
+ @mock_client.add_vm(1, values)
+
+ @accounting.insert(create_vmpool_hash)
+ check_lines(1,1)
+
+ history = values[:history].first
+ sum = history[:petime] - history[:pstime]
+
+ warn "* T1 PSTIME PETIME T3"
+ @watch_client.prolog_time(ts1, ts3).to_i.should eql(sum)
+ warn " - By User"
+ @watch_client.prolog_time(ts1, ts3, :uid => 2).to_i.should eql(sum)
+ warn " - By Host"
+ @watch_client.prolog_time(ts1, ts3, :hid => 7).to_i.should eql(sum)
+ warn " - By Vm"
+ @watch_client.prolog_time(ts1, ts3, :vmid => 1).to_i.should eql(sum)
+
+ warn "* T1 PSTIME T3 PETIME"
+ @watch_client.prolog_time(ts1, 230).to_i.should eql(230 - history[:pstime])
+
+ warn "* PSTIME T1 PETIME T3"
+ @watch_client.prolog_time(160, ts3).to_i.should eql(history[:petime] - 160)
+
+ warn "* PSTIME T1 T3 PETIME"
+ @watch_client.prolog_time(160, 230).to_i.should eql(230 - 160)
+ end
+
+ it "Running testing" do
+ ts1 = 100
+ @accounting.set_mock_timestamp(ts1)
+
+ @accounting.insert(create_vmpool_hash)
+ check_lines(0,0)
+
+ ts2 = 200
+ @accounting.set_mock_timestamp(ts2)
+
+ values = {
+ :uid => 2,
+ :gid => 4,
+ :history => [
+ :hid => 7,
+ :pstime => 150,
+ :petime => 155,
+ :rstime => 155,
+ :retime => 0,
+ :estime => 0,
+ :eetime => 0,
+ :reason => 0
+ ]
+ }
+
+ @mock_client.add_vm(1, values)
+
+ @accounting.insert(create_vmpool_hash)
+ check_lines(1,1)
+
+ history = values[:history].first
+ sum = ts2 - history[:rstime]
+
+ warn "* T1 RSTIME T2"
+ @watch_client.running_time(ts1, ts2).to_i.should eql(sum)
+ warn " - By User"
+ @watch_client.running_time(ts1, ts2, :uid => 2).to_i.should eql(sum)
+ warn " - By Host"
+ @watch_client.running_time(ts1, ts2, :hid => 7).to_i.should eql(sum)
+ warn " - By Vm"
+ @watch_client.running_time(ts1, ts2, :vmid => 1).to_i.should eql(sum)
+
+ warn " - Non existent User"
+ @watch_client.running_time(ts1, ts2, :uid => 555).to_i.should eql(0)
+ warn " - Non existent Host"
+ @watch_client.running_time(ts1, ts2, :hid => 555).to_i.should eql(0)
+ warn " - Non existent Vm"
+ @watch_client.running_time(ts1, ts2, :vmid => 555).to_i.should eql(0)
+
+ warn "* RSTIME T1 T2"
+ @watch_client.running_time(160, ts2).to_i.should eql(ts2-160)
+ warn "* T1 RSTIME T2-10"
+ @watch_client.running_time(ts1, ts2-10).to_i.should eql(sum-10)
+ warn "* T1 T2 RSTIME"
+ @watch_client.running_time(110, 130).to_i.should eql(0)
+
+ warn "* Non Epilog time"
+ @watch_client.epilog_time(ts1, ts2).to_i.should eql(0)
+ warn "* Non Prolog time"
+ @watch_client.prolog_time(ts1, ts2).to_i.should eql(5)
+
+ ts3 = 300
+ @accounting.set_mock_timestamp(ts2)
+
+ values = {
+ :uid => 2,
+ :gid => 4,
+ :history => [
+ :hid => 7,
+ :pstime => 150,
+ :petime => 155,
+ :rstime => 155,
+ :retime => 230,
+ :estime => 0,
+ :eetime => 0,
+ :reason => 0
+ ]
+ }
+
+ @mock_client.add_vm(1, values)
+
+ @accounting.insert(create_vmpool_hash)
+ check_lines(1,1)
+
+ history = values[:history].first
+ sum = history[:retime] - history[:rstime]
+
+ warn "* T1 PSTIME PETIME T3"
+ @watch_client.running_time(ts1, ts3).to_i.should eql(sum)
+ warn " - By User"
+ @watch_client.running_time(ts1, ts3, :uid => 2).to_i.should eql(sum)
+ warn " - By Host"
+ @watch_client.running_time(ts1, ts3, :hid => 7).to_i.should eql(sum)
+ warn " - By Vm"
+ @watch_client.running_time(ts1, ts3, :vmid => 1).to_i.should eql(sum)
+
+ warn "* T1 PSTIME T3 PETIME"
+ @watch_client.running_time(ts1, 230).to_i.should eql(230 - history[:rstime])
+
+ warn "* PSTIME T1 PETIME T3"
+ @watch_client.running_time(160, ts3).to_i.should eql(history[:retime] - 160)
+
+ warn "* PSTIME T1 T3 PETIME"
+ @watch_client.running_time(160, 230).to_i.should eql(230 - 160)
+ end
+
+ it "Epilog testing" do
+ ts1 = 100
+ @accounting.set_mock_timestamp(ts1)
+
+ @accounting.insert(create_vmpool_hash)
+ check_lines(0,0)
+
+ ts2 = 200
+ @accounting.set_mock_timestamp(ts2)
+
+ values = {
+ :uid => 2,
+ :gid => 4,
+ :history => [
+ :hid => 7,
+ :pstime => 150,
+ :petime => 155,
+ :rstime => 155,
+ :retime => 170,
+ :estime => 180,
+ :eetime => 0,
+ :reason => 0
+ ]
+ }
+
+ @mock_client.add_vm(1, values)
+
+ @accounting.insert(create_vmpool_hash)
+ check_lines(1,1)
+
+ history = values[:history].first
+ sum = ts2 - history[:estime]
+
+ warn "* T1 ESTIME T2"
+ @watch_client.epilog_time(ts1, ts2).to_i.should eql(sum)
+ warn " - By User"
+ @watch_client.epilog_time(ts1, ts2, :uid => 2).to_i.should eql(sum)
+ warn " - By Host"
+ @watch_client.epilog_time(ts1, ts2, :hid => 7).to_i.should eql(sum)
+ warn " - By Vm"
+ @watch_client.epilog_time(ts1, ts2, :vmid => 1).to_i.should eql(sum)
+
+ warn " - Non existent User"
+ @watch_client.epilog_time(ts1, ts2, :uid => 555).to_i.should eql(0)
+ warn " - Non existent Host"
+ @watch_client.epilog_time(ts1, ts2, :hid => 555).to_i.should eql(0)
+ warn " - Non existent Vm"
+ @watch_client.epilog_time(ts1, ts2, :vmid => 555).to_i.should eql(0)
+
+ warn "* ESTIME T1 T2"
+ @watch_client.epilog_time(190, ts2).to_i.should eql(ts2-190)
+ warn "* T1 ESTIME T2-10"
+ @watch_client.epilog_time(ts1, ts2-10).to_i.should eql(sum-10)
+ warn "* T1 T2 ESTIME"
+ @watch_client.epilog_time(110, 130).to_i.should eql(0)
+
+ warn "* Non Running time"
+ @watch_client.running_time(ts1, ts2).to_i.should eql(15)
+ warn "* Non Prolog time"
+ @watch_client.prolog_time(ts1, ts2).to_i.should eql(5)
+
+ ts3 = 300
+ @accounting.set_mock_timestamp(ts2)
+
+ values = {
+ :uid => 2,
+ :gid => 4,
+ :history => [
+ :hid => 7,
+ :pstime => 150,
+ :petime => 155,
+ :rstime => 155,
+ :retime => 170,
+ :estime => 180,
+ :eetime => 230,
+ :reason => 0
+ ]
+ }
+
+ @mock_client.add_vm(1, values)
+
+ @accounting.insert(create_vmpool_hash)
+ check_lines(1,1)
+
+ history = values[:history].first
+ sum = history[:eetime] - history[:estime]
+
+ warn "* T1 PSTIME PETIME T3"
+ @watch_client.epilog_time(ts1, ts3).to_i.should eql(sum)
+ warn " - By User"
+ @watch_client.epilog_time(ts1, ts3, :uid => 2).to_i.should eql(sum)
+ warn " - By Host"
+ @watch_client.epilog_time(ts1, ts3, :hid => 7).to_i.should eql(sum)
+ warn " - By Vm"
+ @watch_client.epilog_time(ts1, ts3, :vmid => 1).to_i.should eql(sum)
+
+ warn "* T1 PSTIME T3 PETIME"
+ @watch_client.epilog_time(ts1, 230).to_i.should eql(230 - history[:estime])
+
+ warn "* PSTIME T1 PETIME T3"
+ @watch_client.epilog_time(190, ts3).to_i.should eql(history[:eetime] - 190)
+
+ warn "* PSTIME T1 T3 PETIME"
+ @watch_client.epilog_time(190, 220).to_i.should eql(220 - 190)
+ end
+end
\ No newline at end of file
diff --git a/src/acct/test/1VmXHis.rb b/src/acct/test/1VmXHis.rb
new file mode 100644
index 0000000000..13b1549dcc
--- /dev/null
+++ b/src/acct/test/1VmXHis.rb
@@ -0,0 +1,99 @@
+require 'helper/test_helper.rb'
+
+describe "1 Vm X History" do
+ before(:each) do
+ clean_db
+
+ @mock_client = MockClient.new
+ @accounting = OneWatch::Accounting.new(@mock_client)
+
+ @watch_client = AcctClient.new
+
+ @db = WatchHelper::DB
+ check_lines(0,0)
+ end
+
+ it "Running testing" do
+ ts1 = 100
+ @accounting.set_mock_timestamp(ts1)
+
+ @accounting.insert(create_vmpool_hash)
+ check_lines(0,0)
+
+ ts2 = 200
+ @accounting.set_mock_timestamp(ts2)
+
+ values = {
+ :uid => 2,
+ :gid => 4,
+ :history => [
+ :hid => 7,
+ :seq => 0,
+ :pstime => 150,
+ :petime => 155,
+ :rstime => 155,
+ :retime => 0,
+ :estime => 0,
+ :eetime => 0,
+ :reason => 0
+ ]
+ }
+
+ @mock_client.add_vm(1, values)
+
+ @accounting.insert(create_vmpool_hash)
+ check_lines(1,1)
+
+ history = values[:history].first
+ sum = ts2 - history[:rstime]
+
+ warn "* T1 RSTIME T2"
+ @watch_client.running_time(ts1, ts2).to_i.should eql(sum)
+
+ ts3 = 300
+ @accounting.set_mock_timestamp(ts2)
+
+ values = {
+ :uid => 2,
+ :gid => 4,
+ :history => [
+ {
+ :hid => 7,
+ :seq => 0,
+ :pstime => 150,
+ :petime => 155,
+ :rstime => 155,
+ :retime => 230,
+ :estime => 230,
+ :eetime => 260,
+ :reason => 2
+ },
+ {
+ :hid => 8,
+ :seq => 1,
+ :pstime => 270,
+ :petime => 275,
+ :rstime => 275,
+ :retime => 0,
+ :estime => 0,
+ :eetime => 0,
+ :reason => 0
+ }
+ ]
+ }
+
+ @mock_client.add_vm(1, values)
+
+ @accounting.insert(create_vmpool_hash)
+ check_lines(1,2)
+
+ h1 = values[:history].first
+ sum1 = h1[:retime] - h1[:rstime]
+
+ h2 = values[:history].last
+ sum2 = ts3 - h2[:rstime]
+
+ warn "* T1 RSTIME1 RETIME1 RSTIME1 T2"
+ @watch_client.running_time(ts1, ts3).to_i.should eql(sum1 + sum2)
+ end
+end
\ No newline at end of file
diff --git a/src/acct/test/XVm1His.rb b/src/acct/test/XVm1His.rb
new file mode 100644
index 0000000000..faf17ab0b4
--- /dev/null
+++ b/src/acct/test/XVm1His.rb
@@ -0,0 +1,91 @@
+require 'helper/test_helper.rb'
+
+describe "X Vm 1 History" do
+ before(:each) do
+ clean_db
+
+ @mock_client = MockClient.new
+ @accounting = OneWatch::Accounting.new(@mock_client)
+
+ @watch_client = AcctClient.new
+
+ @db = WatchHelper::DB
+ check_lines(0,0)
+ end
+
+ it "Running testing" do
+ ts1 = 100
+ @accounting.set_mock_timestamp(ts1)
+
+ @accounting.insert(create_vmpool_hash)
+ check_lines(0,0)
+
+ ts2 = 200
+ @accounting.set_mock_timestamp(ts2)
+
+ values = {
+ :uid => 2,
+ :gid => 4,
+ :history => [
+ :hid => 6,
+ :seq => 0,
+ :pstime => 150,
+ :petime => 155,
+ :rstime => 155,
+ :retime => 0,
+ :estime => 0,
+ :eetime => 0,
+ :reason => 0
+ ]
+ }
+
+ @mock_client.add_vm(1, values)
+
+ @accounting.insert(create_vmpool_hash)
+ check_lines(1,1)
+
+ history = values[:history].first
+ sum = ts2 - history[:rstime]
+
+ warn "* T1 RSTIME T2"
+ @watch_client.running_time(ts1, ts2).to_i.should eql(sum)
+
+ ts3 = 300
+ @accounting.set_mock_timestamp(ts3)
+
+ values2 = {
+ :uid => 2,
+ :gid => 4,
+ :history => [
+ :hid => 7,
+ :seq => 0,
+ :pstime => 220,
+ :petime => 260,
+ :rstime => 260,
+ :retime => 0,
+ :estime => 0,
+ :eetime => 0,
+ :reason => 0
+ ]
+ }
+
+ @mock_client.add_vm(2, values2)
+
+ @accounting.insert(create_vmpool_hash)
+ check_lines(2,2)
+
+ history1 = values[:history].first
+ sum1 = ts3 - history1[:rstime]
+
+ history2 = values2[:history].first
+ sum2 = ts3 - history2[:rstime]
+
+ warn "* T1 RSTIME T2"
+ @watch_client.running_time(ts1, ts3).to_i.should eql(sum1 + sum2)
+ @watch_client.running_time(ts1, ts3, :vmid=>1).to_i.should eql(sum1)
+ @watch_client.running_time(ts1, ts3, :vmid=>2).to_i.should eql(sum2)
+ @watch_client.running_time(ts1, ts3, :uid=>2).to_i.should eql(sum1 + sum2)
+ @watch_client.running_time(ts1, ts3, :hid=>6).to_i.should eql(sum1)
+ @watch_client.running_time(ts1, ts3, :hid=>7).to_i.should eql(sum2)
+ end
+end
\ No newline at end of file
diff --git a/src/acct/test/fixtures/empty_pool.xml b/src/acct/test/fixtures/empty_pool.xml
new file mode 100644
index 0000000000..2a8bcd37c2
--- /dev/null
+++ b/src/acct/test/fixtures/empty_pool.xml
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/acct/test/fixtures/vm.xml b/src/acct/test/fixtures/vm.xml
new file mode 100644
index 0000000000..1560a16029
--- /dev/null
+++ b/src/acct/test/fixtures/vm.xml
@@ -0,0 +1,46 @@
+
+ <%= id %>
+ <%= vm[:uid] ? vm[:uid] : 0 %>
+ <%= vm[:gid] ? vm[:gid] : 0 %>
+ <%= vm[:name] ? vm[:uid] : 'pepe' %>
+ <%= vm[:last_poll] ? vm[:last_poll] : '1309275256' %>
+ <%= vm[:state] ? vm[:state] : 3 %>
+ 3
+ 1309275252
+ 0
+ dummy
+ <%= vm[:memory] ? vm[:memory] : 128 %>
+ <%= vm[:cpu] ? vm[:cpu] : 1 %>
+ <%= vm[:net_tx] ? vm[:net_tx] : 0 %>
+ <%= vm[:net_rx] ? vm[:net_rx] : 0 %>
+
+
+
+
+
+
+
+ <% if history = vm[:history] %>
+
+ <% history.each do |h| %>
+
+ <%= h[:seq] ? h[:seq] : 0 %>
+ <%= h[:hostname] ? h[:hostname] : "kvxen" %>
+ /Users/dmolina/trabajo/acctmoni/install/var/
+ <%= h[:hid] ? h[:hid] : 0 %>
+ 1309275256
+ 0
+ vmm_dummy
+ tm_dummy
+ <%= h[:pstime] ? h[:pstime] : 0 %>
+ <%= h[:petime] ? h[:petime] : 0 %>
+ <%= h[:rstime] ? h[:rstime] : 0 %>
+ <%= h[:retime] ? h[:retime] : 0 %>
+ <%= h[:estime] ? h[:estime] : 0 %>
+ <%= h[:eetime] ? h[:eetime] : 0 %>
+ <%= h[:reason] ? h[:reason] : 0 %>
+
+ <% end %>
+
+ <% end %>
+
\ No newline at end of file
diff --git a/src/acct/test/fixtures/vmpool.xml b/src/acct/test/fixtures/vmpool.xml
new file mode 100644
index 0000000000..1ff7f5626e
--- /dev/null
+++ b/src/acct/test/fixtures/vmpool.xml
@@ -0,0 +1,49 @@
+
+ <% vms.each do |id,vm| %>
+
+ <%= id %>
+ <%= vm[:uid] ? vm[:uid] : 0 %>
+ <%= vm[:gid] ? vm[:gid] : 0 %>
+ <%= vm[:name] ? vm[:uid] : 'pepe' %>
+ <%= vm[:last_poll] ? vm[:last_poll] : '1309275256' %>
+ <%= vm[:state] ? vm[:state] : 3 %>
+ 3
+ 1309275252
+ 0
+ dummy
+ <%= vm[:memory] ? vm[:memory] : 128 %>
+ <%= vm[:cpu] ? vm[:cpu] : 1 %>
+ <%= vm[:net_tx] ? vm[:net_tx] : 0 %>
+ <%= vm[:net_rx] ? vm[:net_rx] : 0 %>
+
+
+
+
+
+
+
+ <% if history = vm[:history] %>
+
+ <% h = history.last %>
+
+ <%= h[:seq] ? h[:seq] : 0 %>
+ <%= h[:hostname] ? h[:hostname] : "kvxen" %>
+ /Users/dmolina/trabajo/acctmoni/install/var/
+ <%= h[:hid] ? h[:hid] : 0 %>
+ 1309275256
+ 0
+ vmm_dummy
+ tm_dummy
+ <%= h[:pstime] ? h[:pstime] : 0 %>
+ <%= h[:petime] ? h[:petime] : 0 %>
+ <%= h[:rstime] ? h[:rstime] : 0 %>
+ <%= h[:retime] ? h[:retime] : 0 %>
+ <%= h[:estime] ? h[:estime] : 0 %>
+ <%= h[:eetime] ? h[:eetime] : 0 %>
+ <%= h[:reason] ? h[:reason] : 0 %>
+
+
+ <% end %>
+
+ <% end %>
+
diff --git a/src/acct/test/helper/mock_client.rb b/src/acct/test/helper/mock_client.rb
new file mode 100644
index 0000000000..53a560313f
--- /dev/null
+++ b/src/acct/test/helper/mock_client.rb
@@ -0,0 +1,49 @@
+require 'erb'
+
+FPATH = "./fixtures/"
+
+class MockClient
+ def initialize
+ @vmpool = File.read("./fixtures/empty_pool.xml")
+ @done_vmpool = File.read("./fixtures/empty_pool.xml")
+
+ @vms = Hash.new
+ @done_vms = Hash.new
+ end
+
+
+ def call(action, *args)
+ xmlrpc_action = "one."+action
+
+ case xmlrpc_action
+ when "one.vm.info"
+ id = args[0]
+ vm = @vms[id]
+ return ERB.new(File.read(FPATH+'vm.xml')).result(binding)
+ when "one.vmpool.info"
+ case args[3]
+ when -1
+ return File.read("./fixtures/empty_pool.xml") if @vms.empty?
+ vms = @vms
+ return ERB.new(File.read(FPATH+'vmpool.xml')).result(binding)
+ when 6 then
+ return File.read("./fixtures/empty_pool.xml") if @done_vms.empty?
+ vms = @done_vms
+ return ERB.new(File.read(FPATH+'vmpool.xml')).result(binding)
+ end
+ end
+ end
+
+ def add_vm(id, values)
+ if values[:state] == 6
+ @done_vms[id] = values
+ elsif
+ @vms[id] = values
+ end
+ end
+
+ def delete_vm(id)
+ @vms.delete(id)
+ @vms_done.delete(id)
+ end
+end
\ No newline at end of file
diff --git a/src/acct/test/helper/test_helper.rb b/src/acct/test/helper/test_helper.rb
new file mode 100644
index 0000000000..bfef9dee6f
--- /dev/null
+++ b/src/acct/test/helper/test_helper.rb
@@ -0,0 +1,71 @@
+require 'rubygems'
+require 'sequel'
+
+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
+
+require 'OpenNebula'
+
+$: << './helper'
+$: << '.'
+$: << '..'
+
+
+require 'examples/acct_client'
+require 'watch_client'
+require 'mock_client'
+
+require 'accounting'
+require 'monitoring'
+
+module OneWatch
+ class Accounting
+ def set_mock_timestamp(t)
+ @mock_timestamp = t
+ end
+
+ def generate_timestamp
+ @mock_timestamp
+ end
+ end
+
+ class Monitoring
+ def set_mock_timestamp(t)
+ @mock_timestamp = t
+ end
+
+ def generate_timestamp
+ @mock_timestamp
+ end
+ end
+end
+
+def create_vmpool_hash
+ @vm_pool = OpenNebula::VirtualMachinePool.new(@mock_client, -2)
+ @vm_pool.info
+ hash = @vm_pool.to_hash
+end
+
+def clean_db
+ begin
+ WatchHelper::Register.destroy
+ WatchHelper::Metric.destroy
+ WatchHelper::VmShare.destroy
+ WatchHelper::HostShare.destroy
+ WatchHelper::Vm.destroy
+ WatchHelper::Host.destroy
+ rescue Exception => e
+ warn e.message
+ end
+end
+
+def check_lines(*args)
+ @db[:vms].count.should eql(args[0])
+ @db[:registers].count.should eql(args[1])
+end
diff --git a/src/acct/test/monitoring_spec.rb b/src/acct/test/monitoring_spec.rb
new file mode 100644
index 0000000000..d5d9eea094
--- /dev/null
+++ b/src/acct/test/monitoring_spec.rb
@@ -0,0 +1,56 @@
+require 'helper/test_helper.rb'
+
+describe "1 Vm 1 10 steps" do
+ before(:each) do
+ clean_db
+
+ @mock_client = MockClient.new
+ @monitoring = OneWatch::VmMonitoring.new
+
+ @watch_client = OneWatchClient::WatchClient.new
+
+ @db = WatchHelper::DB
+ @db[:vms].count.should eql(0)
+ end
+
+ it "CPU testing" do
+ ts1 = 100
+ @monitoring.set_mock_timestamp(ts1)
+
+ @monitoring.insert(create_vmpool_hash)
+ @db[:vms].count.should eql(0)
+
+ 10.times { |i|
+ ts2 = 200+100*i
+ @monitoring.set_mock_timestamp(ts2)
+
+ values = {
+ :cpu => 80+i,
+ :memory => 122+i,
+ :net_tx => 200+i,
+ :net_rx => 134+i,
+ :last_poll => 1309275256+i,
+ :uid => 2,
+ :gid => 4,
+ :history => [
+ :hid => 7,
+ :pstime => 150,
+ :petime => 0,
+ :rstime => 0,
+ :retime => 0,
+ :estime => 0,
+ :eetime => 0,
+ :reason => 0
+ ]
+ }
+
+ @mock_client.add_vm(1, values)
+
+ @monitoring.insert(create_vmpool_hash)
+ @db[:vms].count.should eql(1)
+ @db[:vm_shares].count.should eql(1+i > 5 ? 5 : 1+i)
+
+ pp @watch_client.vm_monitoring(1)
+ }
+ end
+end
\ No newline at end of file
diff --git a/src/acct/watch_client.rb b/src/acct/watch_client.rb
new file mode 100644
index 0000000000..427a7e43bc
--- /dev/null
+++ b/src/acct/watch_client.rb
@@ -0,0 +1,30 @@
+module OneWatchClient
+ require 'watch_helper'
+ require 'json'
+
+ class WatchClient
+ def vm_monitoring(id, opts=[])
+ hash = Hash.new
+ hash[:resource] = "VM"
+ hash[:id] = id
+
+ mon = Hash.new
+ opts.each { |opt|
+ next unless WatchHelper::VM_SHARE.has_key?(opt.to_sym)
+ mon[opt] = Array.new
+ }
+
+ # TBD Check if VM exists
+ WatchHelper::Vm[id].vm_shares_dataset.map { |vm|
+ opts.each { |opt|
+ next unless WatchHelper::VM_SHARE.has_key?(opt.to_sym)
+ mon[opt] << [vm.last_poll, vm.send(opt.to_sym)]
+ }
+ }
+
+ hash[:monitoring] = mon
+
+ puts JSON.pretty_generate hash
+ end
+ end
+end
\ No newline at end of file
diff --git a/src/acct/watch_helper.rb b/src/acct/watch_helper.rb
new file mode 100644
index 0000000000..7a98c9992b
--- /dev/null
+++ b/src/acct/watch_helper.rb
@@ -0,0 +1,315 @@
+module WatchHelper
+ DB = Sequel.connect('sqlite:///tmp/test_one_acct.db')
+
+ class Register < Sequel::Model
+ plugin :schema
+
+ set_schema do
+ foreign_key :vm_id, :vms
+ Integer :hid
+ String :hostname
+ Integer :seq
+ Integer :pstime
+ Integer :petime
+ Integer :rstime
+ Integer :retime
+ Integer :estime
+ Integer :eetime
+ Integer :reason
+
+ primary_key [:vm_id, :seq]
+ end
+
+ create_table unless table_exists?
+
+ unrestrict_primary_key
+
+ many_to_one :vm
+
+ def update_from_history(history)
+ self.seq = history['SEQ']
+ self.hostname = history['HOSTNAME']
+ self.hid = history['HID']
+ self.pstime = history['PSTIME']
+ self.petime = history['PETIME']
+ self.rstime = history['RSTIME']
+ self.retime = history['RETIME']
+ self.estime = history['ESTIME']
+ self.eetime = history['EETIME']
+ self.reason = history['REASON']
+
+ self.save
+ end
+
+ def self.create_from_history(history)
+ a = Register.create(
+ :seq => history['SEQ'],
+ :hostname => history['HOSTNAME'],
+ :hid => history['HID'],
+ :pstime => history['PSTIME'],
+ :petime => history['PETIME'],
+ :rstime => history['RSTIME'],
+ :retime => history['RETIME'],
+ :estime => history['ESTIME'],
+ :eetime => history['EETIME'],
+ :reason => history['REASON']
+ )
+ end
+ end
+
+ class Metric < Sequel::Model
+ plugin :schema
+
+ set_schema do
+ foreign_key :vm_id, :vms
+ Integer :timestamp
+ Integer :ptimestamp
+ Integer :net_rx
+ Integer :net_tx
+
+ primary_key [:vm_id, :timestamp]
+ end
+
+ create_table unless table_exists?
+
+ unrestrict_primary_key
+
+ many_to_one :vm
+ end
+
+ class Vm < Sequel::Model
+ plugin :schema
+
+ set_schema do
+ Integer :id, :primary_key=>true
+ String :name
+ Integer :uid
+ Integer :gid
+ Integer :mem
+ Integer :cpu
+ Integer :vcpu
+ Integer :stime
+ Integer :etime
+ end
+
+ create_table unless table_exists?
+
+ unrestrict_primary_key
+
+ # Accounting
+ one_to_many :registers, :order=>:seq
+ one_to_many :metrics
+
+ # Monitoring
+ one_to_many :vm_shares, :before_add=>:control_regs, :order=>:timestamp
+
+ def self.info(vm)
+ Vm.find_or_create(:id=>vm['ID']) { |v|
+ v.uid = vm['UID'].to_i
+ v.name = vm['NAME']
+ v.gid = vm['GID'].to_i
+ v.mem = vm['MEMORY'].to_i
+ v.cpu = vm['CPU'].to_i
+ v.vcpu = vm['VCPU'].to_i
+ v.stime = vm['STIME'].to_i
+ v.etime = vm['ETIME'].to_i
+ }
+ end
+
+ def add_share(vm, timestamp)
+ vs = VmShare.create_from_vm(vm, timestamp)
+ self.add_vm_share(vs)
+ end
+
+ private
+
+ def control_regs(share)
+ if self.vm_shares.count > 4
+ self.vm_shares.first.delete
+ end
+ end
+ end
+
+ class Host < Sequel::Model
+ plugin :schema
+
+ set_schema do
+ Integer :id, :primary_key=>true
+ String :name
+ Integer :im_mad
+ Integer :vm_mad
+ Integer :tm_mad
+ end
+
+ create_table unless table_exists?
+
+ unrestrict_primary_key
+
+ # Monitoring
+ one_to_many :host_shares, :before_add=>:control_regs, :order=>:timestamp
+
+ def add_share(host, timestamp)
+ hs = HostShare.create_from_host(host, timestamp)
+ self.add_host_share(hs)
+ end
+
+ private
+
+ def control_regs(share)
+ if self.host_shares.count > 4
+ self.host_shares.first.delete
+ end
+ end
+ end
+
+ HOST_SHARE = {
+ :disk_usage => {
+ :type => Integer,
+ :path => 'DISK_USAGE'
+ },
+ :mem_usage => {
+ :type => Integer,
+ :path => 'MEM_USAGE'
+ },
+ :cpu_usage => {
+ :type => Integer,
+ :path => 'CPU_USAGE'
+ },
+ :max_disk => {
+ :type => Integer,
+ :path => 'MAX_DISK'
+ },
+ :max_mem => {
+ :type => Integer,
+ :path => 'MAX_MEM'
+ },
+ :mem_cpu => {
+ :type => Integer,
+ :path => 'MAX_CPU'
+ },
+ :free_disk => {
+ :type => Integer,
+ :path => 'FREE_DISK'
+ },
+ :free_mem => {
+ :type => Integer,
+ :path => 'FREE_MEM'
+ },
+ :free_cpu => {
+ :type => Integer,
+ :path => 'FREE_CPU'
+ },
+ :used_disk => {
+ :type => Integer,
+ :path => 'USED_DISK'
+ },
+ :used_mem => {
+ :type => Integer,
+ :path => 'USED_MEM'
+ },
+ :used_cpu => {
+ :type => Integer,
+ :path => 'USED_CPU'
+ },
+ :rvms => {
+ :type => Integer,
+ :path => 'RUNNING_VMS'
+ }
+ }
+
+ class HostShare < Sequel::Model
+ plugin :schema
+
+ set_schema do
+ foreign_key :host_id, :hosts
+ Integer :last_poll
+ Integer :timestamp
+
+ HOST_SHARE.each { |key,value|
+ column key, value[:type]
+ }
+
+ primary_key [:host_id, :timestamp]
+ end
+
+ create_table unless table_exists?
+
+ unrestrict_primary_key
+
+ many_to_one :host
+
+ def self.create_from_host(host, timestamp)
+ hash = {
+ :timestamp => timestamp,
+ :last_poll => host['LAST_MON_TIME'],
+ :state => host['STATE'],
+ }
+
+ host_share = host['HOST_SHARE']
+ HOST_SHARE.each { |key,value|
+ hash[key] = host_share[value[:path]]
+ }
+
+ HostShare.create(hash)
+ end
+ end
+
+ VM_SHARE = {
+ :cpu => {
+ :type => Integer,
+ :path => 'CPU'
+ },
+ :memory => {
+ :type => Integer,
+ :path => 'MEMORY'
+ },
+ :net_tx => {
+ :type => Integer,
+ :path => 'NET_TX'
+ },
+ :net_rx => {
+ :type => Integer,
+ :path => 'NET_RX'
+ }
+ }
+
+ class VmShare < Sequel::Model
+ plugin :schema
+
+ set_schema do
+ foreign_key :vm_id, :vms
+ Integer :state
+ Integer :lcm_state
+ Integer :last_poll
+ Integer :timestamp
+
+ VM_SHARE.each { |key,value|
+ column key, value[:type]
+ }
+
+ primary_key [:vm_id, :timestamp]
+ end
+
+ create_table unless table_exists?
+
+ unrestrict_primary_key
+
+ many_to_one :vm
+
+ def self.create_from_vm(vm, timestamp)
+ hash = {
+ :timestamp => timestamp,
+ :last_poll => vm['LAST_POLL'],
+ :state => vm['STATE'],
+ :lcm_state => vm['LCM_STATE'],
+ }
+
+ VM_SHARE.each { |key,value|
+ hash[key] = vm[value[:path]]
+ }
+
+ VmShare.create(hash)
+ end
+ end
+end
+
\ No newline at end of file