2014-01-20 20:09:13 +04:00
# Copyright (C) 2006, 2013, 2014 Red Hat, Inc.
2006-06-28 23:50:17 +04:00
# Copyright (C) 2006 Daniel P. Berrange <berrange@redhat.com>
#
2018-04-04 16:35:41 +03:00
# This work is licensed under the GNU GPLv2 or later.
2018-03-20 22:00:02 +03:00
# See the COPYING file in the top-level directory.
2006-06-15 01:52:49 +04:00
2006-09-26 02:41:47 +04:00
import logging
2013-10-01 05:41:10 +04:00
import os
2010-12-11 00:04:42 +03:00
import time
import threading
2011-04-18 20:39:53 +04:00
import libvirt
2013-10-01 01:11:22 +04:00
2014-09-18 01:25:03 +04:00
from virtinst import DomainCapabilities
2013-10-01 01:11:22 +04:00
from virtinst import DomainSnapshot
2019-02-08 01:36:10 +03:00
from virtinst import Guest
2018-03-20 19:18:35 +03:00
from virtinst import DeviceController
from virtinst import DeviceDisk
2006-08-08 19:51:58 +04:00
2014-09-13 00:10:45 +04:00
from . libvirtobject import vmmLibvirtObject
2018-02-27 20:29:52 +03:00
from . libvirtenummap import LibvirtEnumMap
2014-01-27 02:09:07 +04:00
2014-03-22 22:34:23 +04:00
class _SENTINEL ( object ) :
pass
2010-12-11 00:04:42 +03:00
def start_job_progress_thread ( vm , meter , progtext ) :
current_thread = threading . currentThread ( )
def jobinfo_cb ( ) :
while True :
time . sleep ( .5 )
if not current_thread . isAlive ( ) :
return False
try :
jobinfo = vm . job_info ( )
data_total = float ( jobinfo [ 3 ] )
2013-04-13 22:34:52 +04:00
# data_processed = float(jobinfo[4])
2010-12-11 00:04:42 +03:00
data_remaining = float ( jobinfo [ 5 ] )
# data_total is 0 if the job hasn't started yet
if not data_total :
continue
if not meter . started :
meter . start ( size = data_total ,
text = progtext )
progress = data_total - data_remaining
meter . update ( progress )
2017-07-24 11:26:48 +03:00
except Exception :
2010-12-11 00:04:42 +03:00
logging . exception ( " Error calling jobinfo " )
return False
return True
if vm . getjobinfo_supported :
t = threading . Thread ( target = jobinfo_cb ,
name = " job progress reporting " ,
args = ( ) )
t . daemon = True
t . start ( )
2013-04-13 22:34:52 +04:00
2019-04-18 17:08:30 +03:00
class vmmInspectionApplication ( object ) :
def __init__ ( self ) :
self . name = None
self . display_name = None
self . epoch = None
self . version = None
self . release = None
self . summary = None
self . description = None
2012-01-25 20:52:45 +04:00
class vmmInspectionData ( object ) :
def __init__ ( self ) :
2017-02-08 18:55:33 +03:00
self . os_type = None
2012-01-25 20:52:45 +04:00
self . distro = None
self . major_version = None
self . minor_version = None
self . hostname = None
self . product_name = None
self . product_variant = None
self . icon = None
self . applications = None
2018-03-13 23:37:46 +03:00
self . errorstr = None
2019-04-17 19:49:51 +03:00
self . package_format = None
2012-01-25 20:52:45 +04:00
2013-04-13 22:34:52 +04:00
Initial snapshot support
This adds initial UI for managing snapshots: list, run/revert, delete,
add, and redefining (for changing <description>) supported, but currently
only for internal snapshots. The UI is mostly in its final form except for
some bells and whistles.
The real remaining question is what do we want to advertise and support.
Internal (qcow2) snapshots are by far the simplest to manage, very
mature, and already have the semantics we want.
However most recent libvirt and qemu work has been to facilitate
external snapshots, which are more extensible and can be performed
live, and with qemu-ga coordination for extra safety. However
they make things much harder for virt-manager at the moment.
Until we have a plan, this work should be considered experimental
and not be relied upon.
2013-08-02 18:18:47 +04:00
class vmmDomainSnapshot ( vmmLibvirtObject ) :
"""
Class wrapping a virDomainSnapshot object
"""
def __init__ ( self , conn , backend ) :
2013-09-10 01:14:16 +04:00
vmmLibvirtObject . __init__ ( self , conn , backend , backend . getName ( ) ,
2013-10-01 01:11:22 +04:00
DomainSnapshot )
Initial snapshot support
This adds initial UI for managing snapshots: list, run/revert, delete,
add, and redefining (for changing <description>) supported, but currently
only for internal snapshots. The UI is mostly in its final form except for
some bells and whistles.
The real remaining question is what do we want to advertise and support.
Internal (qcow2) snapshots are by far the simplest to manage, very
mature, and already have the semantics we want.
However most recent libvirt and qemu work has been to facilitate
external snapshots, which are more extensible and can be performed
live, and with qemu-ga coordination for extra safety. However
they make things much harder for virt-manager at the moment.
Until we have a plan, this work should be considered experimental
and not be relied upon.
2013-08-02 18:18:47 +04:00
2015-04-10 16:15:44 +03:00
##########################
# Required class methods #
##########################
2014-06-03 01:17:47 +04:00
def _backend_get_name ( self ) :
return self . _backend . getName ( )
2015-04-10 16:15:44 +03:00
def _conn_tick_poll_param ( self ) :
return None
def class_name ( self ) :
return " snapshot "
Initial snapshot support
This adds initial UI for managing snapshots: list, run/revert, delete,
add, and redefining (for changing <description>) supported, but currently
only for internal snapshots. The UI is mostly in its final form except for
some bells and whistles.
The real remaining question is what do we want to advertise and support.
Internal (qcow2) snapshots are by far the simplest to manage, very
mature, and already have the semantics we want.
However most recent libvirt and qemu work has been to facilitate
external snapshots, which are more extensible and can be performed
live, and with qemu-ga coordination for extra safety. However
they make things much harder for virt-manager at the moment.
Until we have a plan, this work should be considered experimental
and not be relied upon.
2013-08-02 18:18:47 +04:00
def _XMLDesc ( self , flags ) :
2013-09-10 01:14:16 +04:00
return self . _backend . getXMLDesc ( flags = flags )
2015-04-10 01:02:42 +03:00
def _get_backend_status ( self ) :
return self . _STATUS_ACTIVE
Initial snapshot support
This adds initial UI for managing snapshots: list, run/revert, delete,
add, and redefining (for changing <description>) supported, but currently
only for internal snapshots. The UI is mostly in its final form except for
some bells and whistles.
The real remaining question is what do we want to advertise and support.
Internal (qcow2) snapshots are by far the simplest to manage, very
mature, and already have the semantics we want.
However most recent libvirt and qemu work has been to facilitate
external snapshots, which are more extensible and can be performed
live, and with qemu-ga coordination for extra safety. However
they make things much harder for virt-manager at the moment.
Until we have a plan, this work should be considered experimental
and not be relied upon.
2013-08-02 18:18:47 +04:00
2015-04-10 16:15:44 +03:00
def tick ( self , stats_update = True ) :
ignore = stats_update
2015-04-10 21:08:25 +03:00
def _init_libvirt_state ( self ) :
2015-04-11 00:50:06 +03:00
self . ensure_latest_xml ( )
2015-04-10 16:15:44 +03:00
###########
# Actions #
###########
2013-09-30 23:23:14 +04:00
def delete ( self , force = True ) :
ignore = force
Initial snapshot support
This adds initial UI for managing snapshots: list, run/revert, delete,
add, and redefining (for changing <description>) supported, but currently
only for internal snapshots. The UI is mostly in its final form except for
some bells and whistles.
The real remaining question is what do we want to advertise and support.
Internal (qcow2) snapshots are by far the simplest to manage, very
mature, and already have the semantics we want.
However most recent libvirt and qemu work has been to facilitate
external snapshots, which are more extensible and can be performed
live, and with qemu-ga coordination for extra safety. However
they make things much harder for virt-manager at the moment.
Until we have a plan, this work should be considered experimental
and not be relied upon.
2013-08-02 18:18:47 +04:00
self . _backend . delete ( )
2019-06-09 22:29:44 +03:00
def _state_str_to_int ( self ) :
state = self . get_xmlobj ( ) . state
statemap = {
" nostate " : libvirt . VIR_DOMAIN_NOSTATE ,
" running " : libvirt . VIR_DOMAIN_RUNNING ,
" blocked " : libvirt . VIR_DOMAIN_BLOCKED ,
" paused " : libvirt . VIR_DOMAIN_PAUSED ,
" shutdown " : libvirt . VIR_DOMAIN_SHUTDOWN ,
" shutoff " : libvirt . VIR_DOMAIN_SHUTOFF ,
" crashed " : libvirt . VIR_DOMAIN_CRASHED ,
" pmsuspended " : getattr ( libvirt , " VIR_DOMAIN_PMSUSPENDED " , 7 )
}
if state == " disk-snapshot " or state not in statemap :
state = " shutoff "
return statemap . get ( state , libvirt . VIR_DOMAIN_NOSTATE )
2013-10-01 01:11:22 +04:00
def run_status ( self ) :
2019-06-09 22:29:44 +03:00
status = self . _state_str_to_int ( )
2018-02-27 20:29:52 +03:00
return LibvirtEnumMap . pretty_run_status ( status , False )
2013-10-01 01:11:22 +04:00
def run_status_icon_name ( self ) :
2019-06-09 22:29:44 +03:00
status = self . _state_str_to_int ( )
2018-02-27 20:29:52 +03:00
if status not in LibvirtEnumMap . VM_STATUS_ICONS :
2013-10-01 01:11:22 +04:00
logging . debug ( " Unknown status %d , using NOSTATE " , status )
status = libvirt . VIR_DOMAIN_NOSTATE
2018-02-27 20:29:52 +03:00
return LibvirtEnumMap . VM_STATUS_ICONS [ status ]
2013-10-01 01:11:22 +04:00
2014-02-01 20:25:35 +04:00
def is_current ( self ) :
return self . _backend . isCurrent ( )
2013-10-01 01:53:55 +04:00
def is_external ( self ) :
if self . get_xmlobj ( ) . memory_type == " external " :
return True
for disk in self . get_xmlobj ( ) . disks :
if disk . snapshot == " external " :
return True
return False
Initial snapshot support
This adds initial UI for managing snapshots: list, run/revert, delete,
add, and redefining (for changing <description>) supported, but currently
only for internal snapshots. The UI is mostly in its final form except for
some bells and whistles.
The real remaining question is what do we want to advertise and support.
Internal (qcow2) snapshots are by far the simplest to manage, very
mature, and already have the semantics we want.
However most recent libvirt and qemu work has been to facilitate
external snapshots, which are more extensible and can be performed
live, and with qemu-ga coordination for extra safety. However
they make things much harder for virt-manager at the moment.
Until we have a plan, this work should be considered experimental
and not be relied upon.
2013-08-02 18:18:47 +04:00
2011-05-04 00:17:52 +04:00
class vmmDomain ( vmmLibvirtObject ) :
2012-11-08 17:15:02 +04:00
"""
Class wrapping virDomain libvirt objects . Is also extended to be
backed by a virtinst . Guest object for new VM ' customize before install '
"""
2012-05-14 17:24:56 +04:00
__gsignals__ = {
2018-03-15 15:10:09 +03:00
" resources-sampled " : ( vmmLibvirtObject . RUN_FIRST , None , [ ] ) ,
" inspection-changed " : ( vmmLibvirtObject . RUN_FIRST , None , [ ] ) ,
" pre-startup " : ( vmmLibvirtObject . RUN_FIRST , None , [ object ] ) ,
2012-05-14 17:24:56 +04:00
}
2013-07-07 16:42:57 +04:00
def __init__ ( self , conn , backend , key ) :
2013-10-01 01:11:22 +04:00
vmmLibvirtObject . __init__ ( self , conn , backend , key , Guest )
2010-02-26 03:35:01 +03:00
2010-05-13 18:37:31 +04:00
self . cloning = False
2007-04-12 23:36:04 +04:00
2010-05-13 19:21:01 +04:00
self . _install_abort = False
2011-04-10 06:40:22 +04:00
self . _id = None
2014-06-03 01:17:47 +04:00
self . _uuid = None
2014-09-12 02:01:41 +04:00
self . _has_managed_save = None
Initial snapshot support
This adds initial UI for managing snapshots: list, run/revert, delete,
add, and redefining (for changing <description>) supported, but currently
only for internal snapshots. The UI is mostly in its final form except for
some bells and whistles.
The real remaining question is what do we want to advertise and support.
Internal (qcow2) snapshots are by far the simplest to manage, very
mature, and already have the semantics we want.
However most recent libvirt and qemu work has been to facilitate
external snapshots, which are more extensible and can be performed
live, and with qemu-ga coordination for extra safety. However
they make things much harder for virt-manager at the moment.
Until we have a plan, this work should be considered experimental
and not be relied upon.
2013-08-02 18:18:47 +04:00
self . _snapshot_list = None
2014-09-12 18:15:09 +04:00
self . _autostart = None
2014-09-18 01:25:03 +04:00
self . _domain_caps = None
2015-04-10 01:02:42 +03:00
self . _status_reason = None
2018-09-05 02:02:40 +03:00
self . _ip_cache = None
2011-05-04 00:17:52 +04:00
2010-05-12 20:57:32 +04:00
self . managedsave_supported = False
2018-09-01 04:06:18 +03:00
self . _domain_state_supported = False
2013-12-18 17:42:43 +04:00
2011-07-18 22:53:55 +04:00
self . inspection = vmmInspectionData ( )
Initial snapshot support
This adds initial UI for managing snapshots: list, run/revert, delete,
add, and redefining (for changing <description>) supported, but currently
only for internal snapshots. The UI is mostly in its final form except for
some bells and whistles.
The real remaining question is what do we want to advertise and support.
Internal (qcow2) snapshots are by far the simplest to manage, very
mature, and already have the semantics we want.
However most recent libvirt and qemu work has been to facilitate
external snapshots, which are more extensible and can be performed
live, and with qemu-ga coordination for extra safety. However
they make things much harder for virt-manager at the moment.
Until we have a plan, this work should be considered experimental
and not be relied upon.
2013-08-02 18:18:47 +04:00
def _cleanup ( self ) :
for snap in self . _snapshot_list or [ ] :
snap . cleanup ( )
self . _snapshot_list = None
2018-03-15 14:43:56 +03:00
vmmLibvirtObject . _cleanup ( self )
Initial snapshot support
This adds initial UI for managing snapshots: list, run/revert, delete,
add, and redefining (for changing <description>) supported, but currently
only for internal snapshots. The UI is mostly in its final form except for
some bells and whistles.
The real remaining question is what do we want to advertise and support.
Internal (qcow2) snapshots are by far the simplest to manage, very
mature, and already have the semantics we want.
However most recent libvirt and qemu work has been to facilitate
external snapshots, which are more extensible and can be performed
live, and with qemu-ga coordination for extra safety. However
they make things much harder for virt-manager at the moment.
Until we have a plan, this work should be considered experimental
and not be relied upon.
2013-08-02 18:18:47 +04:00
2015-04-10 21:08:25 +03:00
def _init_libvirt_state ( self ) :
2019-06-07 23:06:52 +03:00
self . managedsave_supported = self . conn . support . domain_managed_save ( self . _backend )
self . _domain_state_supported = self . conn . support . domain_state ( self . _backend )
2011-06-21 19:04:48 +04:00
2011-05-04 00:17:52 +04:00
# Determine available XML flags (older libvirt versions will error
# out if passed SECURE_XML, INACTIVE_XML, etc)
( self . _inactive_xml_flags ,
2011-07-23 00:43:26 +04:00
self . _active_xml_flags ) = self . conn . get_dom_flags ( self . _backend )
2011-05-04 00:17:52 +04:00
2015-04-10 21:08:25 +03:00
# Prime caches
2015-04-19 16:26:16 +03:00
info = self . _backend . info ( )
self . _refresh_status ( newstatus = info [ 0 ] )
2015-04-10 21:08:25 +03:00
self . has_managed_save ( )
self . snapshots_supported ( )
2015-09-17 23:06:14 +03:00
if ( self . get_name ( ) == " Domain-0 " and
self . get_uuid ( ) == " 00000000-0000-0000-0000-000000000000 " ) :
# We don't want virt-manager to track Domain-0 since it
# doesn't work with our UI. Raising an error will ensures it
# is blacklisted.
raise RuntimeError ( " Can ' t track Domain-0 as a vmmDomain " )
2013-05-13 14:14:11 +04:00
self . connect ( " pre-startup " , self . _prestartup_nodedev_check )
def _prestartup_nodedev_check ( self , src , ret ) :
ignore = src
2013-05-28 04:04:55 +04:00
error = _ ( " There is more than one ' %s ' device attached to "
2013-05-13 14:14:11 +04:00
" your host, and we can ' t determine which one to "
" use for your guest. \n "
" To fix this, remove and reattach the USB device "
" to your guest using the ' Add Hardware ' wizard. " )
2019-06-05 21:38:12 +03:00
usb_nodedevs = self . conn . filter_nodedevs ( " usb_device " )
2018-03-21 21:42:50 +03:00
for hostdev in self . xmlobj . devices . hostdev :
2013-05-13 14:14:11 +04:00
devtype = hostdev . type
if devtype != " usb " :
continue
vendor = hostdev . vendor
product = hostdev . product
bus = hostdev . bus
device = hostdev . device
2019-06-05 21:38:12 +03:00
if not vendor or not product :
continue
count = len ( [ d for d in usb_nodedevs if
( d . xmlobj . vendor_id == vendor and
d . xmlobj . product_id == product ) ] )
if count > 1 and not ( bus and device ) :
prettyname = " %s %s " % ( vendor , product )
ret . append ( error % prettyname )
2011-05-04 00:17:52 +04:00
Initial snapshot support
This adds initial UI for managing snapshots: list, run/revert, delete,
add, and redefining (for changing <description>) supported, but currently
only for internal snapshots. The UI is mostly in its final form except for
some bells and whistles.
The real remaining question is what do we want to advertise and support.
Internal (qcow2) snapshots are by far the simplest to manage, very
mature, and already have the semantics we want.
However most recent libvirt and qemu work has been to facilitate
external snapshots, which are more extensible and can be performed
live, and with qemu-ga coordination for extra safety. However
they make things much harder for virt-manager at the moment.
Until we have a plan, this work should be considered experimental
and not be relied upon.
2013-08-02 18:18:47 +04:00
2011-05-04 00:17:52 +04:00
###########################
# Misc API getter methods #
###########################
2011-03-23 23:56:12 +03:00
2015-04-10 19:52:42 +03:00
def reports_stats ( self ) :
return True
2014-02-11 21:07:13 +04:00
def _using_events ( self ) :
return self . conn . using_domain_events
2010-02-07 20:10:41 +03:00
def get_id ( self ) :
2012-11-08 17:15:02 +04:00
if self . _id is None :
2011-05-04 00:17:52 +04:00
self . _id = self . _backend . ID ( )
return self . _id
2008-12-17 23:27:06 +03:00
2011-05-04 00:17:52 +04:00
def status ( self ) :
2015-04-10 01:02:42 +03:00
return self . _normalize_status ( self . _get_status ( ) )
2008-12-17 23:27:06 +03:00
2014-03-18 18:04:59 +04:00
def status_reason ( self ) :
2015-04-10 01:02:42 +03:00
if self . _status_reason is None :
self . _status_reason = 1
2018-09-01 04:06:18 +03:00
if self . _domain_state_supported :
2015-04-10 01:02:42 +03:00
self . _status_reason = self . _backend . state ( ) [ 1 ]
return self . _status_reason
2014-03-18 18:04:59 +04:00
2010-05-13 18:37:31 +04:00
def get_cloning ( self ) :
return self . cloning
def set_cloning ( self , val ) :
self . cloning = bool ( val )
2010-05-13 19:21:01 +04:00
# If manual shutdown or destroy specified, make sure we don't continue
# install process
def get_install_abort ( self ) :
return bool ( self . _install_abort )
2013-07-01 22:33:59 +04:00
def has_spicevmc_type_redirdev ( self ) :
2018-03-21 21:42:50 +03:00
devs = self . xmlobj . devices . redirdev
2013-07-01 22:33:59 +04:00
for dev in devs :
if dev . type == " spicevmc " :
return True
return False
2011-05-04 00:17:52 +04:00
def get_id_pretty ( self ) :
i = self . get_id ( )
if i < 0 :
return " - "
return str ( i )
2017-03-06 11:43:10 +03:00
def has_nvram ( self ) :
return bool ( self . get_xmlobj ( ) . os . loader_ro is True and
self . get_xmlobj ( ) . os . loader_type == " pflash " )
2017-11-24 19:26:59 +03:00
def is_persistent ( self ) :
return bool ( self . _backend . isPersistent ( ) )
2013-10-01 04:33:42 +04:00
##################
# Support checks #
##################
def _get_getjobinfo_supported ( self ) :
2019-06-07 23:06:52 +03:00
return self . conn . support . domain_job_info ( self . _backend )
2013-10-01 04:33:42 +04:00
getjobinfo_supported = property ( _get_getjobinfo_supported )
def snapshots_supported ( self ) :
2019-06-07 23:06:52 +03:00
if not self . conn . support . domain_list_snapshots ( self . _backend ) :
2013-10-01 04:33:42 +04:00
return _ ( " Libvirt connection does not support snapshots. " )
if self . list_snapshots ( ) :
return
# Check if our disks are all qcow2
seen_qcow2 = False
2018-03-21 21:42:50 +03:00
for disk in self . get_disk_devices_norefresh ( ) :
2013-10-01 04:33:42 +04:00
if disk . read_only :
continue
if not disk . path :
continue
if disk . driver_type == " qcow2 " :
seen_qcow2 = True
continue
return _ ( " Snapshots are only supported if all writeable disks "
" images allocated to the guest are qcow2 format. " )
if not seen_qcow2 :
return _ ( " Snapshots require at least one writeable qcow2 disk "
" image allocated to the guest. " )
2014-09-18 01:25:03 +04:00
def get_domain_capabilities ( self ) :
if not self . _domain_caps :
2015-02-18 23:16:48 +03:00
self . _domain_caps = DomainCapabilities . build_from_guest (
self . get_xmlobj ( ) )
2014-09-18 01:25:03 +04:00
return self . _domain_caps
Initial snapshot support
This adds initial UI for managing snapshots: list, run/revert, delete,
add, and redefining (for changing <description>) supported, but currently
only for internal snapshots. The UI is mostly in its final form except for
some bells and whistles.
The real remaining question is what do we want to advertise and support.
Internal (qcow2) snapshots are by far the simplest to manage, very
mature, and already have the semantics we want.
However most recent libvirt and qemu work has been to facilitate
external snapshots, which are more extensible and can be performed
live, and with qemu-ga coordination for extra safety. However
they make things much harder for virt-manager at the moment.
Until we have a plan, this work should be considered experimental
and not be relied upon.
2013-08-02 18:18:47 +04:00
2011-05-04 00:17:52 +04:00
#############################
# Internal XML handling API #
#############################
2010-11-30 01:28:52 +03:00
2010-09-09 01:53:51 +04:00
def _invalidate_xml ( self ) :
vmmLibvirtObject . _invalidate_xml ( self )
2011-04-11 19:55:20 +04:00
self . _id = None
2015-04-10 01:02:42 +03:00
self . _status_reason = None
self . _has_managed_save = None
2010-09-09 01:53:51 +04:00
2015-04-11 00:14:08 +03:00
def _lookup_device_to_define ( self , xmlobj , origdev , for_hotplug ) :
if for_hotplug :
return origdev
2014-02-10 01:21:26 +04:00
2019-02-08 01:36:10 +03:00
dev = xmlobj . find_device ( origdev )
2010-09-09 01:53:51 +04:00
if dev :
2014-02-10 01:21:26 +04:00
return dev
2010-09-09 01:53:51 +04:00
# If we are removing multiple dev from an active VM, a double
# attempt may result in a lookup failure. If device is present
# in the active XML, assume all is good.
2019-02-08 01:36:10 +03:00
if self . get_xmlobj ( ) . find_device ( origdev ) :
2010-12-10 17:57:42 +03:00
logging . debug ( " Device in active config but not inactive config. " )
2010-09-09 01:53:51 +04:00
return
raise RuntimeError ( _ ( " Could not find specified device in the "
" inactive VM configuration: %s " ) % repr ( origdev ) )
2017-03-06 11:43:10 +03:00
def _copy_nvram_file ( self , new_name ) :
"""
We need to do this copy magic because there is no Libvirt storage API
to rename storage volume .
"""
2018-03-20 19:18:35 +03:00
old_nvram = DeviceDisk ( self . conn . get_backend ( ) )
2017-03-06 11:43:10 +03:00
old_nvram . path = self . get_xmlobj ( ) . os . nvram
nvram_dir = os . path . dirname ( old_nvram . path )
new_nvram_path = os . path . join ( nvram_dir , " %s _VARS.fd " % new_name )
2018-03-20 19:18:35 +03:00
new_nvram = DeviceDisk ( self . conn . get_backend ( ) )
2017-03-06 11:43:10 +03:00
2018-03-20 19:18:35 +03:00
nvram_install = DeviceDisk . build_vol_install (
2017-03-08 22:20:41 +03:00
self . conn . get_backend ( ) , os . path . basename ( new_nvram_path ) ,
old_nvram . get_parent_pool ( ) , old_nvram . get_size ( ) , False )
2017-03-06 11:43:10 +03:00
nvram_install . input_vol = old_nvram . get_vol_object ( )
nvram_install . sync_input_vol ( only_format = True )
new_nvram . set_vol_install ( nvram_install )
new_nvram . validate ( )
2018-09-03 23:44:38 +03:00
new_nvram . build_storage ( None )
2017-03-06 11:43:10 +03:00
return new_nvram , old_nvram
2011-05-04 00:17:52 +04:00
##############################
# Persistent XML change APIs #
##############################
2017-03-06 11:43:10 +03:00
def rename_domain ( self , new_name ) :
new_nvram = None
old_nvram = None
if self . has_nvram ( ) :
2017-03-08 21:21:28 +03:00
new_nvram , old_nvram = self . _copy_nvram_file ( new_name )
2017-03-06 11:43:10 +03:00
try :
self . define_name ( new_name )
except Exception as error :
if new_nvram :
try :
new_nvram . get_vol_object ( ) . delete ( 0 )
except Exception as warn :
logging . debug ( " rename failed and new nvram was not "
" removed: ' %s ' " , warn )
raise error
if new_nvram :
try :
old_nvram . get_vol_object ( ) . delete ( 0 )
except Exception as warn :
logging . debug ( " old nvram file was not removed: ' %s ' " , warn )
self . define_overview ( nvram = new_nvram . path )
2011-05-04 00:17:52 +04:00
# Device Add/Remove
2010-09-09 01:53:51 +04:00
def add_device ( self , devobj ) :
"""
Redefine guest with appended device XML ' devxml '
"""
2015-04-11 00:23:11 +03:00
xmlobj = self . _make_xmlobj_to_define ( )
2015-04-07 21:53:28 +03:00
xmlobj . add_device ( devobj )
2015-04-11 00:23:11 +03:00
self . _redefine_xmlobj ( xmlobj )
2010-09-09 01:53:51 +04:00
def remove_device ( self , devobj ) :
"""
Remove passed device from the inactive guest XML
"""
2018-03-21 21:42:50 +03:00
# If serial and duplicate console are both present, they both need
2010-09-09 01:53:51 +04:00
# to be removed at the same time
con = None
2018-03-21 21:42:50 +03:00
if self . serial_is_console_dup ( devobj ) :
2018-06-07 17:55:58 +03:00
con = self . xmlobj . devices . console [ 0 ]
2010-09-09 01:53:51 +04:00
2015-04-11 00:23:11 +03:00
xmlobj = self . _make_xmlobj_to_define ( )
2015-04-11 00:14:08 +03:00
editdev = self . _lookup_device_to_define ( xmlobj , devobj , False )
if not editdev :
return
2010-09-09 01:53:51 +04:00
2015-04-11 00:14:08 +03:00
if con :
2019-02-08 01:36:10 +03:00
rmcon = xmlobj . find_device ( con )
2015-04-11 00:14:08 +03:00
if rmcon :
xmlobj . remove_device ( rmcon )
xmlobj . remove_device ( editdev )
2010-09-09 01:53:51 +04:00
2015-04-11 00:23:11 +03:00
self . _redefine_xmlobj ( xmlobj )
2010-09-09 01:53:51 +04:00
2014-03-22 22:34:23 +04:00
def define_cpu ( self , vcpus = _SENTINEL , maxvcpus = _SENTINEL ,
2019-04-03 16:23:20 +03:00
model = _SENTINEL , secure = _SENTINEL , sockets = _SENTINEL ,
2017-09-20 10:36:27 +03:00
cores = _SENTINEL , threads = _SENTINEL ) :
2015-04-11 00:23:11 +03:00
guest = self . _make_xmlobj_to_define ( )
2014-03-22 22:34:23 +04:00
2015-04-07 21:53:28 +03:00
if vcpus != _SENTINEL :
2019-05-12 02:15:07 +03:00
guest . vcpu_current = int ( vcpus )
2015-04-07 21:53:28 +03:00
if maxvcpus != _SENTINEL :
guest . vcpus = int ( maxvcpus )
if sockets != _SENTINEL :
guest . cpu . sockets = sockets
guest . cpu . cores = cores
guest . cpu . threads = threads
2019-04-03 16:23:20 +03:00
if secure != _SENTINEL or model != _SENTINEL :
guest . cpu . secure = secure
2015-04-07 21:53:28 +03:00
if model in guest . cpu . SPECIAL_MODES :
2018-10-04 21:19:32 +03:00
guest . cpu . set_special_mode ( guest , model )
2015-04-07 21:53:28 +03:00
else :
2019-03-14 12:48:21 +03:00
guest . cpu . set_model ( guest , model )
2015-04-11 00:23:11 +03:00
self . _redefine_xmlobj ( guest )
2010-12-17 00:05:55 +03:00
2014-03-22 22:34:23 +04:00
def define_memory ( self , memory = _SENTINEL , maxmem = _SENTINEL ) :
2015-04-11 00:23:11 +03:00
guest = self . _make_xmlobj_to_define ( )
2015-04-07 21:53:28 +03:00
if memory != _SENTINEL :
2019-05-11 20:34:21 +03:00
guest . currentMemory = int ( memory )
2015-04-07 21:53:28 +03:00
if maxmem != _SENTINEL :
2019-05-11 20:34:21 +03:00
guest . memory = int ( maxmem )
2015-04-11 00:23:11 +03:00
self . _redefine_xmlobj ( guest )
2009-09-25 17:52:03 +04:00
2014-03-22 22:34:23 +04:00
def define_overview ( self , machine = _SENTINEL , description = _SENTINEL ,
2017-09-20 10:36:27 +03:00
title = _SENTINEL , idmap_list = _SENTINEL , loader = _SENTINEL ,
nvram = _SENTINEL ) :
2015-04-11 00:23:11 +03:00
guest = self . _make_xmlobj_to_define ( )
2015-04-07 21:53:28 +03:00
if machine != _SENTINEL :
guest . os . machine = machine
2017-09-19 11:40:09 +03:00
self . _domain_caps = None
2015-04-07 21:53:28 +03:00
if description != _SENTINEL :
guest . description = description or None
if title != _SENTINEL :
guest . title = title or None
if loader != _SENTINEL :
if loader is None :
# Implies seabios, aka the default, so clear everything
guest . os . loader = None
guest . os . loader_ro = None
guest . os . loader_type = None
guest . os . nvram = None
guest . os . nvram_template = None
else :
# Implies UEFI
2018-09-12 20:43:56 +03:00
guest . set_uefi_path ( loader )
2015-04-07 21:53:28 +03:00
2017-03-06 11:43:10 +03:00
if nvram != _SENTINEL :
guest . os . nvram = nvram
2015-04-07 21:53:28 +03:00
if idmap_list != _SENTINEL :
if idmap_list is not None :
# pylint: disable=unpacking-non-sequence
( uid_target , uid_count , gid_target , gid_count ) = idmap_list
guest . idmap . uid_start = 0
guest . idmap . uid_target = uid_target
guest . idmap . uid_count = uid_count
guest . idmap . gid_start = 0
guest . idmap . gid_target = gid_target
guest . idmap . gid_count = gid_count
else :
guest . idmap . clear ( )
2009-09-25 17:52:03 +04:00
2015-04-11 00:23:11 +03:00
self . _redefine_xmlobj ( guest )
2013-09-24 14:57:32 +04:00
2018-09-29 23:04:05 +03:00
def define_os ( self , os_name = _SENTINEL ) :
guest = self . _make_xmlobj_to_define ( )
if os_name != _SENTINEL :
guest . set_os_name ( os_name )
self . _redefine_xmlobj ( guest )
2014-03-22 22:34:23 +04:00
def define_boot ( self , boot_order = _SENTINEL , boot_menu = _SENTINEL ,
2018-12-18 16:45:00 +03:00
kernel = _SENTINEL , initrd = _SENTINEL , dtb = _SENTINEL ,
kernel_args = _SENTINEL , init = _SENTINEL , initargs = _SENTINEL ) :
2014-02-10 01:21:26 +04:00
2015-04-11 00:23:11 +03:00
guest = self . _make_xmlobj_to_define ( )
2015-04-07 21:53:28 +03:00
if boot_order != _SENTINEL :
2019-02-06 12:55:41 +03:00
legacy = not self . can_use_device_boot_order ( )
guest . set_boot_order ( boot_order , legacy = legacy )
2015-04-07 21:53:28 +03:00
if boot_menu != _SENTINEL :
guest . os . enable_bootmenu = bool ( boot_menu )
if init != _SENTINEL :
guest . os . init = init
guest . os . set_initargs_string ( initargs )
if kernel != _SENTINEL :
guest . os . kernel = kernel or None
if initrd != _SENTINEL :
guest . os . initrd = initrd or None
if dtb != _SENTINEL :
guest . os . dtb = dtb or None
if kernel_args != _SENTINEL :
guest . os . kernel_args = kernel_args or None
2015-04-11 00:23:11 +03:00
self . _redefine_xmlobj ( guest )
2010-09-09 01:53:51 +04:00
2015-04-11 00:14:08 +03:00
######################
# Device XML editing #
######################
def define_disk ( self , devobj , do_hotplug ,
2017-09-20 10:36:27 +03:00
path = _SENTINEL , readonly = _SENTINEL , serial = _SENTINEL ,
shareable = _SENTINEL , removable = _SENTINEL , cache = _SENTINEL ,
2018-08-24 02:40:18 +03:00
io = _SENTINEL , discard = _SENTINEL , detect_zeroes = _SENTINEL ,
2018-08-24 02:38:07 +03:00
driver_type = _SENTINEL , bus = _SENTINEL , addrstr = _SENTINEL ,
2018-10-10 12:50:34 +03:00
sgio = _SENTINEL , managed_pr = _SENTINEL ) :
2015-04-11 00:23:11 +03:00
xmlobj = self . _make_xmlobj_to_define ( )
2015-04-11 00:14:08 +03:00
editdev = self . _lookup_device_to_define ( xmlobj , devobj , do_hotplug )
if not editdev :
return
def _change_bus ( ) :
2012-01-30 00:38:33 +04:00
oldprefix = editdev . get_target_prefix ( ) [ 0 ]
oldbus = editdev . bus
2014-03-22 22:34:23 +04:00
editdev . bus = bus
2012-01-30 00:32:25 +04:00
2014-03-22 22:34:23 +04:00
if oldbus == bus :
2012-01-30 00:32:25 +04:00
return
editdev . address . clear ( )
2014-03-22 22:34:23 +04:00
editdev . address . set_addrstr ( addrstr )
2012-01-30 00:32:25 +04:00
2012-01-30 00:38:33 +04:00
if oldprefix == editdev . get_target_prefix ( ) [ 0 ] :
return
2012-01-30 00:32:25 +04:00
used = [ ]
2018-03-21 21:42:50 +03:00
disks = ( self . xmlobj . devices . disk +
self . get_xmlobj ( inactive = True ) . devices . disk )
2012-01-30 00:32:25 +04:00
for d in disks :
used . append ( d . target )
if editdev . target :
used . remove ( editdev . target )
editdev . target = None
editdev . generate_target ( used )
2009-09-25 17:52:03 +04:00
2015-04-11 00:14:08 +03:00
if path != _SENTINEL :
editdev . path = path
if not do_hotplug :
editdev . sync_path_props ( )
if readonly != _SENTINEL :
editdev . read_only = readonly
if shareable != _SENTINEL :
editdev . shareable = shareable
if removable != _SENTINEL :
editdev . removable = removable
if cache != _SENTINEL :
editdev . driver_cache = cache or None
if io != _SENTINEL :
editdev . driver_io = io or None
2018-08-24 02:38:07 +03:00
if discard != _SENTINEL :
editdev . driver_discard = discard or None
2018-08-24 02:40:18 +03:00
if detect_zeroes != _SENTINEL :
editdev . driver_detect_zeroes = detect_zeroes or None
2015-04-11 00:14:08 +03:00
if driver_type != _SENTINEL :
editdev . driver_type = driver_type or None
if serial != _SENTINEL :
editdev . serial = serial or None
if sgio != _SENTINEL :
editdev . sgio = sgio or None
2018-10-10 12:50:34 +03:00
if managed_pr != _SENTINEL :
editdev . reservations_managed = " yes " if managed_pr else None
2015-04-11 00:14:08 +03:00
if bus != _SENTINEL :
_change_bus ( )
if do_hotplug :
2015-08-11 01:30:12 +03:00
self . hotplug ( device = editdev )
2015-04-11 00:14:08 +03:00
else :
2015-04-11 00:23:11 +03:00
self . _redefine_xmlobj ( xmlobj )
2015-04-11 00:14:08 +03:00
def define_network ( self , devobj , do_hotplug ,
2017-09-20 10:36:27 +03:00
ntype = _SENTINEL , source = _SENTINEL ,
mode = _SENTINEL , model = _SENTINEL , addrstr = _SENTINEL ,
vtype = _SENTINEL , managerid = _SENTINEL , typeid = _SENTINEL ,
typeidversion = _SENTINEL , instanceid = _SENTINEL ,
2018-08-16 18:30:31 +03:00
portgroup = _SENTINEL , macaddr = _SENTINEL , linkstate = _SENTINEL ) :
2015-04-11 00:23:11 +03:00
xmlobj = self . _make_xmlobj_to_define ( )
2015-04-11 00:14:08 +03:00
editdev = self . _lookup_device_to_define ( xmlobj , devobj , do_hotplug )
if not editdev :
return
if ntype != _SENTINEL :
editdev . source = None
editdev . type = ntype
editdev . source = source
editdev . source_mode = mode or None
editdev . portgroup = portgroup or None
if model != _SENTINEL :
if editdev . model != model :
editdev . address . clear ( )
editdev . address . set_addrstr ( addrstr )
editdev . model = model
2013-02-17 17:40:37 +04:00
2015-04-11 00:14:08 +03:00
if vtype != _SENTINEL :
editdev . virtualport . type = vtype or None
editdev . virtualport . managerid = managerid or None
editdev . virtualport . typeid = typeid or None
editdev . virtualport . typeidversion = typeidversion or None
editdev . virtualport . instanceid = instanceid or None
if macaddr != _SENTINEL :
editdev . macaddr = macaddr
2018-08-16 18:30:31 +03:00
if linkstate != _SENTINEL :
editdev . link_state = " up " if linkstate else " down "
2015-04-11 00:14:08 +03:00
if do_hotplug :
self . hotplug ( device = editdev )
else :
2015-04-11 00:23:11 +03:00
self . _redefine_xmlobj ( xmlobj )
2015-04-11 00:14:08 +03:00
def define_graphics ( self , devobj , do_hotplug ,
2017-09-20 10:36:27 +03:00
listen = _SENTINEL , addr = _SENTINEL , port = _SENTINEL , tlsport = _SENTINEL ,
passwd = _SENTINEL , keymap = _SENTINEL , gtype = _SENTINEL ,
gl = _SENTINEL , rendernode = _SENTINEL ) :
2015-04-11 00:23:11 +03:00
xmlobj = self . _make_xmlobj_to_define ( )
2015-04-11 00:14:08 +03:00
editdev = self . _lookup_device_to_define ( xmlobj , devobj , do_hotplug )
if not editdev :
return
2019-02-22 18:32:39 +03:00
if addr != _SENTINEL or listen != _SENTINEL :
if listen == " none " :
editdev . listen = listen
else :
editdev . listen = addr
2015-04-11 00:14:08 +03:00
if port != _SENTINEL :
editdev . port = port
if tlsport != _SENTINEL :
editdev . tlsPort = tlsport
if passwd != _SENTINEL :
editdev . passwd = passwd
if keymap != _SENTINEL :
editdev . keymap = keymap
if gtype != _SENTINEL :
editdev . type = gtype
2017-02-21 16:00:56 +03:00
if gl != _SENTINEL :
editdev . gl = gl
2017-02-21 16:01:01 +03:00
if rendernode != _SENTINEL :
editdev . rendernode = rendernode
2015-04-11 00:14:08 +03:00
if do_hotplug :
self . hotplug ( device = editdev )
else :
2015-04-11 00:23:11 +03:00
self . _redefine_xmlobj ( xmlobj )
2011-05-19 20:13:20 +04:00
2015-04-11 00:14:08 +03:00
def define_sound ( self , devobj , do_hotplug , model = _SENTINEL ) :
2015-04-11 00:23:11 +03:00
xmlobj = self . _make_xmlobj_to_define ( )
2015-04-11 00:14:08 +03:00
editdev = self . _lookup_device_to_define ( xmlobj , devobj , do_hotplug )
if not editdev :
return
if model != _SENTINEL :
if editdev . model != model :
editdev . address . clear ( )
editdev . model = model
if do_hotplug :
self . hotplug ( device = editdev )
else :
2015-04-11 00:23:11 +03:00
self . _redefine_xmlobj ( xmlobj )
2015-04-11 00:14:08 +03:00
2017-02-21 16:01:02 +03:00
def define_video ( self , devobj , do_hotplug , model = _SENTINEL , accel3d = _SENTINEL ) :
2015-04-11 00:23:11 +03:00
xmlobj = self . _make_xmlobj_to_define ( )
2015-04-11 00:14:08 +03:00
editdev = self . _lookup_device_to_define ( xmlobj , devobj , do_hotplug )
if not editdev :
return
if model != _SENTINEL and model != editdev . model :
2014-03-22 22:34:23 +04:00
editdev . model = model
2012-01-30 00:40:53 +04:00
editdev . address . clear ( )
2011-05-04 20:45:27 +04:00
# Clear out heads/ram values so they reset to default. If
# we ever allow editing these values in the UI we should
# drop this
editdev . vram = None
editdev . heads = None
2013-05-28 02:50:25 +04:00
editdev . ram = None
2014-12-01 17:56:29 +03:00
editdev . vgamem = None
2017-02-21 16:01:02 +03:00
editdev . accel3d = None
if accel3d != _SENTINEL :
editdev . accel3d = accel3d
2011-05-04 20:45:27 +04:00
2015-04-11 00:14:08 +03:00
if do_hotplug :
self . hotplug ( device = editdev )
else :
2015-04-11 00:23:11 +03:00
self . _redefine_xmlobj ( xmlobj )
2009-09-25 17:52:03 +04:00
2015-04-11 00:14:08 +03:00
def define_watchdog ( self , devobj , do_hotplug ,
2017-09-20 10:36:27 +03:00
model = _SENTINEL , action = _SENTINEL ) :
2015-04-11 00:23:11 +03:00
xmlobj = self . _make_xmlobj_to_define ( )
2015-04-11 00:14:08 +03:00
editdev = self . _lookup_device_to_define ( xmlobj , devobj , do_hotplug )
if not editdev :
return
if model != _SENTINEL :
if editdev . model != model :
editdev . address . clear ( )
editdev . model = model
if action != _SENTINEL :
editdev . action = action
if do_hotplug :
self . hotplug ( device = editdev )
else :
2015-04-11 00:23:11 +03:00
self . _redefine_xmlobj ( xmlobj )
2015-04-11 00:14:08 +03:00
def define_smartcard ( self , devobj , do_hotplug , model = _SENTINEL ) :
2015-04-11 00:23:11 +03:00
xmlobj = self . _make_xmlobj_to_define ( )
2015-04-11 00:14:08 +03:00
editdev = self . _lookup_device_to_define ( xmlobj , devobj , do_hotplug )
if not editdev :
return
if model != _SENTINEL :
editdev . mode = model
2018-09-02 02:58:24 +03:00
editdev . type = None
editdev . type = editdev . default_type ( )
2015-04-11 00:14:08 +03:00
if do_hotplug :
self . hotplug ( device = editdev )
else :
2015-04-11 00:23:11 +03:00
self . _redefine_xmlobj ( xmlobj )
2015-04-11 00:14:08 +03:00
def define_controller ( self , devobj , do_hotplug , model = _SENTINEL ) :
2015-04-11 00:23:11 +03:00
xmlobj = self . _make_xmlobj_to_define ( )
2015-04-11 00:14:08 +03:00
editdev = self . _lookup_device_to_define ( xmlobj , devobj , do_hotplug )
if not editdev :
return
def _change_model ( ) :
2014-01-22 07:46:06 +04:00
if editdev . type == " usb " :
2018-03-21 00:23:34 +03:00
ctrls = xmlobj . devices . controller
2014-01-22 07:46:06 +04:00
ctrls = [ x for x in ctrls if ( x . type ==
2018-03-20 19:18:35 +03:00
DeviceController . TYPE_USB ) ]
2014-01-22 07:46:06 +04:00
for dev in ctrls :
2015-05-19 20:21:36 +03:00
xmlobj . remove_device ( dev )
2014-01-22 07:46:06 +04:00
2014-03-22 22:34:23 +04:00
if model == " ich9-ehci1 " :
2018-03-20 19:18:35 +03:00
for dev in DeviceController . get_usb2_controllers (
2015-05-19 20:21:36 +03:00
xmlobj . conn ) :
xmlobj . add_device ( dev )
2018-10-04 16:53:36 +03:00
elif model == " usb3 " :
dev = DeviceController . get_usb3_controller (
xmlobj . conn , xmlobj )
xmlobj . add_device ( dev )
2014-01-22 07:46:06 +04:00
else :
2018-03-20 19:18:35 +03:00
dev = DeviceController ( xmlobj . conn )
2014-01-22 07:46:06 +04:00
dev . type = " usb "
2015-05-19 19:50:39 +03:00
dev . model = model
2015-05-19 20:21:36 +03:00
xmlobj . add_device ( dev )
2014-03-22 22:34:23 +04:00
2015-05-19 19:50:39 +03:00
else :
editdev . model = model
2016-12-12 15:18:50 +03:00
editdev . address . clear ( )
2014-03-22 22:34:23 +04:00
self . hotplug ( device = editdev )
2011-09-23 19:14:15 +04:00
2015-04-11 00:14:08 +03:00
if model != _SENTINEL :
_change_model ( )
2014-03-22 22:34:23 +04:00
2015-04-11 00:14:08 +03:00
if do_hotplug :
self . hotplug ( device = editdev )
else :
2015-04-11 00:23:11 +03:00
self . _redefine_xmlobj ( xmlobj )
2011-09-23 19:14:15 +04:00
2015-04-11 00:14:08 +03:00
def define_filesystem ( self , devobj , do_hotplug , newdev = _SENTINEL ) :
2015-04-11 00:23:11 +03:00
xmlobj = self . _make_xmlobj_to_define ( )
2015-04-11 00:14:08 +03:00
editdev = self . _lookup_device_to_define ( xmlobj , devobj , do_hotplug )
if not editdev :
return
2014-03-22 22:34:23 +04:00
2015-04-11 00:14:08 +03:00
if newdev != _SENTINEL :
2014-03-22 22:34:23 +04:00
# pylint: disable=maybe-no-member
2014-01-21 13:05:31 +04:00
editdev . type = newdev . type
2015-11-19 05:12:35 +03:00
editdev . accessmode = newdev . accessmode
2014-01-21 13:05:31 +04:00
editdev . wrpolicy = newdev . wrpolicy
editdev . driver = newdev . driver
editdev . format = newdev . format
editdev . readonly = newdev . readonly
editdev . units = newdev . units
editdev . source = newdev . source
editdev . target = newdev . target
2015-04-11 00:14:08 +03:00
if do_hotplug :
self . hotplug ( device = editdev )
2015-09-20 23:48:30 +03:00
else :
self . _redefine_xmlobj ( xmlobj )
2015-04-11 00:14:08 +03:00
def define_hostdev ( self , devobj , do_hotplug , rom_bar = _SENTINEL ) :
2015-04-11 00:23:11 +03:00
xmlobj = self . _make_xmlobj_to_define ( )
2015-04-11 00:14:08 +03:00
editdev = self . _lookup_device_to_define ( xmlobj , devobj , do_hotplug )
if not editdev :
return
2011-09-23 19:14:15 +04:00
2015-04-11 00:14:08 +03:00
if rom_bar != _SENTINEL :
editdev . rom_bar = rom_bar
2014-03-22 22:34:23 +04:00
2015-04-11 00:14:08 +03:00
if do_hotplug :
self . hotplug ( device = editdev )
else :
2015-04-11 00:23:11 +03:00
self . _redefine_xmlobj ( xmlobj )
2014-02-10 23:24:22 +04:00
2018-06-09 00:42:44 +03:00
def define_tpm ( self , devobj , do_hotplug , model = _SENTINEL ) :
xmlobj = self . _make_xmlobj_to_define ( )
editdev = self . _lookup_device_to_define ( xmlobj , devobj , do_hotplug )
if not editdev :
return
if model != _SENTINEL :
editdev . model = model
2018-06-12 15:52:20 +03:00
if do_hotplug :
self . hotplug ( device = editdev )
else :
self . _redefine_xmlobj ( xmlobj )
2018-06-09 00:42:44 +03:00
2018-12-14 17:34:19 +03:00
def define_vsock ( self , devobj , do_hotplug ,
auto_cid = _SENTINEL , cid = _SENTINEL ) :
xmlobj = self . _make_xmlobj_to_define ( )
editdev = self . _lookup_device_to_define ( xmlobj , devobj , do_hotplug )
if not editdev :
return
if auto_cid != _SENTINEL :
editdev . auto_cid = auto_cid
if cid != _SENTINEL :
editdev . cid = cid
if do_hotplug :
self . hotplug ( device = editdev )
else :
self . _redefine_xmlobj ( xmlobj )
2009-09-25 17:52:03 +04:00
2011-05-04 00:17:52 +04:00
####################
# Hotplug routines #
####################
2009-09-25 17:52:03 +04:00
2011-05-04 00:17:52 +04:00
def attach_device ( self , devobj ) :
"""
Hotplug device to running guest
"""
if not self . is_active ( ) :
return
2010-12-13 22:31:27 +03:00
2018-08-31 23:52:02 +03:00
devxml = devobj . get_xml ( )
2015-04-11 00:14:08 +03:00
logging . debug ( " attach_device with xml= \n %s " , devxml )
2011-05-04 00:17:52 +04:00
self . _backend . attachDevice ( devxml )
2010-12-13 22:31:27 +03:00
2011-05-04 00:17:52 +04:00
def detach_device ( self , devobj ) :
"""
Hotunplug device from running guest
"""
if not self . is_active ( ) :
return
2009-09-25 17:52:03 +04:00
2018-08-31 23:52:02 +03:00
devxml = devobj . get_xml ( )
2015-04-11 00:14:08 +03:00
logging . debug ( " detach_device with xml= \n %s " , devxml )
self . _backend . detachDevice ( devxml )
2009-09-25 17:52:03 +04:00
2014-03-22 22:34:23 +04:00
def _update_device ( self , devobj , flags = None ) :
if flags is None :
flags = getattr ( libvirt , " VIR_DOMAIN_DEVICE_MODIFY_LIVE " , 1 )
2009-09-25 17:52:03 +04:00
2018-08-31 23:52:02 +03:00
xml = devobj . get_xml ( )
2015-04-11 00:14:08 +03:00
logging . debug ( " update_device with xml= \n %s " , xml )
2011-05-04 00:17:52 +04:00
self . _backend . updateDeviceFlags ( xml , flags )
2009-09-25 17:52:03 +04:00
2014-03-22 22:34:23 +04:00
def hotplug ( self , vcpus = _SENTINEL , memory = _SENTINEL , maxmem = _SENTINEL ,
2017-09-20 10:36:27 +03:00
description = _SENTINEL , title = _SENTINEL , device = _SENTINEL ) :
2014-03-22 22:34:23 +04:00
if not self . is_active ( ) :
return
def _hotplug_memory ( val ) :
if val != self . get_memory ( ) :
self . _backend . setMemory ( val )
def _hotplug_maxmem ( val ) :
if val != self . maximum_memory ( ) :
self . _backend . setMaxMemory ( val )
2010-05-12 20:57:32 +04:00
2014-03-22 22:34:23 +04:00
def _hotplug_metadata ( val , mtype ) :
flags = ( libvirt . VIR_DOMAIN_AFFECT_LIVE |
libvirt . VIR_DOMAIN_AFFECT_CONFIG )
self . _backend . setMetadata ( mtype , val , None , None , flags )
2011-05-04 00:17:52 +04:00
2014-03-22 22:34:23 +04:00
if vcpus != _SENTINEL :
vcpus = int ( vcpus )
if vcpus != self . vcpu_count ( ) :
self . _backend . setVcpus ( vcpus )
2011-05-04 00:17:52 +04:00
2014-03-22 22:34:23 +04:00
if memory != _SENTINEL :
2019-06-11 21:46:32 +03:00
logging . debug ( " Hotplugging curmem= %s maxmem= %s for VM ' %s ' " ,
2014-03-22 22:34:23 +04:00
memory , maxmem , self . get_name ( ) )
2011-05-04 00:17:52 +04:00
actual_cur = self . get_memory ( )
if memory :
if maxmem < actual_cur :
# Set current first to avoid error
2014-03-22 22:34:23 +04:00
_hotplug_memory ( memory )
_hotplug_maxmem ( maxmem )
2011-05-04 00:17:52 +04:00
else :
2014-03-22 22:34:23 +04:00
_hotplug_maxmem ( maxmem )
_hotplug_memory ( memory )
2011-05-04 00:17:52 +04:00
else :
2014-03-22 22:34:23 +04:00
_hotplug_maxmem ( maxmem )
2012-10-17 01:26:06 +04:00
2014-03-22 22:34:23 +04:00
if description != _SENTINEL :
_hotplug_metadata ( description ,
libvirt . VIR_DOMAIN_METADATA_DESCRIPTION )
if title != _SENTINEL :
_hotplug_metadata ( title , libvirt . VIR_DOMAIN_METADATA_TITLE )
2012-10-17 01:26:06 +04:00
2015-08-11 01:30:12 +03:00
if device != _SENTINEL :
2014-03-22 22:34:23 +04:00
self . _update_device ( device )
2013-09-24 14:57:32 +04:00
2011-05-04 00:17:52 +04:00
########################
# Libvirt API wrappers #
########################
2015-04-10 16:15:44 +03:00
def _conn_tick_poll_param ( self ) :
return " pollvm "
def class_name ( self ) :
return " domain "
2017-06-15 15:18:26 +03:00
def _define ( self , xml ) :
self . conn . define_domain ( xml )
2011-05-04 00:17:52 +04:00
def _XMLDesc ( self , flags ) :
return self . _backend . XMLDesc ( flags )
2015-04-10 01:02:42 +03:00
def _get_backend_status ( self ) :
return self . _backend . info ( ) [ 0 ]
2011-05-04 00:17:52 +04:00
def get_autostart ( self ) :
2014-09-12 18:15:09 +04:00
if self . _autostart is None :
self . _autostart = self . _backend . autostart ( )
return self . _autostart
2011-05-04 00:17:52 +04:00
def set_autostart ( self , val ) :
self . _backend . setAutostart ( val )
2014-09-12 18:15:09 +04:00
# Recache value
self . _autostart = None
self . get_autostart ( )
2011-05-04 00:17:52 +04:00
def job_info ( self ) :
return self . _backend . jobInfo ( )
def abort_job ( self ) :
self . _backend . abortJob ( )
2009-09-25 17:52:03 +04:00
2011-06-21 19:04:48 +04:00
def open_console ( self , devname , stream , flags = 0 ) :
return self . _backend . openConsole ( devname , stream , flags )
2009-09-25 17:52:03 +04:00
2016-03-04 14:31:54 +03:00
def open_graphics_fd ( self ) :
2017-03-23 17:26:19 +03:00
flags = 0
# Ugly workaround for VNC bug where the display cannot be opened
2018-01-16 11:30:50 +03:00
# if the listen type is "none". This bug was fixed in QEMU-2.9.0.
2018-03-21 21:42:50 +03:00
graphics = self . xmlobj . devices . graphics [ 0 ]
2017-03-23 17:26:19 +03:00
if ( graphics . type == " vnc " and
2018-01-16 11:30:50 +03:00
graphics . get_first_listen_type ( ) == " none " and
2019-06-07 23:06:52 +03:00
not self . conn . support . conn_vnc_none_auth ( ) ) :
2017-03-23 17:26:19 +03:00
flags = libvirt . VIR_DOMAIN_OPEN_GRAPHICS_SKIPAUTH
return self . _backend . openGraphicsFD ( 0 , flags )
2016-03-04 14:31:54 +03:00
Initial snapshot support
This adds initial UI for managing snapshots: list, run/revert, delete,
add, and redefining (for changing <description>) supported, but currently
only for internal snapshots. The UI is mostly in its final form except for
some bells and whistles.
The real remaining question is what do we want to advertise and support.
Internal (qcow2) snapshots are by far the simplest to manage, very
mature, and already have the semantics we want.
However most recent libvirt and qemu work has been to facilitate
external snapshots, which are more extensible and can be performed
live, and with qemu-ga coordination for extra safety. However
they make things much harder for virt-manager at the moment.
Until we have a plan, this work should be considered experimental
and not be relied upon.
2013-08-02 18:18:47 +04:00
def list_snapshots ( self ) :
if self . _snapshot_list is None :
newlist = [ ]
for rawsnap in self . _backend . listAllSnapshots ( ) :
2015-04-10 21:08:25 +03:00
obj = vmmDomainSnapshot ( self . conn , rawsnap )
obj . init_libvirt_state ( )
newlist . append ( obj )
Initial snapshot support
This adds initial UI for managing snapshots: list, run/revert, delete,
add, and redefining (for changing <description>) supported, but currently
only for internal snapshots. The UI is mostly in its final form except for
some bells and whistles.
The real remaining question is what do we want to advertise and support.
Internal (qcow2) snapshots are by far the simplest to manage, very
mature, and already have the semantics we want.
However most recent libvirt and qemu work has been to facilitate
external snapshots, which are more extensible and can be performed
live, and with qemu-ga coordination for extra safety. However
they make things much harder for virt-manager at the moment.
Until we have a plan, this work should be considered experimental
and not be relied upon.
2013-08-02 18:18:47 +04:00
self . _snapshot_list = newlist
return self . _snapshot_list [ : ]
2015-04-10 01:27:45 +03:00
@vmmLibvirtObject.lifecycle_action
Initial snapshot support
This adds initial UI for managing snapshots: list, run/revert, delete,
add, and redefining (for changing <description>) supported, but currently
only for internal snapshots. The UI is mostly in its final form except for
some bells and whistles.
The real remaining question is what do we want to advertise and support.
Internal (qcow2) snapshots are by far the simplest to manage, very
mature, and already have the semantics we want.
However most recent libvirt and qemu work has been to facilitate
external snapshots, which are more extensible and can be performed
live, and with qemu-ga coordination for extra safety. However
they make things much harder for virt-manager at the moment.
Until we have a plan, this work should be considered experimental
and not be relied upon.
2013-08-02 18:18:47 +04:00
def revert_to_snapshot ( self , snap ) :
self . _backend . revertToSnapshot ( snap . get_backend ( ) )
def create_snapshot ( self , xml , redefine = False ) :
flags = 0
if redefine :
flags = ( flags | libvirt . VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE )
2018-12-18 16:45:02 +03:00
else :
2013-09-30 22:28:43 +04:00
logging . debug ( " Creating snapshot flags= %s xml= \n %s " , flags , xml )
Initial snapshot support
This adds initial UI for managing snapshots: list, run/revert, delete,
add, and redefining (for changing <description>) supported, but currently
only for internal snapshots. The UI is mostly in its final form except for
some bells and whistles.
The real remaining question is what do we want to advertise and support.
Internal (qcow2) snapshots are by far the simplest to manage, very
mature, and already have the semantics we want.
However most recent libvirt and qemu work has been to facilitate
external snapshots, which are more extensible and can be performed
live, and with qemu-ga coordination for extra safety. However
they make things much harder for virt-manager at the moment.
Until we have a plan, this work should be considered experimental
and not be relied upon.
2013-08-02 18:18:47 +04:00
self . _backend . snapshotCreateXML ( xml , flags )
2018-09-05 02:02:40 +03:00
def refresh_interface_addresses ( self , iface ) :
def agent_ready ( ) :
for dev in self . xmlobj . devices . channel :
if ( dev . type == " unix " and
dev . target_name == dev . CHANNEL_NAME_QEMUGA and
dev . target_state == " connected " ) :
return True
return False
self . _ip_cache = { " qemuga " : { } , " arp " : { } }
if iface . type == " network " :
net = self . conn . get_net ( iface . source )
if net :
net . refresh_dhcp_leases ( )
if not self . is_active ( ) :
return
if agent_ready ( ) :
self . _ip_cache [ " qemuga " ] = self . _get_interface_addresses (
libvirt . VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT )
arp_flag = getattr ( libvirt ,
" VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP " , 3 )
self . _ip_cache [ " arp " ] = self . _get_interface_addresses ( arp_flag )
def _get_interface_addresses ( self , source ) :
logging . debug ( " Calling interfaceAddresses source= %s " , source )
try :
return self . _backend . interfaceAddresses ( source )
except Exception as e :
logging . debug ( " interfaceAddresses failed: %s " , str ( e ) )
return { }
def get_interface_addresses ( self , iface ) :
if self . _ip_cache is None :
self . refresh_interface_addresses ( iface )
qemuga = self . _ip_cache [ " qemuga " ]
arp = self . _ip_cache [ " arp " ]
leases = [ ]
if iface . type == " network " :
net = self . conn . get_net ( iface . source )
if net :
leases = net . get_dhcp_leases ( )
def extract_dom ( info ) :
ipv4 = None
ipv6 = None
for addrs in info . values ( ) :
if addrs [ " hwaddr " ] != iface . macaddr :
continue
2018-09-06 10:46:27 +03:00
if not addrs [ " addrs " ] :
continue
2018-09-05 02:02:40 +03:00
for addr in addrs [ " addrs " ] :
if addr [ " type " ] == 0 :
ipv4 = addr [ " addr " ]
elif ( addr [ " type " ] == 1 and
not str ( addr [ " addr " ] ) . startswith ( " fe80 " ) ) :
ipv6 = addr [ " addr " ] + " / " + str ( addr [ " prefix " ] )
return ipv4 , ipv6
def extract_lease ( info ) :
ipv4 = None
ipv6 = None
if info [ " mac " ] == iface . macaddr :
if info [ " type " ] == 0 :
ipv4 = info [ " ipaddr " ]
2018-12-18 16:45:02 +03:00
elif info [ " type " ] == 1 :
2018-09-05 02:02:40 +03:00
ipv6 = info [ " ipaddr " ]
return ipv4 , ipv6
for ips in ( [ qemuga ] + leases + [ arp ] ) :
if " expirytime " in ips :
ipv4 , ipv6 = extract_lease ( ips )
else :
ipv4 , ipv6 = extract_dom ( ips )
if ipv4 or ipv6 :
return ipv4 , ipv6
return None , None
def refresh_snapshots ( self ) :
self . _snapshot_list = None
Initial snapshot support
This adds initial UI for managing snapshots: list, run/revert, delete,
add, and redefining (for changing <description>) supported, but currently
only for internal snapshots. The UI is mostly in its final form except for
some bells and whistles.
The real remaining question is what do we want to advertise and support.
Internal (qcow2) snapshots are by far the simplest to manage, very
mature, and already have the semantics we want.
However most recent libvirt and qemu work has been to facilitate
external snapshots, which are more extensible and can be performed
live, and with qemu-ga coordination for extra safety. However
they make things much harder for virt-manager at the moment.
Until we have a plan, this work should be considered experimental
and not be relied upon.
2013-08-02 18:18:47 +04:00
2011-05-04 00:17:52 +04:00
########################
# XML Parsing routines #
########################
2011-05-26 20:38:48 +04:00
def is_container ( self ) :
2013-09-23 16:34:50 +04:00
return self . get_xmlobj ( ) . os . is_container ( )
2011-05-26 20:38:48 +04:00
def is_xenpv ( self ) :
2013-09-23 16:34:50 +04:00
return self . get_xmlobj ( ) . os . is_xenpv ( )
2011-05-26 20:38:48 +04:00
def is_hvm ( self ) :
2013-09-23 16:34:50 +04:00
return self . get_xmlobj ( ) . os . is_hvm ( )
2011-05-26 20:38:48 +04:00
2011-05-04 00:17:52 +04:00
def get_uuid ( self ) :
2014-06-03 01:17:47 +04:00
if self . _uuid is None :
self . _uuid = self . _backend . UUIDString ( )
return self . _uuid
2011-05-04 00:17:52 +04:00
def get_abi_type ( self ) :
2013-09-23 16:34:50 +04:00
return self . get_xmlobj ( ) . os . os_type
2011-05-04 00:17:52 +04:00
def get_hv_type ( self ) :
2013-09-23 16:34:50 +04:00
return self . get_xmlobj ( ) . type
2010-02-07 20:10:41 +03:00
def get_pretty_hv_type ( self ) :
2014-01-27 02:42:24 +04:00
return self . conn . pretty_hv ( self . get_abi_type ( ) , self . get_hv_type ( ) )
2010-02-07 20:10:41 +03:00
def get_arch ( self ) :
2013-09-23 16:34:50 +04:00
return self . get_xmlobj ( ) . os . arch
2011-05-26 20:38:48 +04:00
def get_init ( self ) :
2014-06-01 01:34:23 +04:00
import pipes
init = self . get_xmlobj ( ) . os . init
initargs = " " . join (
[ pipes . quote ( i . val ) for i in self . get_xmlobj ( ) . os . initargs ] )
return init , initargs
2010-02-07 20:10:41 +03:00
def get_emulator ( self ) :
2013-09-23 16:34:50 +04:00
return self . get_xmlobj ( ) . emulator
2012-01-05 13:35:40 +04:00
def get_machtype ( self ) :
2013-09-23 16:34:50 +04:00
return self . get_xmlobj ( ) . os . machine
2014-02-21 14:13:10 +04:00
def get_idmap ( self ) :
return self . get_xmlobj ( ) . idmap
2009-09-25 17:52:03 +04:00
2014-02-12 00:03:42 +04:00
def get_name_or_title ( self ) :
title = self . get_title ( )
if title :
return title
return self . get_name ( )
def get_title ( self ) :
2014-09-12 16:57:13 +04:00
return self . get_xmlobj ( ) . title
2010-02-10 20:16:59 +03:00
def get_description ( self ) :
2014-09-12 16:57:13 +04:00
return self . get_xmlobj ( ) . description
2010-02-10 20:16:59 +03:00
2010-11-29 20:55:22 +03:00
def get_memory ( self ) :
2019-05-11 20:34:21 +03:00
return int ( self . get_xmlobj ( ) . currentMemory )
2010-11-29 20:55:22 +03:00
def maximum_memory ( self ) :
2019-05-11 20:34:21 +03:00
return int ( self . get_xmlobj ( ) . memory )
2010-11-29 20:55:22 +03:00
def vcpu_count ( self ) :
2019-05-12 02:15:07 +03:00
return int ( self . get_xmlobj ( ) . vcpu_current or self . get_xmlobj ( ) . vcpus )
2010-02-07 20:10:41 +03:00
def vcpu_max_count ( self ) :
2014-02-12 01:23:51 +04:00
return int ( self . get_xmlobj ( ) . vcpus )
2009-11-15 23:17:03 +03:00
2010-12-17 00:05:55 +03:00
def get_cpu_config ( self ) :
2013-09-23 16:34:50 +04:00
return self . get_xmlobj ( ) . cpu
2010-12-17 00:05:55 +03:00
2014-02-10 01:21:26 +04:00
def get_boot_order ( self ) :
2019-02-06 12:55:40 +03:00
legacy = not self . can_use_device_boot_order ( )
return self . xmlobj . get_boot_order ( legacy = legacy )
2019-02-06 12:55:39 +03:00
2010-12-12 06:00:52 +03:00
def get_boot_menu ( self ) :
2013-09-23 16:34:50 +04:00
guest = self . get_xmlobj ( )
2013-07-17 15:53:47 +04:00
return bool ( guest . os . enable_bootmenu )
2010-12-12 07:00:19 +03:00
def get_boot_kernel_info ( self ) :
2013-09-23 16:34:50 +04:00
guest = self . get_xmlobj ( )
2013-08-18 20:25:20 +04:00
return ( guest . os . kernel , guest . os . initrd ,
guest . os . dtb , guest . os . kernel_args )
2010-12-12 07:00:19 +03:00
2018-03-21 21:42:50 +03:00
def get_interface_devices_norefresh ( self ) :
xmlobj = self . get_xmlobj ( refresh_if_nec = False )
return xmlobj . devices . interface
def get_disk_devices_norefresh ( self ) :
xmlobj = self . get_xmlobj ( refresh_if_nec = False )
return xmlobj . devices . disk
2009-09-25 17:52:03 +04:00
2018-03-21 21:42:50 +03:00
def serial_is_console_dup ( self , serial ) :
if serial . DEVICE_TYPE != " serial " :
return False
2010-09-04 01:56:40 +04:00
2018-03-21 21:42:50 +03:00
consoles = self . xmlobj . devices . console
if not consoles :
return False
2010-09-04 01:56:40 +04:00
2018-03-21 21:42:50 +03:00
console = consoles [ 0 ]
if ( console . type == serial . type and
( console . target_type is None or console . target_type == " serial " ) ) :
return True
return False
2009-10-06 02:00:13 +04:00
2014-03-22 22:34:23 +04:00
def can_use_device_boot_order ( self ) :
# Return 'True' if guest can use new style boot device ordering
2019-06-07 23:06:52 +03:00
return self . conn . support . conn_device_boot_order ( )
2014-03-22 22:34:23 +04:00
def get_bootable_devices ( self ) :
# redirdev can also be marked bootable, but it should be rarely
# used and clutters the UI
2019-02-06 12:55:35 +03:00
return self . xmlobj . get_bootable_devices ( exclude_redirdev = True )
2014-03-22 22:34:23 +04:00
2018-03-21 21:42:50 +03:00
def get_serialcon_devices ( self ) :
return self . xmlobj . devices . serial + self . xmlobj . devices . console
2011-05-04 00:17:52 +04:00
############################
# Domain lifecycle methods #
############################
2012-02-10 23:07:51 +04:00
# All these methods are usually run asynchronously from threads, so
# let's be extra careful and have anything which might touch UI
2012-05-14 17:24:56 +04:00
# or GObject.props invoked in an idle callback
2012-02-10 23:07:51 +04:00
2015-04-10 01:27:45 +03:00
@vmmLibvirtObject.lifecycle_action
2011-05-04 00:17:52 +04:00
def shutdown ( self ) :
2012-02-10 23:07:51 +04:00
self . _install_abort = True
2011-05-04 00:17:52 +04:00
self . _backend . shutdown ( )
2015-04-10 01:27:45 +03:00
@vmmLibvirtObject.lifecycle_action
2011-05-04 00:17:52 +04:00
def reboot ( self ) :
2012-02-10 23:07:51 +04:00
self . _install_abort = True
2011-05-04 00:17:52 +04:00
self . _backend . reboot ( 0 )
2012-02-10 23:07:51 +04:00
2015-04-10 01:27:45 +03:00
@vmmLibvirtObject.lifecycle_action
2012-02-10 23:07:51 +04:00
def destroy ( self ) :
self . _install_abort = True
self . _backend . destroy ( )
2011-05-04 00:17:52 +04:00
2015-04-10 01:27:45 +03:00
@vmmLibvirtObject.lifecycle_action
2013-03-17 01:59:32 +04:00
def reset ( self ) :
self . _install_abort = True
self . _backend . reset ( 0 )
2015-04-10 01:27:45 +03:00
@vmmLibvirtObject.lifecycle_action
2011-05-04 00:17:52 +04:00
def startup ( self ) :
if self . get_cloning ( ) :
raise RuntimeError ( _ ( " Cannot start guest while cloning "
" operation in progress " ) )
2013-05-13 14:14:11 +04:00
pre_startup_ret = [ ]
self . emit ( " pre-startup " , pre_startup_ret )
for error in pre_startup_ret :
raise RuntimeError ( error )
2011-05-04 00:17:52 +04:00
self . _backend . create ( )
2015-04-10 01:27:45 +03:00
@vmmLibvirtObject.lifecycle_action
2011-05-04 00:17:52 +04:00
def suspend ( self ) :
self . _backend . suspend ( )
2015-04-10 01:27:45 +03:00
@vmmLibvirtObject.lifecycle_action
2013-09-30 23:23:14 +04:00
def delete ( self , force = True ) :
2017-03-06 11:43:10 +03:00
"""
@force : True if we are deleting domain , False if we are renaming domain
If the domain is renamed we need to keep the nvram file .
"""
2013-09-30 23:36:09 +04:00
flags = 0
2013-09-30 23:23:14 +04:00
if force :
2013-09-30 23:36:09 +04:00
flags | = getattr ( libvirt ,
" VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA " , 0 )
flags | = getattr ( libvirt , " VIR_DOMAIN_UNDEFINE_MANAGED_SAVE " , 0 )
2017-03-06 11:43:10 +03:00
if self . has_nvram ( ) :
2014-09-18 02:33:30 +04:00
flags | = getattr ( libvirt , " VIR_DOMAIN_UNDEFINE_NVRAM " , 0 )
2017-03-06 11:43:10 +03:00
else :
if self . has_nvram ( ) :
flags | = getattr ( libvirt , " VIR_DOMAIN_UNDEFINE_KEEP_NVRAM " , 0 )
2013-09-30 23:36:09 +04:00
try :
self . _backend . undefineFlags ( flags )
2013-10-03 03:11:59 +04:00
except libvirt . libvirtError :
logging . exception ( " libvirt undefineFlags failed, "
2013-09-30 23:36:09 +04:00
" falling back to old style " )
self . _backend . undefine ( )
2011-05-04 00:17:52 +04:00
2015-04-10 01:27:45 +03:00
@vmmLibvirtObject.lifecycle_action
2011-05-04 00:17:52 +04:00
def resume ( self ) :
if self . get_cloning ( ) :
raise RuntimeError ( _ ( " Cannot resume guest while cloning "
" operation in progress " ) )
self . _backend . resume ( )
2015-04-10 01:27:45 +03:00
@vmmLibvirtObject.lifecycle_action
2015-04-11 20:52:48 +03:00
def save ( self , meter = None ) :
2015-04-10 01:27:45 +03:00
self . _install_abort = True
if meter :
start_job_progress_thread ( self , meter , _ ( " Saving domain to disk " ) )
2015-04-11 20:52:48 +03:00
self . _backend . managedSave ( 0 )
2011-05-04 00:17:52 +04:00
2014-09-12 02:01:41 +04:00
def has_managed_save ( self ) :
2011-05-04 00:17:52 +04:00
if not self . managedsave_supported :
return False
2014-09-12 02:01:41 +04:00
if self . _has_managed_save is None :
try :
self . _has_managed_save = self . _backend . hasManagedSaveImage ( 0 )
2019-06-07 23:39:33 +03:00
except Exception as e :
if self . conn . support . is_libvirt_error_no_domain ( e ) :
return False
raise
2014-09-12 02:01:41 +04:00
return self . _has_managed_save
def remove_saved_image ( self ) :
if not self . has_managed_save ( ) :
2012-07-09 00:06:16 +04:00
return
self . _backend . managedSaveRemove ( 0 )
2014-09-12 02:01:41 +04:00
self . _has_managed_save = None
2012-07-09 00:06:16 +04:00
2011-05-04 00:17:52 +04:00
2017-09-06 10:19:36 +03:00
def migrate ( self , destconn , dest_uri = None ,
2017-09-20 10:36:27 +03:00
tunnel = False , unsafe = False , temporary = False , meter = None ) :
2012-02-10 23:07:51 +04:00
self . _install_abort = True
2011-05-04 00:17:52 +04:00
flags = 0
2015-04-16 01:40:28 +03:00
flags | = libvirt . VIR_MIGRATE_LIVE
2015-04-22 00:32:43 +03:00
if not temporary :
flags | = libvirt . VIR_MIGRATE_PERSIST_DEST
flags | = libvirt . VIR_MIGRATE_UNDEFINE_SOURCE
2011-05-04 00:17:52 +04:00
2017-09-06 10:19:36 +03:00
if tunnel :
2011-05-04 00:17:52 +04:00
flags | = libvirt . VIR_MIGRATE_PEER2PEER
flags | = libvirt . VIR_MIGRATE_TUNNELLED
2013-12-11 01:33:12 +04:00
if unsafe :
flags | = libvirt . VIR_MIGRATE_UNSAFE
2014-09-25 20:19:01 +04:00
libvirt_destconn = destconn . get_backend ( ) . get_conn_for_api_arg ( )
2017-09-06 10:19:36 +03:00
logging . debug ( " Migrating: conn= %s flags= %s uri= %s tunnel= %s "
2015-04-22 00:32:43 +03:00
" unsafe= %s temporary= %s " ,
2017-09-06 10:19:36 +03:00
destconn , flags , dest_uri , tunnel , unsafe , temporary )
2011-05-04 00:17:52 +04:00
if meter :
start_job_progress_thread ( self , meter , _ ( " Migrating domain " ) )
2016-08-31 20:26:24 +03:00
params = { }
2017-10-03 13:24:39 +03:00
if dest_uri and not tunnel :
2017-09-06 10:19:36 +03:00
params [ libvirt . VIR_MIGRATE_PARAM_URI ] = dest_uri
2016-08-31 20:26:24 +03:00
2017-09-06 10:19:36 +03:00
if tunnel :
self . _backend . migrateToURI3 ( dest_uri , params , flags )
else :
self . _backend . migrate3 ( libvirt_destconn , params , flags )
2012-02-10 23:07:51 +04:00
2013-07-07 19:06:15 +04:00
# Don't schedule any conn update, migrate dialog handles it for us
2011-05-04 00:17:52 +04:00
###################
# Stats accessors #
###################
2010-03-24 07:22:17 +03:00
2018-10-10 17:34:52 +03:00
def _get_stats ( self ) :
return self . conn . statsmanager . get_vm_statslist ( self )
2011-05-04 00:17:52 +04:00
def stats_memory ( self ) :
2018-10-10 17:34:52 +03:00
return self . _get_stats ( ) . get_record ( " curmem " )
2011-05-04 00:17:52 +04:00
def cpu_time ( self ) :
2018-10-10 17:34:52 +03:00
return self . _get_stats ( ) . get_record ( " cpuTime " )
2011-07-12 05:22:50 +04:00
def host_cpu_time_percentage ( self ) :
2018-10-10 17:34:52 +03:00
return self . _get_stats ( ) . get_record ( " cpuHostPercent " )
2011-07-12 16:49:47 +04:00
def guest_cpu_time_percentage ( self ) :
2018-10-10 17:34:52 +03:00
return self . _get_stats ( ) . get_record ( " cpuGuestPercent " )
2011-05-04 00:17:52 +04:00
def network_rx_rate ( self ) :
2018-10-10 17:34:52 +03:00
return self . _get_stats ( ) . get_record ( " netRxRate " )
2011-05-04 00:17:52 +04:00
def network_tx_rate ( self ) :
2018-10-10 17:34:52 +03:00
return self . _get_stats ( ) . get_record ( " netTxRate " )
2011-05-04 00:17:52 +04:00
def disk_read_rate ( self ) :
2018-10-10 17:34:52 +03:00
return self . _get_stats ( ) . get_record ( " diskRdRate " )
2011-05-04 00:17:52 +04:00
def disk_write_rate ( self ) :
2018-10-10 17:34:52 +03:00
return self . _get_stats ( ) . get_record ( " diskWrRate " )
2010-03-24 07:22:17 +03:00
2011-05-04 00:17:52 +04:00
def network_traffic_rate ( self ) :
return self . network_tx_rate ( ) + self . network_rx_rate ( )
2011-07-25 23:09:42 +04:00
def network_traffic_max_rate ( self ) :
2018-10-10 17:34:52 +03:00
stats = self . _get_stats ( )
return max ( stats . netRxMaxRate , stats . netTxMaxRate )
2011-05-04 00:17:52 +04:00
def disk_io_rate ( self ) :
return self . disk_read_rate ( ) + self . disk_write_rate ( )
2011-07-25 23:09:42 +04:00
def disk_io_max_rate ( self ) :
2018-10-10 17:34:52 +03:00
stats = self . _get_stats ( )
return max ( stats . diskRdMaxRate , stats . diskWrMaxRate )
2010-03-24 07:22:17 +03:00
2015-05-04 23:33:56 +03:00
def host_cpu_time_vector ( self , limit = None ) :
2018-10-10 17:34:52 +03:00
return self . _get_stats ( ) . get_vector ( " cpuHostPercent " , limit )
2015-05-04 23:33:56 +03:00
def guest_cpu_time_vector ( self , limit = None ) :
2018-10-10 17:34:52 +03:00
return self . _get_stats ( ) . get_vector ( " cpuGuestPercent " , limit )
2015-05-04 23:33:56 +03:00
def stats_memory_vector ( self , limit = None ) :
2018-10-10 17:34:52 +03:00
return self . _get_stats ( ) . get_vector ( " currMemPercent " , limit )
2015-05-04 23:33:56 +03:00
def network_traffic_vectors ( self , limit = None , ceil = None ) :
2018-10-10 17:34:52 +03:00
return self . _get_stats ( ) . get_in_out_vector (
" netRxRate " , " netTxRate " , limit , ceil )
2015-05-04 23:33:56 +03:00
def disk_io_vectors ( self , limit = None , ceil = None ) :
2018-10-10 17:34:52 +03:00
return self . _get_stats ( ) . get_in_out_vector (
" diskRdRate " , " diskWrRate " , limit , ceil )
2010-03-24 07:22:17 +03:00
2011-05-04 00:17:52 +04:00
###################
# Status helpers ##
###################
2009-07-09 22:35:55 +04:00
2011-05-04 00:17:52 +04:00
def _normalize_status ( self , status ) :
if status == libvirt . VIR_DOMAIN_NOSTATE :
return libvirt . VIR_DOMAIN_RUNNING
elif status == libvirt . VIR_DOMAIN_BLOCKED :
return libvirt . VIR_DOMAIN_RUNNING
return status
def is_active ( self ) :
return not self . is_shutoff ( )
def is_shutoff ( self ) :
return self . status ( ) == libvirt . VIR_DOMAIN_SHUTOFF
def is_crashed ( self ) :
return self . status ( ) == libvirt . VIR_DOMAIN_CRASHED
def is_stoppable ( self ) :
return self . status ( ) in [ libvirt . VIR_DOMAIN_RUNNING ,
2014-02-12 01:40:37 +04:00
libvirt . VIR_DOMAIN_PAUSED ,
2017-04-28 11:07:48 +03:00
libvirt . VIR_DOMAIN_CRASHED ,
2014-02-12 01:40:37 +04:00
libvirt . VIR_DOMAIN_PMSUSPENDED ]
2011-05-04 00:17:52 +04:00
def is_destroyable ( self ) :
return ( self . is_stoppable ( ) or
self . status ( ) in [ libvirt . VIR_DOMAIN_CRASHED ] )
def is_runable ( self ) :
2017-04-28 11:07:48 +03:00
return self . is_shutoff ( )
2011-05-04 00:17:52 +04:00
def is_pauseable ( self ) :
return self . status ( ) in [ libvirt . VIR_DOMAIN_RUNNING ]
def is_unpauseable ( self ) :
return self . status ( ) in [ libvirt . VIR_DOMAIN_PAUSED ]
def is_paused ( self ) :
return self . status ( ) in [ libvirt . VIR_DOMAIN_PAUSED ]
2016-10-06 18:12:59 +03:00
def is_clonable ( self ) :
return self . status ( ) in [ libvirt . VIR_DOMAIN_SHUTOFF ,
libvirt . VIR_DOMAIN_PAUSED ,
libvirt . VIR_DOMAIN_PMSUSPENDED ]
2011-05-04 00:17:52 +04:00
2013-10-01 01:11:22 +04:00
def run_status ( self ) :
2018-02-27 20:29:52 +03:00
return LibvirtEnumMap . pretty_run_status (
self . status ( ) , self . has_managed_save ( ) )
2014-03-18 18:04:59 +04:00
def run_status_reason ( self ) :
2018-02-27 20:29:52 +03:00
return LibvirtEnumMap . pretty_status_reason (
self . status ( ) , self . status_reason ( ) )
2014-03-18 18:04:59 +04:00
2011-07-12 19:50:11 +04:00
def run_status_icon_name ( self ) :
2012-10-30 02:55:51 +04:00
status = self . status ( )
2018-02-27 20:29:52 +03:00
if status not in LibvirtEnumMap . VM_STATUS_ICONS :
2015-04-14 00:25:40 +03:00
logging . debug ( " Unknown status %s , using NOSTATE " , status )
2012-10-30 02:55:51 +04:00
status = libvirt . VIR_DOMAIN_NOSTATE
2018-02-27 20:29:52 +03:00
return LibvirtEnumMap . VM_STATUS_ICONS [ status ]
2011-05-04 00:17:52 +04:00
2013-04-18 01:39:25 +04:00
def inspection_data_updated ( self ) :
self . idle_emit ( " inspection-changed " )
2010-11-30 01:40:28 +03:00
2013-04-18 01:39:25 +04:00
##################
# config helpers #
##################
def on_console_scaling_changed ( self , * args , * * kwargs ) :
2014-06-03 01:17:47 +04:00
return self . config . listen_pervm ( self . get_uuid ( ) , " /scaling " ,
2013-04-18 01:39:25 +04:00
* args , * * kwargs )
2011-05-04 00:17:52 +04:00
def set_console_scaling ( self , value ) :
2014-06-03 01:17:47 +04:00
self . config . set_pervm ( self . get_uuid ( ) , " /scaling " , value )
2011-05-04 00:17:52 +04:00
def get_console_scaling ( self ) :
2014-06-03 01:17:47 +04:00
ret = self . config . get_pervm ( self . get_uuid ( ) , " /scaling " )
2013-04-18 01:39:25 +04:00
if ret == - 1 :
return self . config . get_console_scaling ( )
return ret
2010-11-30 01:40:28 +03:00
2014-01-31 18:13:53 +04:00
def on_console_resizeguest_changed ( self , * args , * * kwargs ) :
2014-06-03 01:17:47 +04:00
return self . config . listen_pervm ( self . get_uuid ( ) , " /resize-guest " ,
2014-01-31 18:13:53 +04:00
* args , * * kwargs )
def set_console_resizeguest ( self , value ) :
2014-06-03 01:17:47 +04:00
self . config . set_pervm ( self . get_uuid ( ) , " /resize-guest " , value )
2014-01-31 18:13:53 +04:00
def get_console_resizeguest ( self ) :
2014-06-03 01:17:47 +04:00
ret = self . config . get_pervm ( self . get_uuid ( ) , " /resize-guest " )
2014-01-31 18:13:53 +04:00
if ret == - 1 :
return self . config . get_console_resizeguest ( )
return ret
2011-05-04 00:17:52 +04:00
def set_details_window_size ( self , w , h ) :
2014-06-03 01:17:47 +04:00
self . config . set_pervm ( self . get_uuid ( ) , " /vm-window-size " , ( w , h ) )
2011-05-04 00:17:52 +04:00
def get_details_window_size ( self ) :
2014-06-03 01:17:47 +04:00
ret = self . config . get_pervm ( self . get_uuid ( ) , " /vm-window-size " )
2013-04-18 01:39:25 +04:00
return ret
2010-11-30 01:40:28 +03:00
2013-04-18 01:39:25 +04:00
def get_console_password ( self ) :
2014-06-03 01:17:47 +04:00
return self . config . get_pervm ( self . get_uuid ( ) , " /console-password " )
2013-04-18 01:39:25 +04:00
def set_console_password ( self , username , keyid ) :
2014-06-03 01:17:47 +04:00
return self . config . set_pervm ( self . get_uuid ( ) , " /console-password " ,
2013-04-18 01:39:25 +04:00
( username , keyid ) )
2016-06-07 16:25:55 +03:00
def del_console_password ( self ) :
return self . config . set_pervm ( self . get_uuid ( ) , " /console-password " ,
( " " , - 1 ) )
2013-10-01 05:41:10 +04:00
def get_cache_dir ( self ) :
ret = os . path . join ( self . conn . get_cache_dir ( ) , self . get_uuid ( ) )
if not os . path . exists ( ret ) :
2017-05-05 20:05:30 +03:00
os . makedirs ( ret , 0o755 )
2013-10-01 05:41:10 +04:00
return ret
2011-05-04 00:17:52 +04:00
###################
# Polling helpers #
###################
2010-11-30 01:40:28 +03:00
2013-07-07 17:42:21 +04:00
def tick ( self , stats_update = True ) :
2015-04-19 16:26:16 +03:00
if ( not self . _using_events ( ) and
not stats_update ) :
return
2014-02-11 21:07:13 +04:00
2015-04-19 16:26:16 +03:00
dosignal = False
if not self . _using_events ( ) :
# For domains it's pretty important that we are always using
# the latest XML, but other objects probably don't want to do
# this since it could be a performance hit.
self . _invalidate_xml ( )
2014-02-12 00:29:30 +04:00
info = self . _backend . info ( )
2015-04-19 16:26:16 +03:00
dosignal = self . _refresh_status ( newstatus = info [ 0 ] , cansignal = False )
2013-07-07 17:42:21 +04:00
if stats_update :
2018-10-10 17:34:52 +03:00
self . conn . statsmanager . refresh_vm_stats ( self )
2015-04-19 16:26:16 +03:00
if dosignal :
self . idle_emit ( " state-changed " )
2013-07-07 17:42:21 +04:00
if stats_update :
self . idle_emit ( " resources-sampled " )
2010-02-07 20:16:13 +03:00
2011-05-04 00:17:52 +04:00
########################
# Libvirt domain class #
########################
class vmmDomainVirtinst ( vmmDomain ) :
2010-02-07 20:16:13 +03:00
"""
Domain object backed by a virtinst Guest object .
Used for launching a details window for customizing a VM before install .
"""
2013-07-07 16:42:57 +04:00
def __init__ ( self , conn , backend , key ) :
vmmDomain . __init__ ( self , conn , backend , key )
2015-04-07 21:53:28 +03:00
self . _orig_xml = None
2010-09-09 01:53:51 +04:00
2015-04-14 00:25:40 +03:00
self . _refresh_status ( )
2015-05-04 00:01:16 +03:00
logging . debug ( " %s initialized with XML= \n %s " , self , self . _XMLDesc ( 0 ) )
2015-04-14 00:25:40 +03:00
2010-02-07 20:16:13 +03:00
def get_name ( self ) :
return self . _backend . name
2014-06-03 01:17:47 +04:00
def get_uuid ( self ) :
return self . _backend . uuid
2010-02-07 20:16:13 +03:00
def get_id ( self ) :
return - 1
2014-09-12 02:01:41 +04:00
def has_managed_save ( self ) :
2011-05-04 00:17:52 +04:00
return False
2013-10-02 15:42:24 +04:00
def snapshots_supported ( self ) :
return False
2010-02-07 20:16:13 +03:00
def get_autostart ( self ) :
2018-10-13 16:42:15 +03:00
return self . _backend . installer_instance . autostart
2010-02-07 20:16:13 +03:00
def set_autostart ( self , val ) :
2018-10-13 16:42:15 +03:00
self . _backend . installer_instance . autostart = bool ( val )
2015-04-10 01:02:42 +03:00
self . emit ( " state-changed " )
2010-02-07 20:16:13 +03:00
2015-04-07 21:53:28 +03:00
def _using_events ( self ) :
return False
2015-04-14 00:25:40 +03:00
def _get_backend_status ( self ) :
return libvirt . VIR_DOMAIN_SHUTOFF
def _init_libvirt_state ( self ) :
pass
2015-04-07 21:53:28 +03:00
2015-04-10 16:15:44 +03:00
def tick ( self , stats_update = True ) :
ignore = stats_update
2015-04-07 21:53:28 +03:00
################
# XML handling #
################
2011-03-24 20:24:01 +03:00
def define_name ( self , newname ) :
2015-04-07 21:53:28 +03:00
# We need to overwrite this, since the implementation for libvirt
# needs to do some crazy stuff.
2015-04-11 00:23:11 +03:00
xmlobj = self . _make_xmlobj_to_define ( )
2015-04-07 21:53:28 +03:00
xmlobj . name = str ( newname )
2015-04-11 00:23:11 +03:00
self . _redefine_xmlobj ( xmlobj )
2015-04-07 21:53:28 +03:00
def _XMLDesc ( self , flags ) :
ignore = flags
2018-08-31 23:52:02 +03:00
return self . _backend . get_xml ( )
2015-04-07 21:53:28 +03:00
2017-06-15 15:18:26 +03:00
def _define ( self , xml ) :
ignore = xml
2015-04-10 01:02:42 +03:00
self . emit ( " state-changed " )
2015-04-07 21:53:28 +03:00
def _invalidate_xml ( self ) :
vmmDomain . _invalidate_xml ( self )
self . _orig_xml = None
def _make_xmlobj_to_define ( self ) :
if not self . _orig_xml :
2018-08-31 23:52:02 +03:00
self . _orig_xml = self . _backend . get_xml ( )
2015-04-07 21:53:28 +03:00
return self . _backend
2019-05-09 00:41:24 +03:00
def _redefine_xmlobj ( self , xmlobj ) :
2019-05-09 00:48:08 +03:00
self . _redefine_xml_internal ( self . _orig_xml or " " , xmlobj . get_xml ( ) )
2019-03-05 17:49:23 +03:00
def rename_domain ( self , new_name ) :
self . define_name ( new_name )