[Ovirt-devel] [PATCH server] Vm state change auditing/accounting
Steve Linabery
slinabery at redhat.com
Wed Jun 24 16:38:40 UTC 2009
Adds VmStateChangeEvent class and uses VmObserver to track/audit state
changes for Vm objects. Callbacks in VmObserver also update the new
total_uptime and total_uptime_timestamp attributes of Vm class, which
allows easy calculation of time spent in running states for user
resource use accounting.
---
src/app/models/vm.rb | 34 +++++++++++
src/app/models/vm_observer.rb | 96 ++++++++++++++++++++++++++++++
src/app/models/vm_state_change_event.rb | 22 +++++++
src/config/environment.rb | 2 +-
src/db/migrate/039_add_vm_state_audit.rb | 49 +++++++++++++++
5 files changed, 202 insertions(+), 1 deletions(-)
create mode 100644 src/app/models/vm_observer.rb
create mode 100644 src/app/models/vm_state_change_event.rb
create mode 100644 src/db/migrate/039_add_vm_state_audit.rb
diff --git a/src/app/models/vm.rb b/src/app/models/vm.rb
index c1be4a6..a45342e 100644
--- a/src/app/models/vm.rb
+++ b/src/app/models/vm.rb
@@ -41,6 +41,14 @@ class Vm < ActiveRecord::Base
:order => 'time_started DESC',
:dependent => :destroy
+
+ has_many :vm_state_change_events,
+ :order => 'created_at' do
+ def previous_state_with_type(state_type)
+ find(:first, :conditions=> { :to_state => state_type }, :order=> 'created_at DESC')
+ end
+ end
+
alias history vm_host_histories
validates_presence_of :uuid, :description, :num_vcpus_allocated,
@@ -138,6 +146,25 @@ class Vm < ActiveRecord::Base
STATE_CREATE_FAILED = "create_failed"
STATE_INVALID = "invalid"
+ ALL_STATES = [STATE_PENDING,
+ STATE_CREATING,
+ STATE_RUNNING,
+ STATE_UNREACHABLE,
+ STATE_POWERING_OFF,
+ STATE_STOPPING,
+ STATE_STOPPED,
+ STATE_STARTING,
+ STATE_SUSPENDING,
+ STATE_SUSPENDED,
+ STATE_RESUMING,
+ STATE_SAVING,
+ STATE_SAVED,
+ STATE_RESTORING,
+ STATE_MIGRATING,
+ STATE_CREATE_FAILED,
+ STATE_INVALID]
+
+
DESTROYABLE_STATES = [STATE_PENDING,
STATE_STOPPED,
STATE_CREATE_FAILED,
@@ -176,6 +203,13 @@ class Vm < ActiveRecord::Base
validates_inclusion_of :state,
:in => EFFECTIVE_STATE.keys
+ def get_calculated_uptime
+ if VmObserver::AUDIT_RUNNING_STATES.include?(state)
+ total_uptime_timestamp ? total_uptime + (Time.now - total_uptime_timestamp) : 0
+ else
+ total_uptime
+ end
+ end
def get_vm_pool
vm_resource_pool
diff --git a/src/app/models/vm_observer.rb b/src/app/models/vm_observer.rb
new file mode 100644
index 0000000..914fd35
--- /dev/null
+++ b/src/app/models/vm_observer.rb
@@ -0,0 +1,96 @@
+#
+# Copyright (C) 2008 Red Hat, Inc.
+# Written by Steve Linabery <slinabery at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA. A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+class VmObserver < ActiveRecord::Observer
+
+ AUDIT_RUNNING_STATES = [Vm::STATE_RUNNING,
+ Vm::STATE_POWERING_OFF,
+ Vm::STATE_STOPPING,
+ Vm::STATE_STARTING,
+ Vm::STATE_RESUMING,
+ Vm::STATE_SAVING,
+ Vm::STATE_RESTORING,
+ Vm::STATE_MIGRATING]
+
+ AUDIT_NON_RUNNING_STATES = Vm::ALL_STATES - AUDIT_RUNNING_STATES - [Vm::STATE_UNREACHABLE]
+
+ def after_save(a_vm)
+ if a_vm.changed?
+ change = a_vm.changes['state']
+ if change
+ event = VmStateChangeEvent.new({ :vm => a_vm,
+ :from_state => change[0],
+ :to_state => change[1]})
+ event.save!
+ end
+ end
+ end
+
+ def before_save(a_vm)
+ if a_vm.changed?
+ change = a_vm.changes['state']
+ if change
+ #When going from a non-running state to a running state, update the
+ #total uptime timestamp to indicate the start of the running period.
+
+ if AUDIT_NON_RUNNING_STATES.include?(change[0]) &&
+ AUDIT_RUNNING_STATES.include?(change[1])
+ a_vm.total_uptime_timestamp = Time.now
+ end
+
+ #When going from a running state to anything but a running state,
+ #add the time since the last timestamp to the total uptime, and then
+ #update the total uptime timestamp.
+ #Note that this also matches the transition to unreachable
+
+ if AUDIT_RUNNING_STATES.include?(change[0]) &&
+ !AUDIT_RUNNING_STATES.include?(change[1])
+ a_vm.total_uptime = a_vm.total_uptime +
+ (Time.now - a_vm.total_uptime_timestamp)
+ a_vm.total_uptime_timestamp = Time.now
+ end
+
+
+ #Leaving the unreachable state for a running state is a special case.
+
+ if change[0] == Vm::STATE_UNREACHABLE &&
+ AUDIT_RUNNING_STATES.include?(change[1])
+
+ #We need to know from what state the Vm most recently entered the
+ #unreachable state
+ prev = a_vm.vm_state_change_events.previous_state_with_type(Vm::STATE_UNREACHABLE)
+
+ if prev
+ #If it entered unreachable from a running state, then we consider
+ #the time spent in unreachable as running time. Add the time
+ #spent in unreachable to total uptime, and update the timestamp.
+ if AUDIT_RUNNING_STATES.include?(prev.from_state)
+ a_vm.total_uptime = a_vm.total_uptime +
+ (Time.now - a_vm.total_uptime_timestamp)
+ a_vm.total_uptime_timestamp = Time.now
+ end
+ end
+ end
+
+ end
+ end
+ end
+end
+
+VmObserver.instance
diff --git a/src/app/models/vm_state_change_event.rb b/src/app/models/vm_state_change_event.rb
new file mode 100644
index 0000000..033e9da
--- /dev/null
+++ b/src/app/models/vm_state_change_event.rb
@@ -0,0 +1,22 @@
+#
+# Copyright (C) 2008 Red Hat, Inc.
+# Written by Steve Linabery <slinabery at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA. A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+class VmStateChangeEvent < ActiveRecord::Base
+ belongs_to :vm
+end
diff --git a/src/config/environment.rb b/src/config/environment.rb
index 4014613..98a2fbb 100644
--- a/src/config/environment.rb
+++ b/src/config/environment.rb
@@ -82,7 +82,7 @@ Rails::Initializer.run do |config|
# Activate observers that should always be running
# config.active_record.observers = :cacher, :garbage_collector
- config.active_record.observers = :host_observer
+ config.active_record.observers = :host_observer, :vm_observer
end
# Add new inflection rules using the following format
diff --git a/src/db/migrate/039_add_vm_state_audit.rb b/src/db/migrate/039_add_vm_state_audit.rb
new file mode 100644
index 0000000..f16fb8b
--- /dev/null
+++ b/src/db/migrate/039_add_vm_state_audit.rb
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2009 Red Hat, Inc.
+# Written by Steve Linabery <slinabery at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA. A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+class AddVmStateAudit < ActiveRecord::Migration
+ def self.up
+ add_column :vms, :total_uptime, :integer, :default => 0
+ add_column :vms, :total_uptime_timestamp, :timestamp
+
+ create_table :vm_state_change_events do |t|
+ t.timestamp :created_at
+ t.integer :vm_id
+ t.string :from_state
+ t.string :to_state
+ t.integer :lock_version, :default => 0
+ end
+
+ Vm.transaction do
+ Vm.find(:all).each do |vm|
+ event = VmStateChangeEvent.new(:vm_id => vm.id,
+ :to_state => vm.state
+ )
+ event.save!
+ end
+ end
+ end
+
+ def self.down
+ remove_column :vms, :total_uptime
+ remove_column :vms, :total_uptime_timestamp
+
+ drop_table :vm_state_change_events
+ end
+end
--
1.6.0.6
More information about the ovirt-devel
mailing list