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