2010-02-26 03:35:01 +03:00
#
# Copyright (C) 2010 Red Hat, Inc.
# 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.
#
2013-04-12 01:16:33 +04:00
# pylint: disable=E0611
2012-05-14 17:24:56 +04:00
from gi . repository import GObject
2013-04-12 01:16:33 +04:00
# pylint: enable=E0611
2012-05-14 17:24:56 +04:00
2010-02-26 03:35:01 +03:00
import difflib
import logging
2010-09-09 01:53:51 +04:00
import libxml2
2010-12-09 20:37:48 +03:00
from virtManager . baseclass import vmmGObject
2010-02-26 03:35:01 +03:00
2013-04-13 22:34:52 +04:00
2010-09-09 01:53:51 +04:00
def _sanitize_xml ( xml ) :
xml = libxml2 . parseDoc ( xml ) . serialize ( )
# Strip starting <?...> line
if xml . startswith ( " <? " ) :
ignore , xml = xml . split ( " \n " , 1 )
if not xml . endswith ( " \n " ) and xml . count ( " \n " ) :
xml + = " \n "
return xml
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
2013-09-10 01:14:16 +04:00
self . connect ( " config-changed " , self . _reparse_xml )
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
def get_key ( self ) :
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
def _define_name_helper ( self , objtype , rename_cb , newname ) :
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 " ,
objtype , oldname , newname )
origxml = xmlobj . get_xml_config ( )
xmlobj . name = newname
newxml = xmlobj . get_xml_config ( )
try :
rename_cb ( self , origxml , newxml )
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 #
#############################################################
2010-11-30 01:28:52 +03:00
def get_name ( self ) :
raise NotImplementedError ( )
2010-02-26 03:35:01 +03:00
def _XMLDesc ( self , flags ) :
2010-12-09 20:37:48 +03:00
raise NotImplementedError ( )
2010-02-26 03:35:01 +03:00
def _define ( self , xml ) :
ignore = xml
return
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
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 ) :
2010-09-09 01:53:51 +04:00
return _sanitize_xml ( 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 ) :
origxml = _sanitize_xml ( origxml )
newxml = _sanitize_xml ( newxml )
if origxml != newxml :
2010-02-26 03:35:01 +03:00
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 " ,
self . get_name ( ) , diff )
2010-09-09 01:53:51 +04:00
self . _define ( newxml )
2010-12-10 17:57:42 +03:00
else :
logging . debug ( " Redefine requested, but XML didn ' t change! " )
2010-09-09 01:53:51 +04:00
# Make sure we have latest XML
self . refresh_xml ( forcesignal = True )
return
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 )