2015-02-27 08:53:51 +00:00
|
|
|
import time
|
|
|
|
import os.path
|
|
|
|
try:
|
2018-11-20 14:07:19 +00:00
|
|
|
from libvirt import libvirtError, VIR_DOMAIN_XML_SECURE, VIR_MIGRATE_LIVE, VIR_MIGRATE_UNSAFE, VIR_DOMAIN_RUNNING, \
|
|
|
|
VIR_DOMAIN_AFFECT_LIVE, VIR_DOMAIN_AFFECT_CONFIG
|
2015-02-27 08:53:51 +00:00
|
|
|
except:
|
|
|
|
from libvirt import libvirtError, VIR_DOMAIN_XML_SECURE, VIR_MIGRATE_LIVE
|
|
|
|
from vrtManager import util
|
|
|
|
from xml.etree import ElementTree
|
|
|
|
from datetime import datetime
|
|
|
|
from vrtManager.connection import wvmConnect
|
2015-11-13 09:15:38 +00:00
|
|
|
from vrtManager.storage import wvmStorage
|
2015-02-27 12:44:44 +00:00
|
|
|
from webvirtcloud.settings import QEMU_CONSOLE_TYPES
|
2018-10-05 14:07:25 +00:00
|
|
|
from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_OWNER as owner
|
2015-02-27 08:53:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
class wvmInstances(wvmConnect):
|
|
|
|
def get_instance_status(self, name):
|
|
|
|
inst = self.get_instance(name)
|
|
|
|
return inst.info()[0]
|
|
|
|
|
|
|
|
def get_instance_memory(self, name):
|
|
|
|
inst = self.get_instance(name)
|
|
|
|
mem = util.get_xml_path(inst.XMLDesc(0), "/domain/currentMemory")
|
|
|
|
return int(mem) / 1024
|
|
|
|
|
|
|
|
def get_instance_vcpu(self, name):
|
|
|
|
inst = self.get_instance(name)
|
|
|
|
cur_vcpu = util.get_xml_path(inst.XMLDesc(0), "/domain/vcpu/@current")
|
|
|
|
if cur_vcpu:
|
|
|
|
vcpu = cur_vcpu
|
|
|
|
else:
|
|
|
|
vcpu = util.get_xml_path(inst.XMLDesc(0), "/domain/vcpu")
|
|
|
|
return vcpu
|
|
|
|
|
|
|
|
def get_instance_managed_save_image(self, name):
|
|
|
|
inst = self.get_instance(name)
|
|
|
|
return inst.hasManagedSaveImage(0)
|
|
|
|
|
|
|
|
def get_uuid(self, name):
|
|
|
|
inst = self.get_instance(name)
|
|
|
|
return inst.UUIDString()
|
|
|
|
|
|
|
|
def start(self, name):
|
|
|
|
dom = self.get_instance(name)
|
|
|
|
dom.create()
|
|
|
|
|
|
|
|
def shutdown(self, name):
|
|
|
|
dom = self.get_instance(name)
|
|
|
|
dom.shutdown()
|
|
|
|
|
|
|
|
def force_shutdown(self, name):
|
|
|
|
dom = self.get_instance(name)
|
|
|
|
dom.destroy()
|
|
|
|
|
|
|
|
def managedsave(self, name):
|
|
|
|
dom = self.get_instance(name)
|
|
|
|
dom.managedSave(0)
|
|
|
|
|
|
|
|
def managed_save_remove(self, name):
|
|
|
|
dom = self.get_instance(name)
|
|
|
|
dom.managedSaveRemove(0)
|
|
|
|
|
|
|
|
def suspend(self, name):
|
|
|
|
dom = self.get_instance(name)
|
|
|
|
dom.suspend()
|
|
|
|
|
|
|
|
def resume(self, name):
|
|
|
|
dom = self.get_instance(name)
|
|
|
|
dom.resume()
|
|
|
|
|
2017-01-04 12:14:30 +00:00
|
|
|
def moveto(self, conn, name, live, unsafe, undefine, offline):
|
2015-02-27 08:53:51 +00:00
|
|
|
flags = 0
|
|
|
|
if live and conn.get_status() == 1:
|
|
|
|
flags |= VIR_MIGRATE_LIVE
|
|
|
|
if unsafe and conn.get_status() == 1:
|
|
|
|
flags |= VIR_MIGRATE_UNSAFE
|
|
|
|
dom = conn.get_instance(name)
|
2017-01-04 12:14:30 +00:00
|
|
|
xml = dom.XMLDesc(VIR_DOMAIN_XML_SECURE)
|
|
|
|
if not offline:
|
|
|
|
dom.migrate(self.wvm, flags, None, None, 0)
|
2015-02-27 08:53:51 +00:00
|
|
|
if undefine:
|
|
|
|
dom.undefine()
|
|
|
|
self.wvm.defineXML(xml)
|
2016-04-16 13:06:39 +00:00
|
|
|
|
2015-09-08 10:54:00 +00:00
|
|
|
def graphics_type(self, name):
|
|
|
|
inst = self.get_instance(name)
|
|
|
|
console_type = util.get_xml_path(inst.XMLDesc(0), "/domain/devices/graphics/@type")
|
|
|
|
if console_type is None:
|
|
|
|
return "None"
|
|
|
|
return console_type
|
|
|
|
|
|
|
|
def graphics_listen(self, name):
|
|
|
|
inst = self.get_instance(name)
|
|
|
|
listen_addr = util.get_xml_path(inst.XMLDesc(0), "/domain/devices/graphics/@listen")
|
|
|
|
if listen_addr is None:
|
|
|
|
listen_addr = util.get_xml_path(inst.XMLDesc(0), "/domain/devices/graphics/listen/@address")
|
|
|
|
if listen_addr is None:
|
2019-09-10 06:48:31 +00:00
|
|
|
return "None"
|
2015-09-08 10:54:00 +00:00
|
|
|
return listen_addr
|
|
|
|
|
|
|
|
def graphics_port(self, name):
|
|
|
|
inst = self.get_instance(name)
|
|
|
|
console_port = util.get_xml_path(inst.XMLDesc(0), "/domain/devices/graphics/@port")
|
|
|
|
if console_port is None:
|
|
|
|
return "None"
|
|
|
|
return console_port
|
|
|
|
|
|
|
|
def domain_name(self, name):
|
|
|
|
inst = self.get_instance(name)
|
|
|
|
domname = util.get_xml_path(inst.XMLDesc(0), "/domain/name")
|
|
|
|
if domname is None:
|
|
|
|
return "NoName"
|
|
|
|
return domname
|
|
|
|
|
|
|
|
def graphics_passwd(self, name):
|
|
|
|
inst = self.get_instance(name)
|
|
|
|
password = util.get_xml_path(inst.XMLDesc(VIR_DOMAIN_XML_SECURE), "/domain/devices/graphics/@passwd")
|
|
|
|
if password is None:
|
|
|
|
return "None"
|
|
|
|
return password
|
2015-02-27 08:53:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
class wvmInstance(wvmConnect):
|
|
|
|
def __init__(self, host, login, passwd, conn, vname):
|
|
|
|
wvmConnect.__init__(self, host, login, passwd, conn)
|
|
|
|
self.instance = self.get_instance(vname)
|
|
|
|
|
|
|
|
def start(self):
|
|
|
|
self.instance.create()
|
|
|
|
|
|
|
|
def shutdown(self):
|
|
|
|
self.instance.shutdown()
|
|
|
|
|
|
|
|
def force_shutdown(self):
|
|
|
|
self.instance.destroy()
|
|
|
|
|
|
|
|
def managedsave(self):
|
|
|
|
self.instance.managedSave(0)
|
|
|
|
|
|
|
|
def managed_save_remove(self):
|
|
|
|
self.instance.managedSaveRemove(0)
|
|
|
|
|
|
|
|
def suspend(self):
|
|
|
|
self.instance.suspend()
|
|
|
|
|
|
|
|
def resume(self):
|
|
|
|
self.instance.resume()
|
|
|
|
|
|
|
|
def delete(self):
|
|
|
|
self.instance.undefine()
|
|
|
|
|
|
|
|
def _XMLDesc(self, flag):
|
|
|
|
return self.instance.XMLDesc(flag)
|
|
|
|
|
|
|
|
def _defineXML(self, xml):
|
|
|
|
return self.wvm.defineXML(xml)
|
|
|
|
|
|
|
|
def get_status(self):
|
|
|
|
return self.instance.info()[0]
|
|
|
|
|
|
|
|
def get_autostart(self):
|
|
|
|
return self.instance.autostart()
|
|
|
|
|
|
|
|
def set_autostart(self, flag):
|
|
|
|
return self.instance.setAutostart(flag)
|
|
|
|
|
|
|
|
def get_uuid(self):
|
|
|
|
return self.instance.UUIDString()
|
|
|
|
|
|
|
|
def get_vcpu(self):
|
|
|
|
vcpu = util.get_xml_path(self._XMLDesc(0), "/domain/vcpu")
|
|
|
|
return int(vcpu)
|
|
|
|
|
|
|
|
def get_cur_vcpu(self):
|
|
|
|
cur_vcpu = util.get_xml_path(self._XMLDesc(0), "/domain/vcpu/@current")
|
|
|
|
if cur_vcpu:
|
|
|
|
return int(cur_vcpu)
|
|
|
|
|
|
|
|
def get_memory(self):
|
|
|
|
mem = util.get_xml_path(self._XMLDesc(0), "/domain/memory")
|
|
|
|
return int(mem) / 1024
|
|
|
|
|
|
|
|
def get_cur_memory(self):
|
|
|
|
mem = util.get_xml_path(self._XMLDesc(0), "/domain/currentMemory")
|
|
|
|
return int(mem) / 1024
|
|
|
|
|
2016-02-23 13:43:32 +00:00
|
|
|
def get_title(self):
|
|
|
|
title = util.get_xml_path(self._XMLDesc(0), "/domain/title")
|
|
|
|
return title if title else ''
|
|
|
|
|
2018-09-21 15:46:33 +00:00
|
|
|
def get_filterrefs(self):
|
|
|
|
|
|
|
|
def filterrefs(ctx):
|
|
|
|
result = []
|
|
|
|
for net in ctx.xpath('/domain/devices/interface'):
|
|
|
|
filterref = net.xpath('filterref/@filter')
|
|
|
|
if filterref:
|
|
|
|
result.append(filterref[0])
|
|
|
|
return result
|
|
|
|
|
|
|
|
return util.get_xml_path(self._XMLDesc(0), func=filterrefs)
|
|
|
|
|
2015-02-27 08:53:51 +00:00
|
|
|
def get_description(self):
|
2016-02-23 13:43:32 +00:00
|
|
|
description = util.get_xml_path(self._XMLDesc(0), "/domain/description")
|
|
|
|
return description if description else ''
|
2015-02-27 08:53:51 +00:00
|
|
|
|
|
|
|
def get_max_memory(self):
|
|
|
|
return self.wvm.getInfo()[1] * 1048576
|
|
|
|
|
|
|
|
def get_max_cpus(self):
|
|
|
|
"""Get number of physical CPUs."""
|
|
|
|
hostinfo = self.wvm.getInfo()
|
|
|
|
pcpus = hostinfo[4] * hostinfo[5] * hostinfo[6] * hostinfo[7]
|
|
|
|
range_pcpus = xrange(1, int(pcpus + 1))
|
|
|
|
return range_pcpus
|
|
|
|
|
|
|
|
def get_net_device(self):
|
|
|
|
def get_mac_ipaddr(net, mac_host):
|
2018-06-27 07:20:51 +00:00
|
|
|
def fixed(doc):
|
|
|
|
for net in doc.xpath('/network/ip/dhcp/host'):
|
|
|
|
mac = net.xpath('@mac')[0]
|
|
|
|
host = net.xpath('@ip')[0]
|
2015-02-27 08:53:51 +00:00
|
|
|
if mac == mac_host:
|
|
|
|
return host
|
|
|
|
return None
|
|
|
|
|
|
|
|
return util.get_xml_path(net.XMLDesc(0), func=fixed)
|
|
|
|
|
|
|
|
def networks(ctx):
|
|
|
|
result = []
|
2018-06-27 07:20:51 +00:00
|
|
|
for net in ctx.xpath('/domain/devices/interface'):
|
|
|
|
mac_host = net.xpath('mac/@address')[0]
|
2018-07-24 10:52:47 +00:00
|
|
|
network_host = net.xpath('source/@network|source/@bridge|source/@dev')[0]
|
|
|
|
target_host = '' if not net.xpath('target/@dev') else net.xpath('target/@dev')[0]
|
2018-09-26 14:20:46 +00:00
|
|
|
filterref_host = '' if not net.xpath('filterref/@filter') else net.xpath('filterref/@filter')[0]
|
2015-02-27 08:53:51 +00:00
|
|
|
try:
|
2018-07-24 10:52:47 +00:00
|
|
|
net = self.get_network(network_host)
|
2015-02-27 08:53:51 +00:00
|
|
|
ip = get_mac_ipaddr(net, mac_host)
|
2019-09-10 06:48:31 +00:00
|
|
|
except libvirtError:
|
2015-02-27 08:53:51 +00:00
|
|
|
ip = None
|
2019-09-10 06:48:31 +00:00
|
|
|
result.append({'mac': mac_host, 'nic': network_host, 'target': target_host, 'ip': ip, 'filterref': filterref_host})
|
2015-02-27 08:53:51 +00:00
|
|
|
return result
|
|
|
|
|
|
|
|
return util.get_xml_path(self._XMLDesc(0), func=networks)
|
|
|
|
|
2018-10-24 09:04:05 +00:00
|
|
|
def get_disk_devices(self):
|
2018-06-27 07:20:51 +00:00
|
|
|
def disks(doc):
|
2015-02-27 08:53:51 +00:00
|
|
|
result = []
|
2019-01-09 12:31:42 +00:00
|
|
|
dev = volume = storage = src_file = None
|
2019-01-15 12:55:05 +00:00
|
|
|
disk_format = used_size = disk_size = disk_cache = None
|
2018-11-05 12:19:25 +00:00
|
|
|
|
2018-06-27 07:20:51 +00:00
|
|
|
for disk in doc.xpath('/domain/devices/disk'):
|
|
|
|
device = disk.xpath('@device')[0]
|
2015-02-27 08:53:51 +00:00
|
|
|
if device == 'disk':
|
|
|
|
try:
|
2018-06-27 07:20:51 +00:00
|
|
|
dev = disk.xpath('target/@dev')[0]
|
2018-10-19 13:14:33 +00:00
|
|
|
bus = disk.xpath('target/@bus')[0]
|
2019-01-09 12:31:42 +00:00
|
|
|
src_file = disk.xpath('source/@file|source/@dev|source/@name|source/@volume')[0]
|
2018-09-04 13:40:47 +00:00
|
|
|
try:
|
|
|
|
disk_format = disk.xpath('driver/@type')[0]
|
2019-01-15 12:55:05 +00:00
|
|
|
except:
|
|
|
|
pass
|
|
|
|
try:
|
2019-01-09 12:31:42 +00:00
|
|
|
disk_cache = disk.xpath('driver/@cache')[0]
|
2018-09-04 13:40:47 +00:00
|
|
|
except:
|
|
|
|
pass
|
2015-02-27 08:53:51 +00:00
|
|
|
try:
|
2019-01-09 12:31:42 +00:00
|
|
|
vol = self.get_volume_by_path(src_file)
|
2015-02-27 08:53:51 +00:00
|
|
|
volume = vol.name()
|
2018-10-19 13:14:33 +00:00
|
|
|
|
2015-03-13 15:30:09 +00:00
|
|
|
disk_size = vol.info()[1]
|
2018-10-19 13:14:33 +00:00
|
|
|
used_size = vol.info()[2]
|
2015-02-27 08:53:51 +00:00
|
|
|
stg = vol.storagePoolLookupByVolume()
|
|
|
|
storage = stg.name()
|
|
|
|
except libvirtError:
|
2019-01-09 12:31:42 +00:00
|
|
|
volume = src_file
|
2015-02-27 08:53:51 +00:00
|
|
|
except:
|
|
|
|
pass
|
|
|
|
finally:
|
|
|
|
result.append(
|
2019-01-09 12:31:42 +00:00
|
|
|
{'dev': dev, 'bus': bus, 'image': volume, 'storage': storage, 'path': src_file,
|
|
|
|
'format': disk_format, 'size': disk_size, 'used': used_size, 'cache': disk_cache})
|
2015-02-27 08:53:51 +00:00
|
|
|
return result
|
|
|
|
|
|
|
|
return util.get_xml_path(self._XMLDesc(0), func=disks)
|
|
|
|
|
2018-10-24 09:04:05 +00:00
|
|
|
def get_media_devices(self):
|
2018-06-27 07:20:51 +00:00
|
|
|
def disks(doc):
|
2015-02-27 08:53:51 +00:00
|
|
|
result = []
|
2019-01-09 12:31:42 +00:00
|
|
|
dev = volume = storage = None
|
|
|
|
src_file = None
|
2018-06-27 07:20:51 +00:00
|
|
|
for media in doc.xpath('/domain/devices/disk'):
|
|
|
|
device = media.xpath('@device')[0]
|
2015-02-27 08:53:51 +00:00
|
|
|
if device == 'cdrom':
|
|
|
|
try:
|
2018-08-02 08:47:13 +00:00
|
|
|
dev = media.xpath('target/@dev')[0]
|
2018-11-23 12:05:30 +00:00
|
|
|
bus = media.xpath('target/@bus')[0]
|
2015-02-27 08:53:51 +00:00
|
|
|
try:
|
2019-01-09 12:31:42 +00:00
|
|
|
src_file = media.xpath('source/@file')[0]
|
|
|
|
vol = self.get_volume_by_path(src_file)
|
2015-02-27 08:53:51 +00:00
|
|
|
volume = vol.name()
|
|
|
|
stg = vol.storagePoolLookupByVolume()
|
|
|
|
storage = stg.name()
|
|
|
|
except:
|
2019-01-09 12:31:42 +00:00
|
|
|
src_file = None
|
|
|
|
volume = src_file
|
2015-02-27 08:53:51 +00:00
|
|
|
except:
|
|
|
|
pass
|
|
|
|
finally:
|
2019-01-09 12:31:42 +00:00
|
|
|
result.append({'dev': dev, 'image': volume, 'storage': storage, 'path': src_file, 'bus': bus})
|
2015-02-27 08:53:51 +00:00
|
|
|
return result
|
|
|
|
|
|
|
|
return util.get_xml_path(self._XMLDesc(0), func=disks)
|
|
|
|
|
2019-01-15 12:55:05 +00:00
|
|
|
def get_bootmenu(self):
|
|
|
|
menu = util.get_xml_path(self._XMLDesc(0), "/domain/os/bootmenu/@enable")
|
|
|
|
return True if menu == 'yes' else False
|
|
|
|
|
|
|
|
def set_bootmenu(self, flag):
|
|
|
|
tree = ElementTree.fromstring(self._XMLDesc(0))
|
|
|
|
os = tree.find('os')
|
|
|
|
menu = os.find("bootmenu")
|
|
|
|
|
2019-09-10 06:48:31 +00:00
|
|
|
if menu is None:
|
2019-01-15 12:55:05 +00:00
|
|
|
bootmenu = ElementTree.fromstring("<bootmenu enable='yes'/>")
|
|
|
|
os.append(bootmenu)
|
|
|
|
menu = os.find("bootmenu")
|
|
|
|
|
|
|
|
if flag == 0: # Disable
|
|
|
|
menu.attrib['enable'] = 'no'
|
|
|
|
elif flag == 1: # Enable
|
|
|
|
menu.attrib['enable'] = 'yes'
|
|
|
|
elif flag == -1: # Remove
|
|
|
|
os.remove(menu)
|
|
|
|
else:
|
|
|
|
raise Exception('Unknown boot menu option, please choose one of 0:disable, 1:enable, -1:remove')
|
|
|
|
|
|
|
|
xmldom = ElementTree.tostring(tree)
|
|
|
|
self._defineXML(xmldom)
|
|
|
|
|
|
|
|
def get_bootorder(self):
|
|
|
|
boot_order = {}
|
|
|
|
tree = ElementTree.fromstring(self._XMLDesc(0))
|
|
|
|
os = tree.find('os')
|
|
|
|
boot = os.findall('boot')
|
|
|
|
|
|
|
|
for idx, b in enumerate(boot):
|
|
|
|
dev = b.get('dev')
|
|
|
|
if dev == 'hd':
|
|
|
|
target = "disk"
|
|
|
|
type = "file"
|
|
|
|
elif dev == 'fd':
|
|
|
|
target = "floppy"
|
|
|
|
type = "file"
|
|
|
|
elif dev == 'cdrom':
|
|
|
|
target = "cdrom"
|
|
|
|
type = "file"
|
|
|
|
elif dev == 'network':
|
|
|
|
target = "network"
|
|
|
|
type = "network"
|
|
|
|
boot_order[idx] = {"type": type, "dev": dev, "target": target}
|
|
|
|
|
|
|
|
devices = tree.find('devices')
|
|
|
|
for dev in devices:
|
|
|
|
dev_target = dev_type = dev_device = dev_alias = None
|
|
|
|
boot_dev = dev.find('boot')
|
2019-09-10 06:48:31 +00:00
|
|
|
if boot_dev is not None:
|
2019-01-15 12:55:05 +00:00
|
|
|
idx = boot_dev.get('order')
|
|
|
|
dev_type = dev.get('type')
|
|
|
|
dev_device = dev.get('device')
|
|
|
|
|
|
|
|
if dev_type == 'file':
|
|
|
|
dev_target = dev.find('target').get('dev')
|
|
|
|
|
|
|
|
elif dev_type == 'network':
|
|
|
|
dev_mac = dev.find('mac').get('address')
|
|
|
|
dev_device = "network"
|
|
|
|
dev_target = "nic-{}".format(dev_mac[9:])
|
|
|
|
elif dev_type == 'usb':
|
|
|
|
pass
|
|
|
|
|
|
|
|
boot_order[int(idx)-1] = {"type": dev_type, "dev": dev_device, "target": dev_target}
|
|
|
|
|
|
|
|
return boot_order
|
|
|
|
|
|
|
|
def set_bootorder(self, devorder):
|
|
|
|
if not devorder:
|
|
|
|
return
|
|
|
|
|
|
|
|
def remove_bootorder():
|
|
|
|
tree = ElementTree.fromstring(self._XMLDesc(0))
|
|
|
|
os = tree.find('os')
|
|
|
|
boot = os.findall('boot')
|
|
|
|
# Remove old style boot order
|
|
|
|
for b in boot:
|
|
|
|
os.remove(b)
|
|
|
|
# Remove rest of them
|
|
|
|
for dev in tree.find('devices'):
|
|
|
|
boot_dev = dev.find('boot')
|
2019-09-10 06:48:31 +00:00
|
|
|
if boot_dev is not None:
|
2019-01-15 12:55:05 +00:00
|
|
|
dev.remove(boot_dev)
|
|
|
|
return tree
|
|
|
|
|
|
|
|
tree = remove_bootorder()
|
|
|
|
|
|
|
|
for idx, dev in devorder.items():
|
|
|
|
order = ElementTree.fromstring("<boot order='{}'/>".format(idx + 1))
|
|
|
|
if dev['type'] == 'disk':
|
|
|
|
devices = tree.findall("./devices/disk[@device='disk']")
|
|
|
|
for d in devices:
|
|
|
|
device = d.find("./target[@dev='{}']".format(dev['dev']))
|
2019-09-10 06:48:31 +00:00
|
|
|
if device is not None:
|
2019-01-15 12:55:05 +00:00
|
|
|
d.append(order)
|
|
|
|
elif dev['type'] == 'cdrom':
|
|
|
|
devices = tree.findall("./devices/disk[@device='cdrom']")
|
|
|
|
for d in devices:
|
|
|
|
device = d.find("./target[@dev='{}']".format(dev['dev']))
|
2019-09-10 06:48:31 +00:00
|
|
|
if device is not None:
|
2019-01-15 12:55:05 +00:00
|
|
|
d.append(order)
|
|
|
|
elif dev['type'] == 'network':
|
|
|
|
devices = tree.findall("./devices/interface[@type='network']")
|
|
|
|
for d in devices:
|
|
|
|
device = d.find("mac[@address='{}']".format(dev['dev']))
|
2019-09-10 06:48:31 +00:00
|
|
|
if device is not None:
|
2019-01-15 12:55:05 +00:00
|
|
|
d.append(order)
|
|
|
|
else:
|
|
|
|
raise Exception('Invalid Device Type for boot order')
|
|
|
|
self._defineXML(ElementTree.tostring(tree))
|
|
|
|
|
2015-02-27 08:53:51 +00:00
|
|
|
def mount_iso(self, dev, image):
|
|
|
|
def attach_iso(dev, disk, vol):
|
|
|
|
if disk.get('device') == 'cdrom':
|
|
|
|
for elm in disk:
|
|
|
|
if elm.tag == 'target':
|
|
|
|
if elm.get('dev') == dev:
|
|
|
|
src_media = ElementTree.Element('source')
|
|
|
|
src_media.set('file', vol.path())
|
|
|
|
disk.insert(2, src_media)
|
|
|
|
return True
|
|
|
|
|
2018-07-20 11:04:13 +00:00
|
|
|
storages = self.get_storages(only_actives=True)
|
2015-02-27 08:53:51 +00:00
|
|
|
for storage in storages:
|
|
|
|
stg = self.get_storage(storage)
|
|
|
|
if stg.info()[0] != 0:
|
|
|
|
for img in stg.listVolumes():
|
|
|
|
if image == img:
|
|
|
|
vol = stg.storageVolLookupByName(image)
|
|
|
|
tree = ElementTree.fromstring(self._XMLDesc(0))
|
|
|
|
for disk in tree.findall('devices/disk'):
|
|
|
|
if attach_iso(dev, disk, vol):
|
|
|
|
break
|
|
|
|
if self.get_status() == 1:
|
|
|
|
xml = ElementTree.tostring(disk)
|
|
|
|
self.instance.attachDevice(xml)
|
|
|
|
xmldom = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
|
|
|
if self.get_status() == 5:
|
|
|
|
xmldom = ElementTree.tostring(tree)
|
|
|
|
self._defineXML(xmldom)
|
|
|
|
|
|
|
|
def umount_iso(self, dev, image):
|
|
|
|
tree = ElementTree.fromstring(self._XMLDesc(0))
|
|
|
|
for disk in tree.findall('devices/disk'):
|
|
|
|
if disk.get('device') == 'cdrom':
|
|
|
|
for elm in disk:
|
|
|
|
if elm.tag == 'source':
|
|
|
|
if elm.get('file') == image:
|
|
|
|
src_media = elm
|
|
|
|
if elm.tag == 'target':
|
|
|
|
if elm.get('dev') == dev:
|
|
|
|
disk.remove(src_media)
|
|
|
|
if self.get_status() == 1:
|
|
|
|
xml_disk = ElementTree.tostring(disk)
|
|
|
|
self.instance.attachDevice(xml_disk)
|
|
|
|
xmldom = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
|
|
|
if self.get_status() == 5:
|
|
|
|
xmldom = ElementTree.tostring(tree)
|
|
|
|
self._defineXML(xmldom)
|
|
|
|
|
2018-11-23 12:05:30 +00:00
|
|
|
def attach_disk(self, source, target, sourcetype='file', device='disk', driver='qemu', subdriver='raw', cache='none', targetbus='ide'):
|
2019-01-29 06:29:52 +00:00
|
|
|
xml_disk = "<disk type='%s' device='%s'>" % (sourcetype, device)
|
|
|
|
if device == 'cdrom':
|
|
|
|
xml_disk += "<driver name='%s' type='%s'/>" % (driver, subdriver)
|
|
|
|
elif device == 'disk':
|
|
|
|
xml_disk += "<driver name='%s' type='%s' cache='%s'/>" % (driver, subdriver, cache)
|
|
|
|
xml_disk += """<source file='%s'/>
|
2017-07-19 13:34:03 +00:00
|
|
|
<target dev='%s' bus='%s'/>
|
|
|
|
</disk>
|
2019-01-29 06:29:52 +00:00
|
|
|
""" % (source, target, targetbus)
|
2019-06-21 08:29:41 +00:00
|
|
|
if self.get_status() == 1:
|
|
|
|
self.instance.attachDeviceFlags(xml_disk, VIR_DOMAIN_AFFECT_LIVE)
|
|
|
|
self.instance.attachDeviceFlags(xml_disk, VIR_DOMAIN_AFFECT_CONFIG)
|
2017-07-19 13:34:03 +00:00
|
|
|
if self.get_status() == 5:
|
2019-06-21 08:29:41 +00:00
|
|
|
self.instance.attachDeviceFlags(xml_disk, VIR_DOMAIN_AFFECT_CONFIG)
|
2017-07-19 13:34:03 +00:00
|
|
|
|
2018-11-23 12:05:30 +00:00
|
|
|
def detach_disk(self, dev):
|
2018-10-19 13:14:33 +00:00
|
|
|
tree = ElementTree.fromstring(self._XMLDesc(0))
|
|
|
|
|
2018-11-23 12:05:30 +00:00
|
|
|
for disk in tree.findall("./devices/disk"):
|
2018-10-19 13:14:33 +00:00
|
|
|
target = disk.find("target")
|
2018-11-23 12:05:30 +00:00
|
|
|
if target.get("dev") == dev:
|
2018-10-19 13:14:33 +00:00
|
|
|
devices = tree.find('devices')
|
|
|
|
devices.remove(disk)
|
|
|
|
|
|
|
|
if self.get_status() == 1:
|
|
|
|
xml_disk = ElementTree.tostring(disk)
|
2018-11-23 12:05:30 +00:00
|
|
|
ret = self.instance.detachDevice(xml_disk)
|
2018-10-19 13:14:33 +00:00
|
|
|
xmldom = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
|
|
|
if self.get_status() == 5:
|
|
|
|
xmldom = ElementTree.tostring(tree)
|
|
|
|
break
|
|
|
|
self._defineXML(xmldom)
|
|
|
|
|
2015-02-27 08:53:51 +00:00
|
|
|
def cpu_usage(self):
|
|
|
|
cpu_usage = {}
|
|
|
|
if self.get_status() == 1:
|
|
|
|
nbcore = self.wvm.getInfo()[2]
|
|
|
|
cpu_use_ago = self.instance.info()[4]
|
|
|
|
time.sleep(1)
|
|
|
|
cpu_use_now = self.instance.info()[4]
|
|
|
|
diff_usage = cpu_use_now - cpu_use_ago
|
|
|
|
cpu_usage['cpu'] = 100 * diff_usage / (1 * nbcore * 10 ** 9L)
|
|
|
|
else:
|
|
|
|
cpu_usage['cpu'] = 0
|
|
|
|
return cpu_usage
|
|
|
|
|
2019-05-21 06:07:01 +00:00
|
|
|
def mem_usage(self):
|
|
|
|
mem_usage = {}
|
|
|
|
if self.get_status() == 1:
|
|
|
|
mem_stats = self.instance.memoryStats()
|
|
|
|
rss = mem_stats['rss'] if mem_stats['rss'] else 0
|
|
|
|
total = mem_stats['actual'] if mem_stats['actual'] else 0
|
|
|
|
available = total - rss
|
|
|
|
if available < 0: available = 0
|
|
|
|
|
|
|
|
mem_usage['used'] = rss
|
|
|
|
mem_usage['total'] = total
|
|
|
|
else:
|
|
|
|
mem_usage['used'] = 0
|
|
|
|
mem_usage['total'] = 0
|
|
|
|
return mem_usage
|
|
|
|
|
2015-02-27 08:53:51 +00:00
|
|
|
def disk_usage(self):
|
|
|
|
devices = []
|
|
|
|
dev_usage = []
|
|
|
|
tree = ElementTree.fromstring(self._XMLDesc(0))
|
|
|
|
for disk in tree.findall('devices/disk'):
|
|
|
|
if disk.get('device') == 'disk':
|
|
|
|
dev_file = None
|
|
|
|
dev_bus = None
|
|
|
|
network_disk = True
|
|
|
|
for elm in disk:
|
|
|
|
if elm.tag == 'source':
|
|
|
|
if elm.get('protocol'):
|
|
|
|
dev_file = elm.get('protocol')
|
|
|
|
network_disk = True
|
|
|
|
if elm.get('file'):
|
|
|
|
dev_file = elm.get('file')
|
|
|
|
if elm.get('dev'):
|
|
|
|
dev_file = elm.get('dev')
|
|
|
|
if elm.tag == 'target':
|
|
|
|
dev_bus = elm.get('dev')
|
|
|
|
if (dev_file and dev_bus) is not None:
|
|
|
|
if network_disk:
|
|
|
|
dev_file = dev_bus
|
|
|
|
devices.append([dev_file, dev_bus])
|
|
|
|
for dev in devices:
|
2015-03-23 12:28:24 +00:00
|
|
|
if self.get_status() == 1:
|
|
|
|
rd_use_ago = self.instance.blockStats(dev[0])[1]
|
|
|
|
wr_use_ago = self.instance.blockStats(dev[0])[3]
|
|
|
|
time.sleep(1)
|
|
|
|
rd_use_now = self.instance.blockStats(dev[0])[1]
|
|
|
|
wr_use_now = self.instance.blockStats(dev[0])[3]
|
|
|
|
rd_diff_usage = rd_use_now - rd_use_ago
|
|
|
|
wr_diff_usage = wr_use_now - wr_use_ago
|
|
|
|
else:
|
|
|
|
rd_diff_usage = 0
|
|
|
|
wr_diff_usage = 0
|
2015-02-27 08:53:51 +00:00
|
|
|
dev_usage.append({'dev': dev[1], 'rd': rd_diff_usage, 'wr': wr_diff_usage})
|
|
|
|
return dev_usage
|
|
|
|
|
|
|
|
def net_usage(self):
|
|
|
|
devices = []
|
|
|
|
dev_usage = []
|
2015-03-23 12:28:24 +00:00
|
|
|
if self.get_status() == 1:
|
|
|
|
tree = ElementTree.fromstring(self._XMLDesc(0))
|
|
|
|
for target in tree.findall("devices/interface/target"):
|
|
|
|
devices.append(target.get("dev"))
|
|
|
|
for i, dev in enumerate(devices):
|
|
|
|
rx_use_ago = self.instance.interfaceStats(dev)[0]
|
|
|
|
tx_use_ago = self.instance.interfaceStats(dev)[4]
|
|
|
|
time.sleep(1)
|
|
|
|
rx_use_now = self.instance.interfaceStats(dev)[0]
|
|
|
|
tx_use_now = self.instance.interfaceStats(dev)[4]
|
|
|
|
rx_diff_usage = (rx_use_now - rx_use_ago) * 8
|
|
|
|
tx_diff_usage = (tx_use_now - tx_use_ago) * 8
|
|
|
|
dev_usage.append({'dev': i, 'rx': rx_diff_usage, 'tx': tx_diff_usage})
|
|
|
|
else:
|
|
|
|
for i, dev in enumerate(self.get_net_device()):
|
|
|
|
dev_usage.append({'dev': i, 'rx': 0, 'tx': 0})
|
2015-02-27 08:53:51 +00:00
|
|
|
return dev_usage
|
|
|
|
|
|
|
|
def get_telnet_port(self):
|
|
|
|
telnet_port = None
|
|
|
|
service_port = None
|
|
|
|
tree = ElementTree.fromstring(self._XMLDesc(0))
|
|
|
|
for console in tree.findall('devices/console'):
|
|
|
|
if console.get('type') == 'tcp':
|
|
|
|
for elm in console:
|
|
|
|
if elm.tag == 'source':
|
|
|
|
if elm.get('service'):
|
|
|
|
service_port = elm.get('service')
|
|
|
|
if elm.tag == 'protocol':
|
|
|
|
if elm.get('type') == 'telnet':
|
|
|
|
if service_port is not None:
|
|
|
|
telnet_port = service_port
|
|
|
|
return telnet_port
|
|
|
|
|
|
|
|
def get_console_listen_addr(self):
|
2019-01-09 12:31:42 +00:00
|
|
|
listen_addr = util.get_xml_path(self._XMLDesc(0), "/domain/devices/graphics/@listen")
|
2015-04-29 05:41:37 +00:00
|
|
|
if listen_addr is None:
|
2019-01-09 12:31:42 +00:00
|
|
|
listen_addr = util.get_xml_path(self._XMLDesc(0), "/domain/devices/graphics/listen/@address")
|
2015-04-29 05:41:37 +00:00
|
|
|
if listen_addr is None:
|
2019-09-10 06:48:31 +00:00
|
|
|
return "127.0.0.1"
|
2015-02-27 08:53:51 +00:00
|
|
|
return listen_addr
|
|
|
|
|
2018-06-15 12:13:50 +00:00
|
|
|
def set_console_listen_addr(self, listen_addr):
|
|
|
|
xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
|
|
|
root = ElementTree.fromstring(xml)
|
|
|
|
console_type = self.get_console_type()
|
|
|
|
try:
|
|
|
|
graphic = root.find("devices/graphics[@type='%s']" % console_type)
|
|
|
|
except SyntaxError:
|
|
|
|
# Little fix for old version ElementTree
|
|
|
|
graphic = root.find("devices/graphics")
|
|
|
|
if graphic is None:
|
|
|
|
return False
|
|
|
|
listen = graphic.find("listen[@type='address']")
|
|
|
|
if listen is None:
|
|
|
|
return False
|
|
|
|
if listen_addr:
|
|
|
|
graphic.set("listen", listen_addr)
|
|
|
|
listen.set("address", listen_addr)
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
graphic.attrib.pop("listen")
|
|
|
|
listen.attrib.pop("address")
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
newxml = ElementTree.tostring(root)
|
|
|
|
return self._defineXML(newxml)
|
|
|
|
|
2015-02-27 08:53:51 +00:00
|
|
|
def get_console_socket(self):
|
2018-09-21 13:50:44 +00:00
|
|
|
socket = util.get_xml_path(self._XMLDesc(0), "/domain/devices/graphics/@socket")
|
2015-02-27 08:53:51 +00:00
|
|
|
return socket
|
|
|
|
|
|
|
|
def get_console_type(self):
|
2019-09-10 06:48:31 +00:00
|
|
|
console_type = util.get_xml_path(self._XMLDesc(0), "/domain/devices/graphics/@type")
|
2015-02-27 08:53:51 +00:00
|
|
|
return console_type
|
|
|
|
|
|
|
|
def set_console_type(self, console_type):
|
|
|
|
current_type = self.get_console_type()
|
|
|
|
if current_type == console_type:
|
|
|
|
return True
|
|
|
|
if console_type == '' or console_type not in QEMU_CONSOLE_TYPES:
|
|
|
|
return False
|
|
|
|
xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
|
|
|
root = ElementTree.fromstring(xml)
|
|
|
|
try:
|
|
|
|
graphic = root.find("devices/graphics[@type='%s']" % current_type)
|
|
|
|
except SyntaxError:
|
|
|
|
# Little fix for old version ElementTree
|
|
|
|
graphic = root.find("devices/graphics")
|
|
|
|
graphic.set('type', console_type)
|
|
|
|
newxml = ElementTree.tostring(root)
|
|
|
|
self._defineXML(newxml)
|
|
|
|
|
|
|
|
def get_console_port(self, console_type=None):
|
|
|
|
if console_type is None:
|
|
|
|
console_type = self.get_console_type()
|
|
|
|
port = util.get_xml_path(self._XMLDesc(0),
|
|
|
|
"/domain/devices/graphics[@type='%s']/@port" % console_type)
|
|
|
|
return port
|
|
|
|
|
|
|
|
def get_console_websocket_port(self):
|
|
|
|
console_type = self.get_console_type()
|
|
|
|
websocket_port = util.get_xml_path(self._XMLDesc(0),
|
|
|
|
"/domain/devices/graphics[@type='%s']/@websocket" % console_type)
|
|
|
|
return websocket_port
|
|
|
|
|
|
|
|
def get_console_passwd(self):
|
|
|
|
return util.get_xml_path(self._XMLDesc(VIR_DOMAIN_XML_SECURE),
|
|
|
|
"/domain/devices/graphics/@passwd")
|
|
|
|
|
|
|
|
def set_console_passwd(self, passwd):
|
|
|
|
xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
|
|
|
root = ElementTree.fromstring(xml)
|
|
|
|
console_type = self.get_console_type()
|
|
|
|
try:
|
|
|
|
graphic = root.find("devices/graphics[@type='%s']" % console_type)
|
|
|
|
except SyntaxError:
|
|
|
|
# Little fix for old version ElementTree
|
|
|
|
graphic = root.find("devices/graphics")
|
|
|
|
if graphic is None:
|
|
|
|
return False
|
|
|
|
if passwd:
|
|
|
|
graphic.set('passwd', passwd)
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
graphic.attrib.pop('passwd')
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
newxml = ElementTree.tostring(root)
|
|
|
|
return self._defineXML(newxml)
|
|
|
|
|
|
|
|
def set_console_keymap(self, keymap):
|
|
|
|
xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
|
|
|
root = ElementTree.fromstring(xml)
|
|
|
|
console_type = self.get_console_type()
|
|
|
|
try:
|
|
|
|
graphic = root.find("devices/graphics[@type='%s']" % console_type)
|
|
|
|
except SyntaxError:
|
|
|
|
# Little fix for old version ElementTree
|
|
|
|
graphic = root.find("devices/graphics")
|
|
|
|
if keymap:
|
|
|
|
graphic.set('keymap', keymap)
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
graphic.attrib.pop('keymap')
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
newxml = ElementTree.tostring(root)
|
|
|
|
self._defineXML(newxml)
|
|
|
|
|
|
|
|
def get_console_keymap(self):
|
|
|
|
return util.get_xml_path(self._XMLDesc(VIR_DOMAIN_XML_SECURE),
|
|
|
|
"/domain/devices/graphics/@keymap") or ''
|
|
|
|
|
2015-11-24 08:53:13 +00:00
|
|
|
def resize(self, cur_memory, memory, cur_vcpu, vcpu, disks=[]):
|
2015-02-27 08:53:51 +00:00
|
|
|
"""
|
|
|
|
Function change ram and cpu on vds.
|
|
|
|
"""
|
|
|
|
memory = int(memory) * 1024
|
|
|
|
cur_memory = int(cur_memory) * 1024
|
2018-11-20 14:07:19 +00:00
|
|
|
# if dom is running change only ram
|
|
|
|
if self.get_status() == VIR_DOMAIN_RUNNING:
|
|
|
|
self.set_memory(cur_memory, VIR_DOMAIN_AFFECT_LIVE)
|
|
|
|
self.set_memory(cur_memory, VIR_DOMAIN_AFFECT_CONFIG)
|
|
|
|
return
|
2015-02-27 08:53:51 +00:00
|
|
|
|
|
|
|
xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
|
|
|
tree = ElementTree.fromstring(xml)
|
|
|
|
|
|
|
|
set_mem = tree.find('memory')
|
|
|
|
set_mem.text = str(memory)
|
|
|
|
set_cur_mem = tree.find('currentMemory')
|
|
|
|
set_cur_mem.text = str(cur_memory)
|
|
|
|
set_vcpu = tree.find('vcpu')
|
|
|
|
set_vcpu.text = vcpu
|
|
|
|
set_vcpu.set('current', cur_vcpu)
|
|
|
|
|
2015-11-24 08:53:13 +00:00
|
|
|
for disk in disks:
|
|
|
|
source_dev = disk['path']
|
|
|
|
vol = self.get_volume_by_path(source_dev)
|
|
|
|
vol.resize(disk['size_new'])
|
|
|
|
|
2015-02-27 08:53:51 +00:00
|
|
|
new_xml = ElementTree.tostring(tree)
|
|
|
|
self._defineXML(new_xml)
|
|
|
|
|
2019-08-27 14:18:33 +00:00
|
|
|
def resize_cpu(self, cur_vcpu, vcpu):
|
|
|
|
"""
|
|
|
|
Function change ram and cpu on vds.
|
|
|
|
"""
|
|
|
|
xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
|
|
|
tree = ElementTree.fromstring(xml)
|
|
|
|
|
|
|
|
set_vcpu = tree.find('vcpu')
|
|
|
|
set_vcpu.text = vcpu
|
|
|
|
set_vcpu.set('current', cur_vcpu)
|
|
|
|
|
|
|
|
new_xml = ElementTree.tostring(tree)
|
|
|
|
self._defineXML(new_xml)
|
|
|
|
|
|
|
|
def resize_mem(self, cur_memory, memory):
|
|
|
|
"""
|
|
|
|
Function change ram and cpu on vds.
|
|
|
|
"""
|
|
|
|
memory = int(memory) * 1024
|
|
|
|
cur_memory = int(cur_memory) * 1024
|
|
|
|
# if dom is running change only ram
|
|
|
|
if self.get_status() == VIR_DOMAIN_RUNNING:
|
|
|
|
self.set_memory(cur_memory, VIR_DOMAIN_AFFECT_LIVE)
|
|
|
|
self.set_memory(cur_memory, VIR_DOMAIN_AFFECT_CONFIG)
|
|
|
|
return
|
|
|
|
|
|
|
|
xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
|
|
|
tree = ElementTree.fromstring(xml)
|
|
|
|
|
|
|
|
set_mem = tree.find('memory')
|
|
|
|
set_mem.text = str(memory)
|
|
|
|
set_cur_mem = tree.find('currentMemory')
|
|
|
|
set_cur_mem.text = str(cur_memory)
|
|
|
|
|
|
|
|
new_xml = ElementTree.tostring(tree)
|
|
|
|
self._defineXML(new_xml)
|
|
|
|
|
2019-09-10 06:48:31 +00:00
|
|
|
def resize_disk(self, disks):
|
2019-08-27 14:18:33 +00:00
|
|
|
"""
|
|
|
|
Function change disks on vds.
|
|
|
|
"""
|
|
|
|
xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
|
|
|
tree = ElementTree.fromstring(xml)
|
|
|
|
|
|
|
|
for disk in disks:
|
|
|
|
source_dev = disk['path']
|
|
|
|
vol = self.get_volume_by_path(source_dev)
|
|
|
|
vol.resize(disk['size_new'])
|
|
|
|
|
|
|
|
new_xml = ElementTree.tostring(tree)
|
|
|
|
self._defineXML(new_xml)
|
|
|
|
|
2015-02-27 08:53:51 +00:00
|
|
|
def get_iso_media(self):
|
|
|
|
iso = []
|
2018-07-20 11:04:13 +00:00
|
|
|
storages = self.get_storages(only_actives=True)
|
2015-02-27 08:53:51 +00:00
|
|
|
for storage in storages:
|
|
|
|
stg = self.get_storage(storage)
|
|
|
|
if stg.info()[0] != 0:
|
|
|
|
try:
|
|
|
|
stg.refresh(0)
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
for img in stg.listVolumes():
|
|
|
|
if img.endswith('.iso'):
|
|
|
|
iso.append(img)
|
|
|
|
return iso
|
|
|
|
|
2018-10-19 13:14:33 +00:00
|
|
|
def delete_all_disks(self):
|
2018-10-24 09:04:05 +00:00
|
|
|
disks = self.get_disk_devices()
|
2015-02-27 08:53:51 +00:00
|
|
|
for disk in disks:
|
|
|
|
vol = self.get_volume_by_path(disk.get('path'))
|
|
|
|
vol.delete(0)
|
|
|
|
|
|
|
|
def _snapshotCreateXML(self, xml, flag):
|
|
|
|
self.instance.snapshotCreateXML(xml, flag)
|
|
|
|
|
|
|
|
def create_snapshot(self, name):
|
|
|
|
xml = """<domainsnapshot>
|
|
|
|
<name>%s</name>
|
|
|
|
<state>shutoff</state>
|
|
|
|
<creationTime>%d</creationTime>""" % (name, time.time())
|
|
|
|
xml += self._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
|
|
|
xml += """<active>0</active>
|
|
|
|
</domainsnapshot>"""
|
|
|
|
self._snapshotCreateXML(xml, 0)
|
|
|
|
|
|
|
|
def get_snapshot(self):
|
|
|
|
snapshots = []
|
|
|
|
snapshot_list = self.instance.snapshotListNames(0)
|
|
|
|
for snapshot in snapshot_list:
|
|
|
|
snap = self.instance.snapshotLookupByName(snapshot, 0)
|
|
|
|
snap_time_create = util.get_xml_path(snap.getXMLDesc(0), "/domainsnapshot/creationTime")
|
|
|
|
snapshots.append({'date': datetime.fromtimestamp(int(snap_time_create)), 'name': snapshot})
|
|
|
|
return snapshots
|
|
|
|
|
|
|
|
def snapshot_delete(self, snapshot):
|
|
|
|
snap = self.instance.snapshotLookupByName(snapshot, 0)
|
|
|
|
snap.delete(0)
|
|
|
|
|
|
|
|
def snapshot_revert(self, snapshot):
|
|
|
|
snap = self.instance.snapshotLookupByName(snapshot, 0)
|
|
|
|
self.instance.revertToSnapshot(snap, 0)
|
|
|
|
|
|
|
|
def get_managed_save_image(self):
|
|
|
|
return self.instance.hasManagedSaveImage(0)
|
|
|
|
|
2015-11-13 09:15:38 +00:00
|
|
|
def get_wvmStorage(self, pool):
|
|
|
|
storage = wvmStorage(self.host,
|
|
|
|
self.login,
|
|
|
|
self.passwd,
|
|
|
|
self.conn,
|
|
|
|
pool)
|
|
|
|
return storage
|
|
|
|
|
2016-01-29 13:44:19 +00:00
|
|
|
def fix_mac(self, mac):
|
|
|
|
if ":" in mac:
|
|
|
|
return mac
|
|
|
|
# if mac does not contain ":", try to split into tuples and join with ":"
|
|
|
|
n = 2
|
|
|
|
mac_tuples = [mac[i:i+n] for i in range(0, len(mac), n)]
|
|
|
|
return ':'.join(mac_tuples)
|
|
|
|
|
2015-02-27 08:53:51 +00:00
|
|
|
def clone_instance(self, clone_data):
|
|
|
|
clone_dev_path = []
|
|
|
|
|
|
|
|
xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
|
|
|
tree = ElementTree.fromstring(xml)
|
|
|
|
name = tree.find('name')
|
|
|
|
name.text = clone_data['name']
|
|
|
|
uuid = tree.find('uuid')
|
|
|
|
tree.remove(uuid)
|
|
|
|
|
|
|
|
for num, net in enumerate(tree.findall('devices/interface')):
|
|
|
|
elm = net.find('mac')
|
2016-02-10 16:52:50 +00:00
|
|
|
mac_address = self.fix_mac(clone_data['clone-net-mac-' + str(num)])
|
2016-01-29 13:44:19 +00:00
|
|
|
elm.set('address', mac_address)
|
2015-02-27 08:53:51 +00:00
|
|
|
|
|
|
|
for disk in tree.findall('devices/disk'):
|
|
|
|
if disk.get('device') == 'disk':
|
|
|
|
elm = disk.find('target')
|
|
|
|
device_name = elm.get('dev')
|
|
|
|
if device_name:
|
|
|
|
target_file = clone_data['disk-' + device_name]
|
|
|
|
try:
|
|
|
|
meta_prealloc = clone_data['meta-' + device_name]
|
|
|
|
except:
|
|
|
|
meta_prealloc = False
|
|
|
|
elm.set('dev', device_name)
|
|
|
|
|
|
|
|
elm = disk.find('source')
|
|
|
|
source_file = elm.get('file')
|
|
|
|
if source_file:
|
|
|
|
clone_dev_path.append(source_file)
|
2018-09-27 06:45:10 +00:00
|
|
|
clone_path = os.path.join(os.path.dirname(source_file), target_file)
|
2015-02-27 08:53:51 +00:00
|
|
|
elm.set('file', clone_path)
|
|
|
|
|
|
|
|
vol = self.get_volume_by_path(source_file)
|
2018-09-27 06:45:10 +00:00
|
|
|
vol_format = util.get_xml_path(vol.XMLDesc(0), "/volume/target/format/@type")
|
2015-02-27 08:53:51 +00:00
|
|
|
|
|
|
|
if vol_format == 'qcow2' and meta_prealloc:
|
|
|
|
meta_prealloc = True
|
2018-10-05 14:07:25 +00:00
|
|
|
|
2015-02-27 08:53:51 +00:00
|
|
|
vol_clone_xml = """
|
|
|
|
<volume>
|
|
|
|
<name>%s</name>
|
|
|
|
<capacity>0</capacity>
|
|
|
|
<allocation>0</allocation>
|
|
|
|
<target>
|
|
|
|
<format type='%s'/>
|
2019-04-04 13:04:34 +00:00
|
|
|
<permissions>
|
|
|
|
<owner>%s</owner>
|
|
|
|
<group>%s</group>
|
|
|
|
<mode>0644</mode>
|
|
|
|
<label>virt_image_t</label>
|
|
|
|
</permissions>
|
|
|
|
<compat>1.1</compat>
|
|
|
|
<features>
|
|
|
|
<lazy_refcounts/>
|
|
|
|
</features>
|
2015-02-27 08:53:51 +00:00
|
|
|
</target>
|
2018-10-05 14:07:25 +00:00
|
|
|
</volume>""" % (target_file, vol_format, owner['uid'], owner['guid'])
|
2019-04-04 13:04:34 +00:00
|
|
|
|
2015-02-27 08:53:51 +00:00
|
|
|
stg = vol.storagePoolLookupByVolume()
|
|
|
|
stg.createXMLFrom(vol_clone_xml, vol, meta_prealloc)
|
2015-11-13 09:15:38 +00:00
|
|
|
|
2018-09-04 13:40:47 +00:00
|
|
|
source_protocol = elm.get('protocol')
|
|
|
|
if source_protocol == 'rbd':
|
|
|
|
source_name = elm.get('name')
|
|
|
|
clone_name = "%s/%s" % (os.path.dirname(source_name), target_file)
|
|
|
|
elm.set('name', clone_name)
|
|
|
|
|
|
|
|
vol = self.get_volume_by_path(source_name)
|
2018-09-27 06:45:10 +00:00
|
|
|
vol_format = util.get_xml_path(vol.XMLDesc(0), "/volume/target/format/@type")
|
2018-09-04 13:40:47 +00:00
|
|
|
|
|
|
|
vol_clone_xml = """
|
|
|
|
<volume type='network'>
|
|
|
|
<name>%s</name>
|
|
|
|
<capacity>0</capacity>
|
|
|
|
<allocation>0</allocation>
|
|
|
|
<target>
|
|
|
|
<format type='%s'/>
|
|
|
|
</target>
|
|
|
|
</volume>""" % (target_file, vol_format)
|
|
|
|
stg = vol.storagePoolLookupByVolume()
|
|
|
|
stg.createXMLFrom(vol_clone_xml, vol, meta_prealloc)
|
|
|
|
|
2015-11-13 09:15:38 +00:00
|
|
|
source_dev = elm.get('dev')
|
|
|
|
if source_dev:
|
|
|
|
clone_path = os.path.join(os.path.dirname(source_dev), target_file)
|
|
|
|
elm.set('dev', clone_path)
|
|
|
|
|
|
|
|
vol = self.get_volume_by_path(source_dev)
|
|
|
|
stg = vol.storagePoolLookupByVolume()
|
|
|
|
|
|
|
|
vol_name = util.get_xml_path(vol.XMLDesc(0), "/volume/name")
|
|
|
|
pool_name = util.get_xml_path(stg.XMLDesc(0), "/pool/name")
|
|
|
|
|
|
|
|
storage = self.get_wvmStorage(pool_name)
|
|
|
|
storage.clone_volume(vol_name, target_file)
|
2016-02-24 12:08:43 +00:00
|
|
|
|
|
|
|
options = {
|
|
|
|
'title': clone_data.get('clone-title', ''),
|
|
|
|
'description': clone_data.get('clone-description', ''),
|
|
|
|
}
|
|
|
|
self._set_options(tree, options)
|
2015-02-27 08:53:51 +00:00
|
|
|
self._defineXML(ElementTree.tostring(tree))
|
2016-01-14 15:59:50 +00:00
|
|
|
|
2016-03-23 08:00:42 +00:00
|
|
|
return self.get_instance(clone_data['name']).UUIDString()
|
|
|
|
|
2018-08-28 10:18:35 +00:00
|
|
|
def get_bridge_name(self, source, source_type='net'):
|
|
|
|
if source_type == 'iface':
|
|
|
|
iface = self.get_iface(source)
|
|
|
|
bridge_name = iface.name()
|
|
|
|
else:
|
|
|
|
net = self.get_network(source)
|
|
|
|
bridge_name = net.bridgeName()
|
|
|
|
return bridge_name
|
|
|
|
|
2018-09-24 11:41:13 +00:00
|
|
|
def add_network(self, mac_address, source, source_type='net', interface_type='bridge', model='virtio', nwfilter=None):
|
2018-08-28 10:18:35 +00:00
|
|
|
bridge_name = self.get_bridge_name(source, source_type)
|
2018-08-28 08:55:27 +00:00
|
|
|
xml_interface = """
|
|
|
|
<interface type='%s'>
|
|
|
|
<mac address='%s'/>
|
|
|
|
<source bridge='%s'/>
|
|
|
|
<model type='%s'/>
|
2018-09-24 11:41:13 +00:00
|
|
|
""" % (interface_type, mac_address, bridge_name, model)
|
|
|
|
if nwfilter:
|
|
|
|
xml_interface += """
|
|
|
|
<filterref filter='%s'/>
|
|
|
|
""" % nwfilter
|
|
|
|
xml_interface += """</interface>"""
|
|
|
|
|
2019-07-17 10:52:14 +00:00
|
|
|
if self.get_status() == 1:
|
|
|
|
self.instance.attachDeviceFlags(xml_interface, VIR_DOMAIN_AFFECT_LIVE)
|
|
|
|
self.instance.attachDeviceFlags(xml_interface, VIR_DOMAIN_AFFECT_CONFIG)
|
2018-08-28 08:55:27 +00:00
|
|
|
if self.get_status() == 5:
|
2019-07-17 10:52:14 +00:00
|
|
|
self.instance.attachDeviceFlags(xml_interface, VIR_DOMAIN_AFFECT_CONFIG)
|
2018-08-28 08:55:27 +00:00
|
|
|
|
2018-09-26 14:20:46 +00:00
|
|
|
def delete_network(self, mac_address):
|
|
|
|
tree = ElementTree.fromstring(self._XMLDesc(0))
|
|
|
|
for interface in tree.findall('devices/interface'):
|
|
|
|
source = interface.find('mac')
|
|
|
|
if source.get('address', '') == mac_address:
|
2019-07-17 10:52:14 +00:00
|
|
|
new_xml = ElementTree.tostring(interface)
|
|
|
|
|
|
|
|
if self.get_status() == 1:
|
|
|
|
self.instance.detachDeviceFlags(new_xml, VIR_DOMAIN_AFFECT_LIVE)
|
|
|
|
self.instance.detachDeviceFlags(new_xml, VIR_DOMAIN_AFFECT_CONFIG)
|
|
|
|
if self.get_status() == 5:
|
|
|
|
self.instance.detachDeviceFlags(new_xml, VIR_DOMAIN_AFFECT_CONFIG)
|
2018-09-26 14:20:46 +00:00
|
|
|
|
2016-01-14 15:59:50 +00:00
|
|
|
def change_network(self, network_data):
|
|
|
|
xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
|
|
|
tree = ElementTree.fromstring(xml)
|
2016-02-10 16:52:50 +00:00
|
|
|
for num, interface in enumerate(tree.findall('devices/interface')):
|
2018-08-28 10:18:35 +00:00
|
|
|
net_source = network_data['net-source-' + str(num)]
|
|
|
|
net_source_type = network_data['net-source-' + str(num) + '-type']
|
|
|
|
net_mac = network_data['net-mac-' + str(num)]
|
2018-09-26 14:20:46 +00:00
|
|
|
net_filter = network_data['net-nwfilter-' + str(num)]
|
2018-08-28 10:18:35 +00:00
|
|
|
bridge_name = self.get_bridge_name(net_source, net_source_type)
|
2016-01-14 15:59:50 +00:00
|
|
|
if interface.get('type') == 'bridge':
|
2016-02-10 16:52:50 +00:00
|
|
|
source = interface.find('mac')
|
2018-08-28 10:18:35 +00:00
|
|
|
source.set('address', net_mac)
|
2016-01-14 15:59:50 +00:00
|
|
|
source = interface.find('source')
|
2018-08-28 10:18:35 +00:00
|
|
|
source.set('bridge', bridge_name)
|
2018-09-26 14:20:46 +00:00
|
|
|
source = interface.find('filterref')
|
|
|
|
|
|
|
|
if net_filter:
|
|
|
|
if source is not None: source.set('filter', net_filter)
|
|
|
|
else:
|
|
|
|
element = ElementTree.Element("filterref")
|
|
|
|
element.attrib['filter'] = net_filter
|
|
|
|
interface.append(element)
|
|
|
|
else:
|
2019-01-25 10:42:48 +00:00
|
|
|
if source is not None: interface.remove(source)
|
|
|
|
elif interface.get('type') == 'network':
|
|
|
|
source = interface.find('mac')
|
|
|
|
source.set('address', net_mac)
|
|
|
|
source = interface.find('source')
|
|
|
|
source.set('network', net_source)
|
|
|
|
source = interface.find('filterref')
|
|
|
|
|
|
|
|
if net_filter:
|
|
|
|
if source is not None: source.set('filter', net_filter)
|
|
|
|
else:
|
|
|
|
element = ElementTree.Element("filterref")
|
|
|
|
element.attrib['filter'] = net_filter
|
|
|
|
interface.append(element)
|
|
|
|
else:
|
2018-09-26 14:20:46 +00:00
|
|
|
if source is not None: interface.remove(source)
|
|
|
|
|
2016-01-14 15:59:50 +00:00
|
|
|
new_xml = ElementTree.tostring(tree)
|
|
|
|
self._defineXML(new_xml)
|
|
|
|
|
2016-02-24 12:08:43 +00:00
|
|
|
def _set_options(self, tree, options):
|
2016-02-23 13:43:32 +00:00
|
|
|
for o in ['title', 'description']:
|
|
|
|
option = tree.find(o)
|
2016-04-27 13:32:40 +00:00
|
|
|
option_value = options.get(o, '').strip()
|
2016-02-23 13:43:32 +00:00
|
|
|
if not option_value:
|
2019-09-10 06:48:31 +00:00
|
|
|
if option is not None:
|
2016-02-23 13:43:32 +00:00
|
|
|
tree.remove(option)
|
|
|
|
else:
|
|
|
|
if option is None:
|
|
|
|
option = ElementTree.SubElement(tree, o)
|
|
|
|
option.text = option_value
|
|
|
|
|
2016-02-24 12:08:43 +00:00
|
|
|
def set_options(self, options):
|
|
|
|
"""
|
|
|
|
Function change description, title
|
|
|
|
"""
|
|
|
|
xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
|
|
|
tree = ElementTree.fromstring(xml)
|
|
|
|
|
|
|
|
self._set_options(tree, options)
|
|
|
|
|
2016-02-23 13:43:32 +00:00
|
|
|
new_xml = ElementTree.tostring(tree)
|
|
|
|
self._defineXML(new_xml)
|
|
|
|
|
2018-11-20 14:07:19 +00:00
|
|
|
def set_memory(self, size, flags=0):
|
|
|
|
self.instance.setMemoryFlags(size, flags)
|
|
|
|
|