2010-02-26 03:35:01 +03:00
#
2013-10-28 00:59:46 +04:00
# Copyright (C) 2010, 2013 Red Hat, Inc.
2010-02-26 03:35:01 +03:00
# Copyright (C) 2010 Cole Robinson <crobinso@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; either version 2 of the License, or
# (at your option) any later version.
#
# 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.
#
2012-05-14 17:24:56 +04:00
from gi . repository import GObject
2010-02-26 03:35:01 +03:00
import logging
2014-09-13 00:10:45 +04:00
from . baseclass import vmmGObject
2010-02-26 03:35:01 +03:00
2013-04-13 22:34:52 +04:00
2010-12-09 20:37:48 +03:00
class vmmLibvirtObject ( vmmGObject ) :
2012-05-14 17:24:56 +04:00
__gsignals__ = {
" config-changed " : ( GObject . SignalFlags . RUN_FIRST , None , [ ] ) ,
2013-07-07 02:37:10 +04:00
" started " : ( GObject . SignalFlags . RUN_FIRST , None , [ ] ) ,
" stopped " : ( GObject . SignalFlags . RUN_FIRST , None , [ ] ) ,
2012-05-14 17:24:56 +04:00
}
2013-09-23 16:34:50 +04:00
def __init__ ( self , conn , backend , key , parseclass ) :
2010-12-09 20:37:48 +03:00
vmmGObject . __init__ ( self )
2011-07-23 00:43:26 +04:00
self . _conn = conn
2013-07-07 16:42:57 +04:00
self . _backend = backend
self . _key = key
2013-09-10 01:14:16 +04:00
self . _parseclass = parseclass
2010-02-26 03:35:01 +03:00
self . _xml = None
self . _is_xml_valid = False
2013-09-10 01:14:16 +04:00
self . _xmlobj = None
self . _xmlobj_to_define = None
2010-02-26 03:35:01 +03:00
# These should be set by the child classes if necessary
self . _inactive_xml_flags = 0
self . _active_xml_flags = 0
2014-06-03 01:17:47 +04:00
# Cache object name
self . _name = None
self . get_name ( )
2013-09-10 01:14:16 +04:00
self . connect ( " config-changed " , self . _reparse_xml )
2014-01-27 02:42:24 +04:00
@staticmethod
def log_redefine_xml_diff ( obj , origxml , newxml ) :
objname = " < %s name= %s > " % ( obj . __class__ . __name__ , obj . get_name ( ) )
if origxml == newxml :
logging . debug ( " Redefine requested for %s , but XML didn ' t change! " ,
objname )
return
import difflib
diff = " " . join ( difflib . unified_diff ( origxml . splitlines ( 1 ) ,
newxml . splitlines ( 1 ) ,
fromfile = " Original XML " ,
tofile = " New XML " ) )
logging . debug ( " Redefining %s with XML diff: \n %s " , objname , diff )
2011-07-24 05:16:54 +04:00
def _cleanup ( self ) :
pass
2011-07-23 00:43:26 +04:00
def _get_conn ( self ) :
return self . _conn
conn = property ( _get_conn )
2010-02-26 03:35:01 +03:00
2013-07-07 16:42:57 +04:00
def get_backend ( self ) :
return self . _backend
2014-06-03 01:17:47 +04:00
def get_connkey ( self ) :
2013-07-07 16:42:57 +04:00
return self . _key
2013-09-29 20:14:00 +04:00
def change_name_backend ( self , newbackend ) :
# Used for changing the backing object after a rename
self . _backend = newbackend
2014-09-21 00:55:11 +04:00
def define_name ( self , newname ) :
2013-09-29 20:14:00 +04:00
oldname = self . get_xmlobj ( ) . name
self . _invalidate_xml ( )
xmlobj = self . _get_xmlobj_to_define ( )
if xmlobj . name == newname :
return
logging . debug ( " Changing %s name from %s to %s " ,
2014-09-21 00:55:11 +04:00
self . __class__ , oldname , newname )
2013-09-29 20:14:00 +04:00
origxml = xmlobj . get_xml_config ( )
xmlobj . name = newname
newxml = xmlobj . get_xml_config ( )
try :
2014-09-21 00:55:11 +04:00
self . _key = newname
self . conn . rename_object ( self , origxml , newxml , oldname , newname )
except :
self . _key = oldname
raise
2013-09-29 20:14:00 +04:00
finally :
self . _invalidate_xml ( )
self . emit ( " config-changed " )
2013-09-23 16:34:50 +04:00
2010-02-26 03:35:01 +03:00
#############################################################
# Functions that should probably be overridden in sub class #
#############################################################
def _XMLDesc ( self , flags ) :
2010-12-09 20:37:48 +03:00
raise NotImplementedError ( )
2014-02-11 21:07:13 +04:00
def _using_events ( self ) :
return False
2010-02-26 03:35:01 +03:00
def _define ( self , xml ) :
ignore = xml
return
2013-09-30 23:23:14 +04:00
def delete ( self , force = True ) :
ignore = force
2014-05-28 16:26:31 +04:00
def force_update_status ( self , from_event = False , log = True ) :
2014-02-11 22:19:15 +04:00
ignore = from_event
2014-05-28 16:26:31 +04:00
ignore = log
2014-02-11 22:19:15 +04:00
2014-06-03 01:17:47 +04:00
def get_name ( self ) :
if self . _name is None :
self . _name = self . _backend_get_name ( )
return self . _name
def _backend_get_name ( self ) :
return self . _backend . name ( )
2013-07-07 16:05:23 +04:00
2010-02-26 03:35:01 +03:00
##################
# Public XML API #
##################
2013-09-10 01:14:16 +04:00
def get_xml ( self , * args , * * kwargs ) :
2010-02-26 03:35:01 +03:00
"""
2013-09-10 01:14:16 +04:00
See _get_raw_xml for parameter docs
2010-02-26 03:35:01 +03:00
"""
2013-09-23 16:34:50 +04:00
return self . get_xmlobj ( * args , * * kwargs ) . get_xml_config ( )
def get_xmlobj ( self , inactive = False , refresh_if_nec = True ) :
xml = self . _get_raw_xml ( inactive , refresh_if_nec )
if inactive :
# If inactive XML requested, always return a fresh object even
# the current object is inactive XML (like when the domain is
# stopped). Callers that request inactive are basically expecting
# a new copy.
return self . _build_xmlobj ( xml )
if not self . _xmlobj :
self . _reparse_xml ( )
return self . _xmlobj
2010-02-26 03:35:01 +03:00
2010-09-09 01:53:51 +04:00
def refresh_xml ( self , forcesignal = False ) :
2010-02-26 03:35:01 +03:00
# Force an xml update. Signal 'config-changed' if domain xml has
# changed since last refresh
origxml = self . _xml
2010-09-09 01:53:51 +04:00
self . _invalidate_xml ( )
2010-02-26 03:35:01 +03:00
self . _xml = self . _XMLDesc ( self . _active_xml_flags )
self . _is_xml_valid = True
2010-09-09 01:53:51 +04:00
if origxml != self . _xml or forcesignal :
2011-04-18 19:12:36 +04:00
self . idle_emit ( " config-changed " )
2010-02-26 03:35:01 +03:00
2013-07-07 16:05:23 +04:00
2010-02-26 03:35:01 +03:00
######################################
# Internal XML cache/update routines #
######################################
def _invalidate_xml ( self ) :
# Mark cached xml as invalid
self . _is_xml_valid = False
2013-09-10 01:14:16 +04:00
self . _xmlobj_to_define = None
2014-09-21 01:21:16 +04:00
self . _name = None
2010-02-26 03:35:01 +03:00
2013-07-07 16:05:23 +04:00
2010-02-26 03:35:01 +03:00
##########################
# Internal API functions #
##########################
2013-09-10 01:14:16 +04:00
def _get_raw_xml ( self , inactive = False , refresh_if_nec = True ) :
"""
Get object xml . If cached xml is invalid , update .
@param inactive : Return persistent XML , not the running config .
No effect if domain is not running . Use this flag
if the XML will be used for redefining a guest
@param refresh_if_nec : Check if XML is out of date , and if so ,
refresh it ( default behavior ) . Skipping a refresh is
useful to prevent updating xml in the tick loop when
it ' s not that important (disk/net stats)
"""
if inactive :
return self . _XMLDesc ( self . _inactive_xml_flags )
if self . _xml is None :
self . refresh_xml ( )
elif refresh_if_nec and not self . _is_xml_valid :
self . refresh_xml ( )
return self . _xml
2010-12-10 17:57:42 +03:00
def _xml_to_redefine ( self ) :
2013-09-30 23:01:11 +04:00
return self . get_xml ( inactive = True )
2010-02-26 03:35:01 +03:00
2013-09-10 01:14:16 +04:00
def redefine_cached ( self ) :
if not self . _xmlobj_to_define :
logging . debug ( " No cached XML to define, skipping. " )
return
obj = self . _get_xmlobj_to_define ( )
xml = obj . get_xml_config ( )
self . _redefine_xml ( xml )
def _reparse_xml ( self , ignore = None ) :
self . _xmlobj = self . _build_xmlobj ( self . _get_raw_xml ( ) )
def _build_xmlobj ( self , xml ) :
return self . _parseclass ( self . conn . get_backend ( ) , parsexml = xml )
def _get_xmlobj_to_define ( self ) :
if not self . _xmlobj_to_define :
2013-09-23 16:34:50 +04:00
self . _xmlobj_to_define = self . get_xmlobj ( inactive = True )
2013-09-10 01:14:16 +04:00
return self . _xmlobj_to_define
2010-09-09 01:53:51 +04:00
def _redefine_helper ( self , origxml , newxml ) :
2014-01-27 02:42:24 +04:00
self . log_redefine_xml_diff ( self , origxml , newxml )
2010-02-26 03:35:01 +03:00
2013-09-30 22:28:43 +04:00
if origxml != newxml :
2010-09-09 01:53:51 +04:00
self . _define ( newxml )
2014-02-11 21:07:13 +04:00
if not self . _using_events ( ) :
# Make sure we have latest XML
self . refresh_xml ( forcesignal = True )
2010-02-26 03:35:01 +03:00
2010-09-09 01:53:51 +04:00
def _redefine_xml ( self , newxml ) :
2010-12-10 17:57:42 +03:00
origxml = self . _xml_to_redefine ( )
2010-09-09 01:53:51 +04:00
return self . _redefine_helper ( origxml , newxml )
2013-09-10 01:14:16 +04:00
def _redefine ( self , cb ) :
guest = self . _get_xmlobj_to_define ( )
return cb ( guest )