Coverage for nova/virt/libvirt/config.py: 92%
2790 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-17 15:08 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-17 15:08 +0000
1# Copyright (C) 2012-2013 Red Hat, Inc.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
15"""
16Configuration for libvirt objects.
18Classes to represent the configuration of various libvirt objects
19and support conversion to/from XML. These classes are solely concerned
20by providing direct Object <-> XML document conversions. No policy or
21operational decisions should be made by code in these classes. Such
22policy belongs in the 'designer.py' module which provides simplified
23helpers for populating up config object instances.
24"""
26import time
27import typing as ty
29from collections import OrderedDict
30from lxml import etree
31from oslo_log import log as logging
32from oslo_utils import strutils
33from oslo_utils import units
35from nova import exception
36from nova.i18n import _
37from nova.objects import fields
38from nova.pci import utils as pci_utils
39from nova.virt import hardware
41LOG = logging.getLogger(__name__)
43# Namespace to use for Nova specific metadata items in XML
44NOVA_NS = "http://openstack.org/xmlns/libvirt/nova/1.1"
47def make_libvirt_device_alias(identifier):
48 return 'ua-%s' % identifier
51def parse_libvirt_device_alias(alias):
52 if alias.startswith('ua-'):
53 return alias.split('-', 1)[1]
54 else:
55 return alias
58class LibvirtConfigObject(object):
60 def __init__(self, **kwargs):
61 super(LibvirtConfigObject, self).__init__()
63 self.root_name = kwargs.pop("root_name")
64 self.ns_prefix = kwargs.pop("ns_prefix", None)
65 self.ns_uri = kwargs.pop("ns_uri", None)
67 # handle programmer error
68 assert not kwargs
70 def _new_node(self, node_name, **kwargs):
71 if self.ns_uri is None:
72 return etree.Element(node_name, **kwargs)
73 else:
74 return etree.Element("{" + self.ns_uri + "}" + node_name,
75 nsmap={self.ns_prefix: self.ns_uri},
76 **kwargs)
78 def _text_node(self, node_name, value, **kwargs):
79 child = self._new_node(node_name, **kwargs)
80 if value is not None:
81 child.text = str(value)
82 return child
84 def format_dom(self):
85 return self._new_node(self.root_name)
87 def parse_str(self, xmlstr):
88 try:
89 self.parse_dom(etree.fromstring(xmlstr))
90 except etree.Error:
91 LOG.debug("Failed to parse the libvirt XML: %s", xmlstr)
92 raise
94 def parse_dom(self, xmldoc):
95 if self.root_name != xmldoc.tag: 95 ↛ 96line 95 didn't jump to line 96 because the condition on line 95 was never true
96 msg = (_("Root element name should be '%(name)s' not '%(tag)s'") %
97 {'name': self.root_name, 'tag': xmldoc.tag})
98 raise exception.InvalidInput(msg)
100 def to_xml(self, pretty_print=True):
101 root = self.format_dom()
102 xml_str = etree.tostring(root, encoding='unicode',
103 pretty_print=pretty_print)
104 return xml_str
106 @classmethod
107 def parse_on_off_str(self, value: ty.Optional[str]) -> bool:
108 if value is not None and value not in ('on', 'off'):
109 msg = _(
110 "Element should contain either 'on' or 'off'; "
111 "found: '%(value)s'"
112 )
113 raise exception.InvalidInput(msg % {'value': value})
115 return value == 'on'
117 @classmethod
118 def get_yes_no_str(self, value: bool) -> str:
119 return 'yes' if value else 'no'
121 @classmethod
122 def get_on_off_str(self, value: bool) -> str:
123 return 'on' if value else 'off'
125 def __repr__(self):
126 return self.to_xml(pretty_print=False)
129class LibvirtConfigCaps(LibvirtConfigObject):
131 def __init__(self, **kwargs):
132 super(LibvirtConfigCaps, self).__init__(root_name="capabilities",
133 **kwargs)
134 self.host = None
135 self.guests = []
137 def parse_dom(self, xmldoc):
138 super(LibvirtConfigCaps, self).parse_dom(xmldoc)
140 for c in xmldoc:
141 if c.tag == "host":
142 host = LibvirtConfigCapsHost()
143 host.parse_dom(c)
144 self.host = host
145 elif c.tag == "guest": 145 ↛ 140line 145 didn't jump to line 140 because the condition on line 145 was always true
146 guest = LibvirtConfigCapsGuest()
147 guest.parse_dom(c)
148 self.guests.append(guest)
150 def format_dom(self):
151 caps = super(LibvirtConfigCaps, self).format_dom()
153 if self.host:
154 caps.append(self.host.format_dom())
155 for g in self.guests:
156 caps.append(g.format_dom())
158 return caps
161class LibvirtConfigDomainCaps(LibvirtConfigObject):
163 def __init__(self, **kwargs):
164 super(LibvirtConfigDomainCaps, self).__init__(
165 root_name="domainCapabilities", **kwargs)
166 self._features = None
167 self._machine = None
168 self._alias = None
169 self._devices = None
170 self._os = None
172 def parse_dom(self, xmldoc):
173 super(LibvirtConfigDomainCaps, self).parse_dom(xmldoc)
175 for c in xmldoc:
176 if c.tag == "features":
177 features = LibvirtConfigDomainCapsFeatures()
178 features.parse_dom(c)
179 self._features = features
180 elif c.tag == "machine":
181 self._machine = c.text
182 elif c.tag == "devices":
183 devices = LibvirtConfigDomainCapsDevices()
184 devices.parse_dom(c)
185 self._devices = devices
186 elif c.tag == "os":
187 os = LibvirtConfigDomainCapsOS()
188 os.parse_dom(c)
189 self._os = os
191 @property
192 def features(self):
193 if self._features is None:
194 return []
195 return self._features.features
197 @property
198 def machine_type(self):
199 if self._machine is None: 199 ↛ 200line 199 didn't jump to line 200 because the condition on line 199 was never true
200 return ""
201 return self._machine
203 @property
204 def machine_type_alias(self):
205 if self._alias is None:
206 return self._machine
207 return self._alias
209 @machine_type_alias.setter
210 def machine_type_alias(self, alias):
211 self._alias = alias
213 @property
214 def devices(self):
215 if self._devices is None: 215 ↛ 216line 215 didn't jump to line 216 because the condition on line 215 was never true
216 return []
217 return self._devices
219 @property
220 def os(self):
221 return self._os
224class LibvirtConfigDomainCapsVideoModels(LibvirtConfigObject):
226 def __init__(self, **kwargs):
227 super().__init__(root_name='video', **kwargs)
228 self.supported = False
229 self.models = set()
231 def parse_dom(self, xmldoc):
232 super().parse_dom(xmldoc)
234 if xmldoc.get('supported') == 'yes': 234 ↛ 236line 234 didn't jump to line 236 because the condition on line 234 was always true
235 self.supported = True
236 self.models = {str(node) for node in
237 xmldoc.xpath("//enum[@name='modelType']/value/text()")}
240class LibvirtConfigDomainCapsDiskBuses(LibvirtConfigObject):
242 def __init__(self, **kwargs):
243 super().__init__(root_name='disk', **kwargs)
244 self.supported = False
245 self.buses = set()
247 def parse_dom(self, xmldoc):
248 super(LibvirtConfigDomainCapsDiskBuses, self).parse_dom(xmldoc)
250 if xmldoc.get('supported') == 'yes': 250 ↛ 252line 250 didn't jump to line 252 because the condition on line 250 was always true
251 self.supported = True
252 self.buses = {str(node) for node in
253 xmldoc.xpath("//enum[@name='bus']/value/text()")}
256class LibvirtConfigDomainCapsTpm(LibvirtConfigObject):
258 def __init__(self, **kwargs):
259 super().__init__(root_name='tpm', **kwargs)
260 self.supported = False
261 self.models = []
262 self.backend_models = []
263 # TODO(tkajinam): Change default to [] once libvirt >= 8.6.0 is
264 # required
265 self.backend_versions = None
267 def parse_dom(self, xmldoc):
268 super(LibvirtConfigDomainCapsTpm, self).parse_dom(xmldoc)
270 if xmldoc.get('supported'): 270 ↛ 272line 270 didn't jump to line 272 because the condition on line 270 was always true
271 self.supported = (xmldoc.get('supported') == 'yes')
272 for c in xmldoc:
273 if c.tag == 'enum': 273 ↛ 272line 273 didn't jump to line 272 because the condition on line 273 was always true
274 if c.get('name') == 'model':
275 for c2 in c:
276 if c2.tag == 'value': 276 ↛ 275line 276 didn't jump to line 275 because the condition on line 276 was always true
277 self.models.append(c2.text)
278 if c.get('name') == 'backendModel':
279 for c2 in c:
280 if c2.tag == 'value': 280 ↛ 279line 280 didn't jump to line 279 because the condition on line 280 was always true
281 self.backend_models.append(c2.text)
282 if c.get('name') == 'backendVersion':
283 for c2 in c:
284 if c2.tag == 'value': 284 ↛ 283line 284 didn't jump to line 283 because the condition on line 284 was always true
285 if self.backend_versions is None: 285 ↛ 287line 285 didn't jump to line 287 because the condition on line 285 was always true
286 self.backend_versions = []
287 self.backend_versions.append(c2.text)
290class LibvirtConfigDomainCapsDevices(LibvirtConfigObject):
291 DEVICE_PARSERS = {
292 'video': LibvirtConfigDomainCapsVideoModels,
293 'disk': LibvirtConfigDomainCapsDiskBuses,
294 'tpm': LibvirtConfigDomainCapsTpm,
295 }
297 def __init__(self, **kwargs):
298 super().__init__(root_name='devices', **kwargs)
299 self.devices = set()
301 def parse_dom(self, xmldoc):
302 super().parse_dom(xmldoc)
304 for c in list(xmldoc):
305 device = self.DEVICE_PARSERS.get(c.tag)
306 if device:
307 device = device()
308 device.parse_dom(c)
309 self.devices.add(device)
311 def _get_device(self, device_type):
312 for device in self.devices:
313 if type(device) is self.DEVICE_PARSERS.get(device_type):
314 return device
315 return None
317 @property
318 def disk(self):
319 return self._get_device('disk')
321 @property
322 def video(self):
323 return self._get_device('video')
325 @property
326 def tpm(self):
327 return self._get_device('tpm')
330class LibvirtConfigDomainCapsFeatures(LibvirtConfigObject):
332 def __init__(self, **kwargs):
333 super(LibvirtConfigDomainCapsFeatures, self).__init__(
334 root_name="features", **kwargs)
335 self.features = []
337 def parse_dom(self, xmldoc):
338 super(LibvirtConfigDomainCapsFeatures, self).parse_dom(xmldoc)
340 for c in xmldoc:
341 feature = None
342 if c.tag == "sev":
343 feature = LibvirtConfigDomainCapsFeatureSev()
344 if feature:
345 feature.parse_dom(c)
346 self.features.append(feature)
348 # There are many other features and domain capabilities,
349 # but we don't need to regenerate the XML (it's read-only
350 # data provided by libvirtd), so there's no point parsing
351 # them until we actually need their values.
353 # For the same reason, we do not need a format_dom() method, but
354 # it's a bug if this ever gets called and we inherited one from
355 # the base class, so override that to watch out for accidental
356 # calls.
357 def format_dom(self):
358 raise RuntimeError(_('BUG: tried to generate domainCapabilities XML'))
361class LibvirtConfigDomainCapsFeatureSev(LibvirtConfigObject):
363 def __init__(self, **kwargs):
364 super(LibvirtConfigDomainCapsFeatureSev, self).__init__(
365 root_name='sev', **kwargs)
366 self.supported = False
367 self.cbitpos = None
368 self.reduced_phys_bits = None
369 self.max_guests = None
370 self.max_es_guests = None
372 def parse_dom(self, xmldoc):
373 super(LibvirtConfigDomainCapsFeatureSev, self).parse_dom(xmldoc)
375 if xmldoc.get('supported') == 'yes':
376 self.supported = True
378 for c in list(xmldoc):
379 if c.tag == 'reducedPhysBits':
380 self.reduced_phys_bits = int(c.text)
381 elif c.tag == 'cbitpos':
382 self.cbitpos = int(c.text)
383 elif c.tag == 'maxGuests':
384 self.max_guests = int(c.text)
385 elif c.tag == 'maxESGuests': 385 ↛ 378line 385 didn't jump to line 378 because the condition on line 385 was always true
386 self.max_es_guests = int(c.text)
389class LibvirtConfigDomainCapsOS(LibvirtConfigObject):
391 def __init__(self, **kwargs):
392 super().__init__(root_name='os', **kwargs)
394 self.supported = False
395 self.loader_supported = None
396 self.uefi_autoconfig_supported = None
397 self.loader_paths = []
398 self.uefi_supported = None
399 self.secure_boot_supported = None
401 def parse_dom(self, xmldoc):
402 super().parse_dom(xmldoc)
404 self.supported = xmldoc.get('supported')
406 for c in xmldoc:
407 self.loader_supported = c.get('supported')
409 if c.tag == 'enum':
410 if c.get('name') == 'firmware': 410 ↛ 406line 410 didn't jump to line 406 because the condition on line 410 was always true
411 # theoretically we can also do autoconfiguration of BIOS
412 # but it's unlikely that anything supports this yet
413 self.uefi_autoconfig_supported = 'efi' in [
414 child.text for child in c if child.tag == 'value'
415 ]
416 elif c.tag == 'loader': 416 ↛ 406line 416 didn't jump to line 406 because the condition on line 416 was always true
417 for c2 in c:
418 if c2.tag == 'value':
419 self.loader_paths.append(c2.text)
420 elif c2.tag == 'enum': 420 ↛ 417line 420 didn't jump to line 417 because the condition on line 420 was always true
421 if c2.get('name') == 'type':
422 self.uefi_supported = 'pflash' in [
423 val.text for val in c2 if val.tag == 'value'
424 ]
425 elif c2.get('name') == 'secure':
426 # we might want to ensure 'no' is also supported,
427 # but a platform that only supports SB sounds odd
428 self.secure_boot_supported = 'yes' in [
429 val.text for val in c2 if val.tag == 'value'
430 ]
433class LibvirtConfigCapsNUMATopology(LibvirtConfigObject):
435 def __init__(self, **kwargs):
436 super(LibvirtConfigCapsNUMATopology, self).__init__(
437 root_name="topology",
438 **kwargs)
440 self.cells = []
442 def parse_dom(self, xmldoc):
443 super(LibvirtConfigCapsNUMATopology, self).parse_dom(xmldoc)
445 xmlcells = xmldoc[0]
446 for xmlcell in xmlcells:
447 cell = LibvirtConfigCapsNUMACell()
448 cell.parse_dom(xmlcell)
449 self.cells.append(cell)
451 def format_dom(self):
452 topo = super(LibvirtConfigCapsNUMATopology, self).format_dom()
454 cells = etree.Element("cells")
455 cells.set("num", str(len(self.cells)))
456 topo.append(cells)
458 for cell in self.cells:
459 cells.append(cell.format_dom())
461 return topo
464class LibvirtConfigCapsNUMACell(LibvirtConfigObject):
466 def __init__(self, **kwargs):
467 super(LibvirtConfigCapsNUMACell, self).__init__(root_name="cell",
468 **kwargs)
470 self.id = None
471 self.memory = 0
472 self.mempages = []
473 self.cpus = []
475 def parse_dom(self, xmldoc):
476 super(LibvirtConfigCapsNUMACell, self).parse_dom(xmldoc)
478 self.id = int(xmldoc.get("id"))
479 for c in xmldoc:
480 if c.tag == "memory":
481 self.memory = int(c.text)
482 elif c.tag == "pages":
483 pages = LibvirtConfigCapsNUMAPages()
484 pages.parse_dom(c)
485 self.mempages.append(pages)
486 elif c.tag == "cpus": 486 ↛ 479line 486 didn't jump to line 479 because the condition on line 486 was always true
487 for c2 in c:
488 cpu = LibvirtConfigCapsNUMACPU()
489 cpu.parse_dom(c2)
490 self.cpus.append(cpu)
492 def format_dom(self):
493 cell = super(LibvirtConfigCapsNUMACell, self).format_dom()
495 cell.set("id", str(self.id))
497 mem = etree.Element("memory")
498 mem.set("unit", "KiB")
499 mem.text = str(self.memory)
500 cell.append(mem)
502 for pages in self.mempages:
503 cell.append(pages.format_dom())
505 cpus = etree.Element("cpus")
506 cpus.set("num", str(len(self.cpus)))
507 for cpu in self.cpus:
508 cpus.append(cpu.format_dom())
509 cell.append(cpus)
511 return cell
514class LibvirtConfigCapsNUMACPU(LibvirtConfigObject):
516 def __init__(self, **kwargs):
517 super(LibvirtConfigCapsNUMACPU, self).__init__(root_name="cpu",
518 **kwargs)
520 self.id = None
521 self.socket_id = None
522 self.core_id = None
523 self.siblings = None
525 def parse_dom(self, xmldoc):
526 super(LibvirtConfigCapsNUMACPU, self).parse_dom(xmldoc)
528 self.id = int(xmldoc.get("id"))
529 if xmldoc.get("socket_id") is not None: 529 ↛ 531line 529 didn't jump to line 531 because the condition on line 529 was always true
530 self.socket_id = int(xmldoc.get("socket_id"))
531 if xmldoc.get("core_id") is not None: 531 ↛ 534line 531 didn't jump to line 534 because the condition on line 531 was always true
532 self.core_id = int(xmldoc.get("core_id"))
534 if xmldoc.get("siblings") is not None: 534 ↛ exitline 534 didn't return from function 'parse_dom' because the condition on line 534 was always true
535 self.siblings = hardware.parse_cpu_spec(
536 xmldoc.get("siblings"))
538 def format_dom(self):
539 cpu = super(LibvirtConfigCapsNUMACPU, self).format_dom()
541 cpu.set("id", str(self.id))
542 if self.socket_id is not None: 542 ↛ 544line 542 didn't jump to line 544 because the condition on line 542 was always true
543 cpu.set("socket_id", str(self.socket_id))
544 if self.core_id is not None: 544 ↛ 546line 544 didn't jump to line 546 because the condition on line 544 was always true
545 cpu.set("core_id", str(self.core_id))
546 if self.siblings is not None: 546 ↛ 550line 546 didn't jump to line 550 because the condition on line 546 was always true
547 cpu.set("siblings",
548 hardware.format_cpu_spec(self.siblings))
550 return cpu
553class LibvirtConfigCapsNUMAPages(LibvirtConfigObject):
555 def __init__(self, **kwargs):
556 super(LibvirtConfigCapsNUMAPages, self).__init__(
557 root_name="pages", **kwargs)
559 self.size = None
560 self.total = None
562 def parse_dom(self, xmldoc):
563 super(LibvirtConfigCapsNUMAPages, self).parse_dom(xmldoc)
565 self.size = int(xmldoc.get("size"))
566 self.total = int(xmldoc.text)
568 def format_dom(self):
569 pages = super(LibvirtConfigCapsNUMAPages, self).format_dom()
571 pages.text = str(self.total)
572 pages.set("size", str(self.size))
573 pages.set("unit", "KiB")
575 return pages
578class LibvirtConfigCapsHost(LibvirtConfigObject):
580 def __init__(self, **kwargs):
581 super(LibvirtConfigCapsHost, self).__init__(root_name="host",
582 **kwargs)
584 self.cpu = None
585 self.uuid = None
586 self.topology = None
588 def parse_dom(self, xmldoc):
589 super(LibvirtConfigCapsHost, self).parse_dom(xmldoc)
591 for c in xmldoc:
592 if c.tag == "cpu":
593 cpu = LibvirtConfigCPU()
594 cpu.parse_dom(c)
595 self.cpu = cpu
596 elif c.tag == "uuid":
597 self.uuid = c.text
598 elif c.tag == "topology":
599 self.topology = LibvirtConfigCapsNUMATopology()
600 self.topology.parse_dom(c)
602 def format_dom(self):
603 caps = super(LibvirtConfigCapsHost, self).format_dom()
605 if self.uuid:
606 caps.append(self._text_node("uuid", self.uuid))
607 if self.cpu: 607 ↛ 609line 607 didn't jump to line 609 because the condition on line 607 was always true
608 caps.append(self.cpu.format_dom())
609 if self.topology:
610 caps.append(self.topology.format_dom())
612 return caps
615class LibvirtConfigCapsGuest(LibvirtConfigObject):
617 def __init__(self, **kwargs):
618 super(LibvirtConfigCapsGuest, self).__init__(root_name="guest",
619 **kwargs)
621 self.arch = None
622 self.ostype = None
623 # Map domain types such as 'qemu' and 'kvm' to
624 # LibvirtConfigCapsGuestDomain instances.
625 self.domains = OrderedDict()
626 self.default_domain = None
628 def parse_dom(self, xmldoc):
629 super(LibvirtConfigCapsGuest, self).parse_dom(xmldoc)
631 for child in xmldoc:
632 if child.tag == "os_type":
633 self.ostype = child.text
634 elif child.tag == "arch":
635 self.parse_arch(child)
637 def parse_arch(self, xmldoc):
638 self.arch = xmldoc.get("name")
639 # NOTE(aspiers): The data relating to each <domain> element
640 # under <arch> (such as <emulator> and many <machine>
641 # elements) is structured in a slightly odd way. There is one
642 # "default" domain such as
643 #
644 # <domain type='qemu'/>
645 #
646 # which has no child elements, and all its data is provided in
647 # sibling elements. Then others such as
648 #
649 # <domain type='kvm'>
650 #
651 # will have their <emulator> and <machine> elements as
652 # children. So we need to handle the two cases separately.
653 self.default_domain = LibvirtConfigCapsGuestDomain()
654 for child in xmldoc:
655 if child.tag == "domain":
656 if list(child):
657 # This domain has children, so create a new instance,
658 # parse it, and register it in the dict of domains.
659 domain = LibvirtConfigCapsGuestDomain()
660 domain.parse_dom(child)
661 self.domains[domain.domtype] = domain
662 else:
663 # This is the childless <domain/> element for the
664 # default domain
665 self.default_domain.parse_domain(child)
666 self.domains[self.default_domain.domtype] = \
667 self.default_domain
668 else:
669 # Sibling element of the default domain
670 self.default_domain.parse_child(child)
672 def format_dom(self):
673 caps = super(LibvirtConfigCapsGuest, self).format_dom()
675 if self.ostype is not None: 675 ↛ 677line 675 didn't jump to line 677 because the condition on line 675 was always true
676 caps.append(self._text_node("os_type", self.ostype))
677 if self.arch: 677 ↛ 681line 677 didn't jump to line 681 because the condition on line 677 was always true
678 arch = self.format_arch()
679 caps.append(arch)
681 return caps
683 def format_arch(self):
684 arch = etree.Element("arch", name=self.arch)
686 for c in self.default_domain.format_dom():
687 arch.append(c)
688 arch.append(self._new_node("domain", type=self.default_domain.domtype))
690 for domtype, domain in self.domains.items():
691 if domtype == self.default_domain.domtype:
692 # We've already added this domain at the top level
693 continue
694 arch.append(domain.format_dom())
696 return arch
699class LibvirtConfigCapsGuestDomain(LibvirtConfigObject):
700 def __init__(self, **kwargs):
701 super(LibvirtConfigCapsGuestDomain, self).__init__(
702 root_name="domain", **kwargs)
704 self.domtype = None
706 # Track <emulator> values, which we need in order to be able
707 # to call virConnectGetDomainCapabilities() - typically
708 # something like '/usr/bin/qemu-system-i386'.
709 self.emulator = None
711 self.machines = {}
712 self.aliases = {}
714 def parse_dom(self, xmldoc):
715 super(LibvirtConfigCapsGuestDomain, self).parse_dom(xmldoc)
717 self.parse_domain(xmldoc)
719 for c in xmldoc:
720 self.parse_child(c)
722 def parse_child(self, xmldoc):
723 if xmldoc.tag == "emulator":
724 self.emulator = xmldoc.text
725 elif xmldoc.tag == "machine":
726 self.parse_machine(xmldoc)
728 def parse_domain(self, xmldoc):
729 self.domtype = xmldoc.get("type")
730 if self.domtype is None: 730 ↛ 731line 730 didn't jump to line 731 because the condition on line 730 was never true
731 raise exception.InvalidInput(
732 "Didn't find domain type in %s", xmldoc)
734 def parse_machine(self, xmldoc):
735 if 'canonical' in xmldoc.attrib:
736 self.aliases[xmldoc.text] = xmldoc.attrib
737 else:
738 self.machines[xmldoc.text] = xmldoc.attrib
740 def format_dom(self):
741 domain = super(LibvirtConfigCapsGuestDomain, self).format_dom()
743 if self.domtype is not None: 743 ↛ 745line 743 didn't jump to line 745 because the condition on line 743 was always true
744 domain.set("type", self.domtype)
745 if self.emulator is not None: 745 ↛ 747line 745 didn't jump to line 747 because the condition on line 745 was always true
746 domain.append(self._text_node("emulator", self.emulator))
747 for mach_type, machine in self.machines.items():
748 domain.append(self._text_node("machine", mach_type, **machine))
749 for alias, machine in self.aliases.items():
750 domain.append(self._text_node("machine", alias, **machine))
752 return domain
755class LibvirtConfigGuestTimer(LibvirtConfigObject):
757 def __init__(self, **kwargs):
758 super(LibvirtConfigGuestTimer, self).__init__(root_name="timer",
759 **kwargs)
761 self.name = "platform"
762 self.track = None
763 self.tickpolicy = None
764 self.present = None
766 def format_dom(self):
767 tm = super(LibvirtConfigGuestTimer, self).format_dom()
769 tm.set("name", self.name)
770 if self.track is not None:
771 tm.set("track", self.track)
772 if self.tickpolicy is not None:
773 tm.set("tickpolicy", self.tickpolicy)
774 if self.present is not None:
775 tm.set("present", self.get_yes_no_str(self.present))
777 return tm
780class LibvirtConfigGuestClock(LibvirtConfigObject):
782 def __init__(self, **kwargs):
783 super(LibvirtConfigGuestClock, self).__init__(root_name="clock",
784 **kwargs)
786 self.offset = "utc"
787 self.adjustment = None
788 self.timezone = None
789 self.timers = []
791 def format_dom(self):
792 clk = super(LibvirtConfigGuestClock, self).format_dom()
794 clk.set("offset", self.offset)
795 if self.adjustment:
796 clk.set("adjustment", self.adjustment)
797 elif self.timezone:
798 clk.set("timezone", self.timezone)
800 for tm in self.timers:
801 clk.append(tm.format_dom())
803 return clk
805 def add_timer(self, tm):
806 self.timers.append(tm)
809class LibvirtConfigCPUFeature(LibvirtConfigObject):
811 def __init__(self, name=None, **kwargs):
812 super(LibvirtConfigCPUFeature, self).__init__(root_name='feature',
813 **kwargs)
815 self.name = name
816 self.policy = "require"
818 def parse_dom(self, xmldoc):
819 super(LibvirtConfigCPUFeature, self).parse_dom(xmldoc)
821 self.name = xmldoc.get("name")
822 self.policy = xmldoc.get("policy", "require")
824 def format_dom(self):
825 ft = super(LibvirtConfigCPUFeature, self).format_dom()
827 ft.set("name", self.name)
829 return ft
831 def __eq__(self, obj):
832 return obj.name == self.name
834 def __ne__(self, obj):
835 return obj.name != self.name
837 def __hash__(self):
838 return hash(self.name)
841class LibvirtConfigCPUMaxPhysAddr(LibvirtConfigObject):
843 def __init__(self, **kwargs):
844 super(LibvirtConfigCPUMaxPhysAddr, self).__init__(
845 root_name='maxphysaddr', **kwargs)
847 self.mode = None
848 self.bits = None
850 def parse_dom(self, xmldoc):
851 super(LibvirtConfigCPUMaxPhysAddr, self).parse_dom(xmldoc)
853 self.mode = xmldoc.get("mode")
854 if xmldoc.get("bits") is not None:
855 self.bits = int(xmldoc.get("bits"))
857 def format_dom(self):
858 m = super(LibvirtConfigCPUMaxPhysAddr, self).format_dom()
860 m.set("mode", self.mode)
862 if self.bits:
863 m.set("bits", str(self.bits))
865 return m
868class LibvirtConfigGuestCPUMaxPhysAddr(LibvirtConfigCPUMaxPhysAddr):
869 pass
872class LibvirtConfigCPU(LibvirtConfigObject):
874 def __init__(self, **kwargs):
875 super(LibvirtConfigCPU, self).__init__(root_name='cpu',
876 **kwargs)
878 self.arch = None
879 self.vendor = None
880 self.model = None
882 self.sockets = None
883 self.cores = None
884 self.threads = None
886 self.maxphysaddr = None
888 self.features = set()
890 def parse_dom(self, xmldoc):
891 super(LibvirtConfigCPU, self).parse_dom(xmldoc)
893 for c in xmldoc:
894 if c.tag == "arch":
895 self.arch = c.text
896 elif c.tag == "model":
897 self.model = c.text
898 elif c.tag == "vendor":
899 self.vendor = c.text
900 elif c.tag == "topology":
901 self.sockets = int(c.get("sockets"))
902 self.cores = int(c.get("cores"))
903 self.threads = int(c.get("threads"))
904 elif c.tag == "maxphysaddr":
905 self.maxphysaddr = LibvirtConfigCPUMaxPhysAddr()
906 self.maxphysaddr.parse_dom(c)
907 elif c.tag == "feature":
908 f = LibvirtConfigCPUFeature()
909 f.parse_dom(c)
910 if f.policy != "disable": 910 ↛ 893line 910 didn't jump to line 893 because the condition on line 910 was always true
911 self.add_feature(f)
913 def format_dom(self):
914 cpu = super(LibvirtConfigCPU, self).format_dom()
916 if self.arch is not None:
917 cpu.append(self._text_node("arch", self.arch))
918 if self.model is not None:
919 cpu.append(self._text_node("model", self.model))
920 if self.vendor is not None:
921 cpu.append(self._text_node("vendor", self.vendor))
923 if (self.sockets is not None and
924 self.cores is not None and
925 self.threads is not None):
926 top = etree.Element("topology")
927 top.set("sockets", str(self.sockets))
928 top.set("cores", str(self.cores))
929 top.set("threads", str(self.threads))
930 cpu.append(top)
932 if self.maxphysaddr is not None:
933 cpu.append(self.maxphysaddr.format_dom())
935 # sorting the features to allow more predictable tests
936 for f in sorted(self.features, key=lambda x: x.name):
937 cpu.append(f.format_dom())
939 return cpu
941 def add_feature(self, feat):
942 self.features.add(feat)
945class LibvirtConfigGuestCPUFeature(LibvirtConfigCPUFeature):
947 def __init__(self, name=None, policy="require", **kwargs):
948 super(LibvirtConfigGuestCPUFeature, self).__init__(name, **kwargs)
950 self.policy = policy
952 def format_dom(self):
953 ft = super(LibvirtConfigGuestCPUFeature, self).format_dom()
955 ft.set("policy", self.policy)
957 return ft
960class LibvirtConfigGuestCPUNUMACell(LibvirtConfigObject):
962 def __init__(self, **kwargs):
963 super(LibvirtConfigGuestCPUNUMACell, self).__init__(root_name="cell",
964 **kwargs)
965 self.id = None
966 self.cpus = None
967 self.memory = None
968 self.memAccess = None
970 def parse_dom(self, xmldoc):
971 if xmldoc.get("id") is not None: 971 ↛ 973line 971 didn't jump to line 973 because the condition on line 971 was always true
972 self.id = int(xmldoc.get("id"))
973 if xmldoc.get("memory") is not None: 973 ↛ 975line 973 didn't jump to line 975 because the condition on line 973 was always true
974 self.memory = int(xmldoc.get("memory"))
975 if xmldoc.get("cpus") is not None: 975 ↛ 977line 975 didn't jump to line 977 because the condition on line 975 was always true
976 self.cpus = hardware.parse_cpu_spec(xmldoc.get("cpus"))
977 self.memAccess = xmldoc.get("memAccess")
979 def format_dom(self):
980 cell = super(LibvirtConfigGuestCPUNUMACell, self).format_dom()
982 if self.id is not None: 982 ↛ 984line 982 didn't jump to line 984 because the condition on line 982 was always true
983 cell.set("id", str(self.id))
984 if self.cpus is not None: 984 ↛ 987line 984 didn't jump to line 987 because the condition on line 984 was always true
985 cell.set("cpus",
986 hardware.format_cpu_spec(self.cpus))
987 if self.memory is not None: 987 ↛ 989line 987 didn't jump to line 989 because the condition on line 987 was always true
988 cell.set("memory", str(self.memory))
989 if self.memAccess is not None:
990 cell.set("memAccess", self.memAccess)
992 return cell
995class LibvirtConfigGuestCPUNUMA(LibvirtConfigObject):
997 def __init__(self, **kwargs):
998 super(LibvirtConfigGuestCPUNUMA, self).__init__(root_name="numa",
999 **kwargs)
1001 self.cells = []
1003 def parse_dom(self, xmldoc):
1004 super(LibvirtConfigGuestCPUNUMA, self).parse_dom(xmldoc)
1006 for child in xmldoc:
1007 if child.tag == "cell": 1007 ↛ 1006line 1007 didn't jump to line 1006 because the condition on line 1007 was always true
1008 cell = LibvirtConfigGuestCPUNUMACell()
1009 cell.parse_dom(child)
1010 self.cells.append(cell)
1012 def format_dom(self):
1013 numa = super(LibvirtConfigGuestCPUNUMA, self).format_dom()
1015 for cell in self.cells:
1016 numa.append(cell.format_dom())
1018 return numa
1021class LibvirtConfigGuestCPU(LibvirtConfigCPU):
1023 def __init__(self, **kwargs):
1024 super(LibvirtConfigGuestCPU, self).__init__(**kwargs)
1026 self.mode = None
1027 self.match = "exact"
1028 self.numa = None
1029 self.maxphysaddr = None
1031 def parse_dom(self, xmldoc):
1032 super(LibvirtConfigGuestCPU, self).parse_dom(xmldoc)
1033 self.mode = xmldoc.get('mode')
1034 self.match = xmldoc.get('match')
1035 for child in xmldoc:
1036 if child.tag == "numa": 1036 ↛ 1037line 1036 didn't jump to line 1037 because the condition on line 1036 was never true
1037 numa = LibvirtConfigGuestCPUNUMA()
1038 numa.parse_dom(child)
1039 self.numa = numa
1040 elif child.tag == "maxphysaddr": 1040 ↛ 1041line 1040 didn't jump to line 1041 because the condition on line 1040 was never true
1041 m = LibvirtConfigGuestCPUMaxPhysAddr()
1042 m.parse_dom(child)
1043 self.maxphysaddr = m
1045 def format_dom(self):
1046 cpu = super(LibvirtConfigGuestCPU, self).format_dom()
1048 if self.mode:
1049 cpu.set("mode", self.mode)
1050 cpu.set("match", self.match)
1051 if self.numa is not None:
1052 cpu.append(self.numa.format_dom())
1054 return cpu
1057class LibvirtConfigGuestSMBIOS(LibvirtConfigObject):
1059 def __init__(self, **kwargs):
1060 super(LibvirtConfigGuestSMBIOS, self).__init__(root_name="smbios",
1061 **kwargs)
1063 self.mode = "sysinfo"
1065 def format_dom(self):
1066 smbios = super(LibvirtConfigGuestSMBIOS, self).format_dom()
1067 smbios.set("mode", self.mode)
1069 return smbios
1072class LibvirtConfigGuestSysinfo(LibvirtConfigObject):
1074 def __init__(self, **kwargs):
1075 super(LibvirtConfigGuestSysinfo, self).__init__(root_name="sysinfo",
1076 **kwargs)
1078 self.type = "smbios"
1079 self.bios_vendor = None
1080 self.bios_version = None
1081 self.system_manufacturer = None
1082 self.system_product = None
1083 self.system_version = None
1084 self.system_serial = None
1085 self.system_uuid = None
1086 self.system_family = None
1088 def format_dom(self):
1089 sysinfo = super(LibvirtConfigGuestSysinfo, self).format_dom()
1091 sysinfo.set("type", self.type)
1093 bios = etree.Element("bios")
1094 system = etree.Element("system")
1096 if self.bios_vendor is not None:
1097 bios.append(self._text_node("entry", self.bios_vendor,
1098 name="vendor"))
1100 if self.bios_version is not None:
1101 bios.append(self._text_node("entry", self.bios_version,
1102 name="version"))
1104 if self.system_manufacturer is not None:
1105 system.append(self._text_node("entry", self.system_manufacturer,
1106 name="manufacturer"))
1108 if self.system_product is not None:
1109 system.append(self._text_node("entry", self.system_product,
1110 name="product"))
1112 if self.system_version is not None:
1113 system.append(self._text_node("entry", self.system_version,
1114 name="version"))
1116 if self.system_serial is not None:
1117 system.append(self._text_node("entry", self.system_serial,
1118 name="serial"))
1120 if self.system_uuid is not None:
1121 system.append(self._text_node("entry", self.system_uuid,
1122 name="uuid"))
1124 if self.system_family is not None:
1125 system.append(self._text_node("entry", self.system_family,
1126 name="family"))
1128 if len(list(bios)) > 0:
1129 sysinfo.append(bios)
1131 if len(list(system)) > 0:
1132 sysinfo.append(system)
1134 return sysinfo
1137class LibvirtConfigGuestDevice(LibvirtConfigObject):
1139 def __init__(self, **kwargs):
1140 super(LibvirtConfigGuestDevice, self).__init__(**kwargs)
1142 @property
1143 def uses_virtio(self):
1144 return False
1147class LibvirtConfigGuestVTPM(LibvirtConfigGuestDevice):
1149 def __init__(self, vtpm_config, vtpm_secret_uuid, **kwargs):
1150 super(LibvirtConfigGuestVTPM, self).__init__(root_name="tpm", **kwargs)
1152 self.version = vtpm_config.version
1153 self.model = vtpm_config.model
1154 self.secret_uuid = vtpm_secret_uuid
1156 def format_dom(self):
1157 # <tpm model='$model'>
1158 dev = super(LibvirtConfigGuestVTPM, self).format_dom()
1159 dev.set("model", self.model)
1160 # <backend type='emulator' version='$version'>
1161 back = etree.Element("backend")
1162 back.set("type", "emulator")
1163 back.set("version", self.version)
1164 # <encryption secret='$secret_uuid'/>
1165 enc = etree.Element("encryption")
1166 enc.set("secret", self.secret_uuid)
1168 back.append(enc)
1169 dev.append(back)
1171 return dev
1174class LibvirtConfigGuestDisk(LibvirtConfigGuestDevice):
1176 def __init__(self, **kwargs):
1177 super(LibvirtConfigGuestDisk, self).__init__(root_name="disk",
1178 **kwargs)
1180 self.source_type = "file"
1181 self.source_device = "disk"
1182 self.driver_name = None
1183 self.driver_format = None
1184 self.driver_cache = None
1185 self.driver_discard = None
1186 self.driver_io = None
1187 self.driver_iommu = False
1188 self.source_path = None
1189 self.source_protocol = None
1190 self.source_name = None
1191 self.source_hosts = []
1192 self.source_ports = []
1193 self.target_dev = None
1194 self.target_path = None
1195 self.target_bus = None
1196 self.auth_username = None
1197 self.auth_secret_type = None
1198 self.auth_secret_uuid = None
1199 self.serial = None
1200 self.disk_read_bytes_sec = None
1201 self.disk_read_iops_sec = None
1202 self.disk_write_bytes_sec = None
1203 self.disk_write_iops_sec = None
1204 self.disk_total_bytes_sec = None
1205 self.disk_total_iops_sec = None
1206 self.disk_read_bytes_sec_max = None
1207 self.disk_write_bytes_sec_max = None
1208 self.disk_total_bytes_sec_max = None
1209 self.disk_read_iops_sec_max = None
1210 self.disk_write_iops_sec_max = None
1211 self.disk_total_iops_sec_max = None
1212 self.disk_size_iops_sec = None
1213 self.logical_block_size = None
1214 self.physical_block_size = None
1215 self.readonly = False
1216 self.shareable = False
1217 self.snapshot = None
1218 self.backing_store = None
1219 self.device_addr = None
1220 self.boot_order = None
1221 self.mirror = None
1222 self.volume_encryption = None
1223 self.ephemeral_encryption = None
1224 self.alias = None
1226 def _format_iotune(self, dev):
1227 iotune = etree.Element("iotune")
1229 if self.disk_read_bytes_sec is not None:
1230 iotune.append(self._text_node("read_bytes_sec",
1231 self.disk_read_bytes_sec))
1233 if self.disk_read_iops_sec is not None:
1234 iotune.append(self._text_node("read_iops_sec",
1235 self.disk_read_iops_sec))
1237 if self.disk_write_bytes_sec is not None:
1238 iotune.append(self._text_node("write_bytes_sec",
1239 self.disk_write_bytes_sec))
1241 if self.disk_write_iops_sec is not None:
1242 iotune.append(self._text_node("write_iops_sec",
1243 self.disk_write_iops_sec))
1245 if self.disk_total_bytes_sec is not None:
1246 iotune.append(self._text_node("total_bytes_sec",
1247 self.disk_total_bytes_sec))
1249 if self.disk_total_iops_sec is not None:
1250 iotune.append(self._text_node("total_iops_sec",
1251 self.disk_total_iops_sec))
1253 if self.disk_read_bytes_sec_max is not None:
1254 iotune.append(self._text_node("read_bytes_sec_max",
1255 self.disk_read_bytes_sec_max))
1257 if self.disk_write_bytes_sec_max is not None:
1258 iotune.append(self._text_node("write_bytes_sec_max",
1259 self.disk_write_bytes_sec_max))
1261 if self.disk_total_bytes_sec_max is not None:
1262 iotune.append(self._text_node("total_bytes_sec_max",
1263 self.disk_total_bytes_sec_max))
1265 if self.disk_read_iops_sec_max is not None:
1266 iotune.append(self._text_node("read_iops_sec_max",
1267 self.disk_read_iops_sec_max))
1269 if self.disk_write_iops_sec_max is not None:
1270 iotune.append(self._text_node("write_iops_sec_max",
1271 self.disk_write_iops_sec_max))
1273 if self.disk_total_iops_sec_max is not None:
1274 iotune.append(self._text_node("total_iops_sec_max",
1275 self.disk_total_iops_sec_max))
1277 if self.disk_size_iops_sec is not None:
1278 iotune.append(self._text_node("size_iops_sec",
1279 self.disk_size_iops_sec))
1281 if len(iotune) > 0:
1282 dev.append(iotune)
1284 @property
1285 def uses_virtio(self):
1286 return 'virtio' == self.target_bus
1288 def format_dom(self):
1289 dev = super(LibvirtConfigGuestDisk, self).format_dom()
1291 dev.set("type", self.source_type)
1292 dev.set("device", self.source_device)
1293 if any((self.driver_name, self.driver_format, self.driver_cache,
1294 self.driver_discard, self.driver_iommu)):
1295 drv = etree.Element("driver")
1296 if self.driver_name is not None:
1297 drv.set("name", self.driver_name)
1298 if self.driver_format is not None:
1299 drv.set("type", self.driver_format)
1300 if self.driver_cache is not None:
1301 drv.set("cache", self.driver_cache)
1302 if self.driver_discard is not None:
1303 drv.set("discard", self.driver_discard)
1304 if self.driver_io is not None:
1305 drv.set("io", self.driver_io)
1306 if self.driver_iommu:
1307 drv.set("iommu", "on")
1308 dev.append(drv)
1310 if self.alias:
1311 alias = etree.Element("alias")
1312 alias.set("name", self.alias)
1313 dev.append(alias)
1315 if self.source_type == "file":
1316 source = etree.Element("source", file=self.source_path)
1317 dev.append(source)
1318 elif self.source_type == "block":
1319 source = etree.Element("source", dev=self.source_path)
1320 dev.append(source)
1321 elif self.source_type == "mount": 1321 ↛ 1322line 1321 didn't jump to line 1322 because the condition on line 1321 was never true
1322 source = etree.Element("source", dir=self.source_path)
1323 dev.append(source)
1324 elif self.source_type == "network" and self.source_protocol:
1325 source = etree.Element("source", protocol=self.source_protocol)
1326 if self.source_name is not None:
1327 source.set('name', self.source_name)
1328 hosts_info = zip(self.source_hosts, self.source_ports)
1329 for name, port in hosts_info:
1330 host = etree.Element('host', name=name)
1331 if port is not None:
1332 host.set('port', port)
1333 source.append(host)
1334 dev.append(source)
1336 if self.ephemeral_encryption:
1337 # NOTE(melwitt): <encryption> should be a sub element of <source>
1338 # in order to ensure the image uses encryption.
1339 # See the following for more details:
1340 # https://libvirt.org/formatdomain.html#hard-drives-floppy-disks-cdroms
1341 # https://bugzilla.redhat.com/show_bug.cgi?id=1371022#c13
1342 source.append(self.ephemeral_encryption.format_dom())
1344 if self.auth_secret_type is not None:
1345 auth = etree.Element("auth")
1346 auth.set("username", self.auth_username)
1347 auth.append(etree.Element("secret", type=self.auth_secret_type,
1348 uuid=self.auth_secret_uuid))
1349 dev.append(auth)
1351 if self.source_type == "mount": 1351 ↛ 1352line 1351 didn't jump to line 1352 because the condition on line 1351 was never true
1352 dev.append(etree.Element("target", dir=self.target_path))
1353 else:
1354 dev.append(etree.Element("target", dev=self.target_dev,
1355 bus=self.target_bus))
1357 if self.serial is not None and self.source_device != 'lun':
1358 dev.append(self._text_node("serial", self.serial))
1360 self._format_iotune(dev)
1362 # Block size tuning
1363 if (self.logical_block_size is not None or
1364 self.physical_block_size is not None):
1366 blockio = etree.Element("blockio")
1367 if self.logical_block_size is not None: 1367 ↛ 1370line 1367 didn't jump to line 1370 because the condition on line 1367 was always true
1368 blockio.set('logical_block_size', self.logical_block_size)
1370 if self.physical_block_size is not None: 1370 ↛ 1373line 1370 didn't jump to line 1373 because the condition on line 1370 was always true
1371 blockio.set('physical_block_size', self.physical_block_size)
1373 dev.append(blockio)
1375 if self.readonly:
1376 dev.append(etree.Element("readonly"))
1377 if self.shareable:
1378 dev.append(etree.Element("shareable"))
1380 if self.boot_order:
1381 dev.append(etree.Element("boot", order=self.boot_order))
1383 if self.device_addr:
1384 dev.append(self.device_addr.format_dom())
1386 if self.volume_encryption:
1387 dev.append(self.volume_encryption.format_dom())
1389 return dev
1391 def parse_dom(self, xmldoc):
1392 super(LibvirtConfigGuestDisk, self).parse_dom(xmldoc)
1394 self.source_type = xmldoc.get('type')
1395 self.snapshot = xmldoc.get('snapshot')
1397 for c in xmldoc:
1398 if c.tag == 'driver':
1399 self.driver_name = c.get('name')
1400 self.driver_format = c.get('type')
1401 self.driver_cache = c.get('cache')
1402 self.driver_discard = c.get('discard')
1403 self.driver_io = c.get('io')
1404 self.driver_iommu = c.get('iommu', '') == "on"
1405 elif c.tag == 'source':
1406 if self.source_type == 'file':
1407 self.source_path = c.get('file')
1408 elif self.source_type == 'block':
1409 self.source_path = c.get('dev')
1410 elif self.source_type == 'mount': 1410 ↛ 1411line 1410 didn't jump to line 1411 because the condition on line 1410 was never true
1411 self.source_path = c.get('dir')
1412 elif self.source_type == 'network': 1412 ↛ 1419line 1412 didn't jump to line 1419 because the condition on line 1412 was always true
1413 self.source_protocol = c.get('protocol')
1414 self.source_name = c.get('name')
1415 for sub in c:
1416 if sub.tag == 'host': 1416 ↛ 1415line 1416 didn't jump to line 1415 because the condition on line 1416 was always true
1417 self.source_hosts.append(sub.get('name'))
1418 self.source_ports.append(sub.get('port'))
1419 for sub in c:
1420 if sub.tag == 'encryption':
1421 e = LibvirtConfigGuestDiskEncryption()
1422 e.parse_dom(sub)
1423 self.ephemeral_encryption = e
1425 elif c.tag == 'serial':
1426 self.serial = c.text
1427 elif c.tag == 'target':
1428 if self.source_type == 'mount': 1428 ↛ 1429line 1428 didn't jump to line 1429 because the condition on line 1428 was never true
1429 self.target_path = c.get('dir')
1430 else:
1431 self.target_dev = c.get('dev')
1433 self.target_bus = c.get('bus', None)
1434 elif c.tag == 'backingStore':
1435 b = LibvirtConfigGuestDiskBackingStore()
1436 b.parse_dom(c)
1437 self.backing_store = b
1438 elif c.tag == 'readonly':
1439 self.readonly = True
1440 elif c.tag == 'shareable':
1441 self.shareable = True
1442 elif c.tag == 'address':
1443 obj = LibvirtConfigGuestDeviceAddress.parse_dom(c)
1444 self.device_addr = obj
1445 elif c.tag == 'boot':
1446 self.boot_order = c.get('order')
1447 elif c.tag == 'mirror':
1448 m = LibvirtConfigGuestDiskMirror()
1449 m.parse_dom(c)
1450 self.mirror = m
1451 elif c.tag == 'encryption': 1451 ↛ 1452line 1451 didn't jump to line 1452 because the condition on line 1451 was never true
1452 e = LibvirtConfigGuestDiskEncryption()
1453 e.parse_dom(c)
1454 self.volume_encryption = e
1455 elif c.tag == 'alias':
1456 self.alias = c.get('name')
1459class LibvirtConfigGuestDiskBackingStore(LibvirtConfigObject):
1460 def __init__(self, **kwargs):
1461 super(LibvirtConfigGuestDiskBackingStore, self).__init__(
1462 root_name="backingStore", **kwargs)
1464 self.index = None
1465 self.source_type = None
1466 self.source_file = None
1467 self.source_protocol = None
1468 self.source_name = None
1469 self.source_hosts = []
1470 self.source_ports = []
1471 self.driver_name = None
1472 self.driver_format = None
1473 self.backing_store = None
1475 def parse_dom(self, xmldoc):
1476 super(LibvirtConfigGuestDiskBackingStore, self).parse_dom(xmldoc)
1478 self.source_type = xmldoc.get('type')
1479 self.index = xmldoc.get('index')
1481 for c in xmldoc:
1482 if c.tag == 'driver':
1483 self.driver_name = c.get('name')
1484 self.driver_format = c.get('type')
1485 elif c.tag == 'source':
1486 self.source_file = c.get('file')
1487 self.source_protocol = c.get('protocol')
1488 self.source_name = c.get('name')
1489 for d in c:
1490 if d.tag == 'host': 1490 ↛ 1489line 1490 didn't jump to line 1489 because the condition on line 1490 was always true
1491 self.source_hosts.append(d.get('name'))
1492 self.source_ports.append(d.get('port'))
1493 elif c.tag == 'backingStore':
1494 if len(c):
1495 self.backing_store = LibvirtConfigGuestDiskBackingStore()
1496 self.backing_store.parse_dom(c)
1499class LibvirtConfigGuestSnapshotDisk(LibvirtConfigObject):
1500 """Disk class for handling disk information in snapshots.
1502 Similar to LibvirtConfigGuestDisk, but used to represent
1503 disk entities in <domainsnapshot> structures rather than
1504 real devices. These typically have fewer members, and
1505 different expectations for which fields are required.
1506 """
1508 def __init__(self, **kwargs):
1509 super(LibvirtConfigGuestSnapshotDisk, self).__init__(root_name="disk",
1510 **kwargs)
1512 self.source_type = None
1513 self.source_device = None
1514 self.name = None
1515 self.snapshot = None
1516 self.driver_name = None
1517 self.driver_format = None
1518 self.driver_cache = None
1519 self.source_path = None
1520 self.source_protocol = None
1521 self.source_name = None
1522 self.source_hosts = []
1523 self.source_ports = []
1524 self.target_dev = None
1525 self.target_path = None
1526 self.target_bus = None
1527 self.auth_username = None
1528 self.auth_secret_type = None
1529 self.auth_secret_uuid = None
1530 self.serial = None
1532 def format_dom(self):
1533 dev = super(LibvirtConfigGuestSnapshotDisk, self).format_dom()
1535 if self.name: 1535 ↛ 1537line 1535 didn't jump to line 1537 because the condition on line 1535 was always true
1536 dev.attrib['name'] = self.name
1537 if self.snapshot: 1537 ↛ 1540line 1537 didn't jump to line 1540 because the condition on line 1537 was always true
1538 dev.attrib['snapshot'] = self.snapshot
1540 if self.source_type:
1541 dev.set("type", self.source_type)
1543 if self.source_device: 1543 ↛ 1544line 1543 didn't jump to line 1544 because the condition on line 1543 was never true
1544 dev.set("device", self.source_device)
1545 if (self.driver_name is not None or
1546 self.driver_format is not None or
1547 self.driver_cache is not None):
1548 drv = etree.Element("driver")
1549 if self.driver_name is not None:
1550 drv.set("name", self.driver_name)
1551 if self.driver_format is not None:
1552 drv.set("type", self.driver_format)
1553 if self.driver_cache is not None:
1554 drv.set("cache", self.driver_cache)
1555 dev.append(drv)
1557 if self.source_type == "file":
1558 dev.append(etree.Element("source", file=self.source_path))
1559 elif self.source_type == "block": 1559 ↛ 1560line 1559 didn't jump to line 1560 because the condition on line 1559 was never true
1560 dev.append(etree.Element("source", dev=self.source_path))
1561 elif self.source_type == "mount": 1561 ↛ 1562line 1561 didn't jump to line 1562 because the condition on line 1561 was never true
1562 dev.append(etree.Element("source", dir=self.source_path))
1563 elif self.source_type == "network":
1564 source = etree.Element("source", protocol=self.source_protocol)
1565 if self.source_name is not None: 1565 ↛ 1567line 1565 didn't jump to line 1567 because the condition on line 1565 was always true
1566 source.set('name', self.source_name)
1567 hosts_info = zip(self.source_hosts, self.source_ports)
1568 for name, port in hosts_info:
1569 host = etree.Element('host', name=name)
1570 if port is not None: 1570 ↛ 1572line 1570 didn't jump to line 1572 because the condition on line 1570 was always true
1571 host.set('port', port)
1572 source.append(host)
1573 dev.append(source)
1575 if self.auth_secret_type is not None: 1575 ↛ 1576line 1575 didn't jump to line 1576 because the condition on line 1575 was never true
1576 auth = etree.Element("auth")
1577 auth.set("username", self.auth_username)
1578 auth.append(etree.Element("secret", type=self.auth_secret_type,
1579 uuid=self.auth_secret_uuid))
1580 dev.append(auth)
1582 if self.source_type == "mount": 1582 ↛ 1583line 1582 didn't jump to line 1583 because the condition on line 1582 was never true
1583 dev.append(etree.Element("target", dir=self.target_path))
1584 else:
1585 if self.target_bus and self.target_dev: 1585 ↛ 1586line 1585 didn't jump to line 1586 because the condition on line 1585 was never true
1586 dev.append(etree.Element("target", dev=self.target_dev,
1587 bus=self.target_bus))
1589 return dev
1591 def parse_dom(self, xmldoc):
1592 super(LibvirtConfigGuestSnapshotDisk, self).parse_dom(xmldoc)
1594 self.source_type = xmldoc.get('type')
1595 self.snapshot = xmldoc.get('snapshot')
1597 for c in xmldoc:
1598 if c.tag == 'driver':
1599 self.driver_name = c.get('name')
1600 self.driver_format = c.get('type')
1601 self.driver_cache = c.get('cache')
1602 elif c.tag == 'source':
1603 if self.source_type == 'file':
1604 self.source_path = c.get('file')
1605 elif self.source_type == 'block':
1606 self.source_path = c.get('dev')
1607 elif self.source_type == 'mount':
1608 self.source_path = c.get('dir')
1609 elif self.source_type == 'network':
1610 self.source_protocol = c.get('protocol')
1611 self.source_name = c.get('name')
1612 for sub in c:
1613 if sub.tag == 'host':
1614 self.source_hosts.append(sub.get('name'))
1615 self.source_ports.append(sub.get('port'))
1617 elif c.tag == 'serial':
1618 self.serial = c.text
1620 for c in xmldoc:
1621 if c.tag == 'target':
1622 if self.source_type == 'mount':
1623 self.target_path = c.get('dir')
1624 else:
1625 self.target_dev = c.get('dev')
1627 self.target_bus = c.get('bus', None)
1630class LibvirtConfigGuestFilesys(LibvirtConfigGuestDevice):
1632 def __init__(self, **kwargs):
1633 super(LibvirtConfigGuestFilesys, self).__init__(root_name="filesystem",
1634 **kwargs)
1636 self.source_type = "mount"
1637 self.accessmode = None
1638 self.source_dir = None
1639 self.source_file = None
1640 self.source_dev = None
1641 self.target_dir = "/"
1642 self.driver_type = "loop"
1643 self.driver_format = "raw"
1645 def format_dom(self):
1646 dev = super(LibvirtConfigGuestFilesys, self).format_dom()
1648 dev.set("type", self.source_type)
1649 if self.accessmode:
1650 dev.set("accessmode", self.accessmode)
1652 if self.source_type == "file":
1653 dev.append(etree.Element("driver", type = self.driver_type,
1654 format = self.driver_format))
1655 dev.append(etree.Element("source", file=self.source_file))
1656 elif self.source_type == "block":
1657 dev.append(etree.Element("source", dev=self.source_dev))
1658 elif self.source_type == "mount" and self.driver_type == "virtiofs":
1659 dev.append(etree.Element("driver", type=self.driver_type))
1660 dev.append(etree.Element("source", dir=self.source_dir))
1661 else:
1662 dev.append(etree.Element("source", dir=self.source_dir))
1663 dev.append(etree.Element("target", dir=self.target_dir))
1665 return dev
1667 def parse_dom(self, xmldoc):
1668 super(LibvirtConfigGuestFilesys, self).parse_dom(xmldoc)
1670 self.source_type = xmldoc.get('type')
1671 self.accessmode = xmldoc.get('accessmode')
1673 for c in xmldoc:
1674 if c.tag == 'driver':
1675 if self.source_type == 'file':
1676 self.driver_type = c.get('type')
1677 self.driver_format = c.get('format')
1678 if self.source_type == 'mount':
1679 self.driver_type = c.get('type')
1680 elif c.tag == 'source':
1681 if self.source_type == 'file':
1682 self.source_file = c.get('file')
1683 elif self.source_type == 'block':
1684 self.source_dev = c.get('dev')
1685 else:
1686 self.source_dir = c.get('dir')
1687 elif c.tag == 'target': 1687 ↛ 1673line 1687 didn't jump to line 1673 because the condition on line 1687 was always true
1688 self.target_dir = c.get('dir')
1691class LibvirtConfigGuestDiskEncryptionSecret(LibvirtConfigObject):
1692 def __init__(self, **kwargs):
1693 super(LibvirtConfigGuestDiskEncryptionSecret, self).__init__(
1694 root_name='diskencryptionsecret', **kwargs)
1695 self.type = None
1696 self.uuid = None
1698 def parse_dom(self, xmldoc):
1699 self.type = xmldoc.get('type')
1700 self.uuid = xmldoc.get('uuid')
1702 def format_dom(self):
1703 obj = etree.Element("secret")
1704 obj.set("type", self.type)
1705 obj.set("uuid", self.uuid)
1706 return obj
1709class LibvirtConfigGuestDiskEncryption(LibvirtConfigObject):
1710 """https://libvirt.org/formatstorageencryption.html
1711 """
1713 def __init__(self, **kwargs):
1714 super(LibvirtConfigGuestDiskEncryption, self).__init__(
1715 root_name='diskencryption', **kwargs)
1716 self.format = None
1717 self.secret = None
1719 def parse_dom(self, xmldoc):
1720 self.format = xmldoc.get('format')
1721 for c in xmldoc:
1722 if c.tag == 'secret': 1722 ↛ 1721line 1722 didn't jump to line 1721 because the condition on line 1722 was always true
1723 m = LibvirtConfigGuestDiskEncryptionSecret()
1724 m.parse_dom(c)
1725 self.secret = m
1727 def format_dom(self):
1728 obj = etree.Element("encryption")
1729 obj.set("format", self.format)
1730 obj.append(self.secret.format_dom())
1732 return obj
1735class LibvirtConfigGuestDiskMirror(LibvirtConfigObject):
1737 def __init__(self, **kwargs):
1738 super(LibvirtConfigGuestDiskMirror, self).__init__(
1739 root_name='diskmirror', **kwargs)
1740 self.ready = None
1742 def parse_dom(self, xmldoc):
1743 self.ready = xmldoc.get('ready')
1746class LibvirtConfigGuestIDMap(LibvirtConfigObject):
1748 def __init__(self, **kwargs):
1749 if 'root_name' not in kwargs:
1750 kwargs['root_name'] = 'id'
1751 super(LibvirtConfigGuestIDMap, self).__init__(**kwargs)
1752 self.start = 0
1753 self.target = 0
1754 self.count = 10000
1756 def parse_dom(self, xmldoc):
1757 self.start = int(xmldoc.get('start'))
1758 self.target = int(xmldoc.get('target'))
1759 self.count = int(xmldoc.get('count'))
1761 def format_dom(self):
1762 obj = super(LibvirtConfigGuestIDMap, self).format_dom()
1764 obj.set("start", str(self.start))
1765 obj.set("target", str(self.target))
1766 obj.set("count", str(self.count))
1768 return obj
1771class LibvirtConfigGuestUIDMap(LibvirtConfigGuestIDMap):
1773 def __init__(self, **kwargs):
1774 super(LibvirtConfigGuestUIDMap, self).__init__(root_name="uid",
1775 **kwargs)
1778class LibvirtConfigGuestGIDMap(LibvirtConfigGuestIDMap):
1780 def __init__(self, **kwargs):
1781 super(LibvirtConfigGuestGIDMap, self).__init__(root_name="gid",
1782 **kwargs)
1785class LibvirtConfigGuestDeviceAddress(LibvirtConfigObject):
1786 def __init__(self, type=None, **kwargs):
1787 super(LibvirtConfigGuestDeviceAddress, self).__init__(
1788 root_name='address', **kwargs)
1789 self.type = type
1791 def format_dom(self):
1792 xml = super(LibvirtConfigGuestDeviceAddress, self).format_dom()
1793 xml.set("type", self.type)
1794 return xml
1796 @staticmethod
1797 def parse_dom(xmldoc):
1798 addr_type = xmldoc.get('type')
1799 if addr_type == 'pci':
1800 obj = LibvirtConfigGuestDeviceAddressPCI()
1801 elif addr_type == 'drive':
1802 obj = LibvirtConfigGuestDeviceAddressDrive()
1803 else:
1804 return None
1805 obj.parse_dom(xmldoc)
1806 return obj
1809class LibvirtConfigGuestDeviceAddressDrive(LibvirtConfigGuestDeviceAddress):
1810 def __init__(self, **kwargs):
1811 super(LibvirtConfigGuestDeviceAddressDrive, self).\
1812 __init__(type='drive', **kwargs)
1813 self.controller = None
1814 self.bus = None
1815 self.target = None
1816 self.unit = None
1818 def format_dom(self):
1819 xml = super(LibvirtConfigGuestDeviceAddressDrive, self).format_dom()
1821 if self.controller is not None: 1821 ↛ 1823line 1821 didn't jump to line 1823 because the condition on line 1821 was always true
1822 xml.set("controller", str(self.controller))
1823 if self.bus is not None:
1824 xml.set("bus", str(self.bus))
1825 if self.target is not None:
1826 xml.set("target", str(self.target))
1827 if self.unit is not None:
1828 xml.set("unit", str(self.unit))
1830 return xml
1832 def parse_dom(self, xmldoc):
1833 self.controller = xmldoc.get('controller')
1834 self.bus = xmldoc.get('bus')
1835 self.target = xmldoc.get('target')
1836 self.unit = xmldoc.get('unit')
1838 def format_address(self):
1839 return None
1842class LibvirtConfigGuestDeviceAddressPCI(LibvirtConfigGuestDeviceAddress):
1843 def __init__(self, **kwargs):
1844 super(LibvirtConfigGuestDeviceAddressPCI, self).\
1845 __init__(type='pci', **kwargs)
1846 self.domain = None
1847 self.bus = None
1848 self.slot = None
1849 self.function = None
1851 def format_dom(self):
1852 xml = super(LibvirtConfigGuestDeviceAddressPCI, self).format_dom()
1854 if self.domain is not None: 1854 ↛ 1856line 1854 didn't jump to line 1856 because the condition on line 1854 was always true
1855 xml.set("domain", str(self.domain))
1856 if self.bus is not None: 1856 ↛ 1858line 1856 didn't jump to line 1858 because the condition on line 1856 was always true
1857 xml.set("bus", str(self.bus))
1858 if self.slot is not None: 1858 ↛ 1860line 1858 didn't jump to line 1860 because the condition on line 1858 was always true
1859 xml.set("slot", str(self.slot))
1860 if self.function is not None: 1860 ↛ 1863line 1860 didn't jump to line 1863 because the condition on line 1860 was always true
1861 xml.set("function", str(self.function))
1863 return xml
1865 def parse_dom(self, xmldoc):
1866 self.domain = xmldoc.get('domain')
1867 self.bus = xmldoc.get('bus')
1868 self.slot = xmldoc.get('slot')
1869 self.function = xmldoc.get('function')
1871 def format_address(self):
1872 if self.domain is not None: 1872 ↛ exitline 1872 didn't return from function 'format_address' because the condition on line 1872 was always true
1873 return pci_utils.get_pci_address(self.domain[2:],
1874 self.bus[2:],
1875 self.slot[2:],
1876 self.function[2:])
1879class LibvirtConfigGuestInterface(LibvirtConfigGuestDevice):
1881 def __init__(self, **kwargs):
1882 super(LibvirtConfigGuestInterface, self).__init__(
1883 root_name="interface",
1884 **kwargs)
1886 self.net_type = None
1887 self.target_dev = None
1888 self.model = None
1889 self.mac_addr = None
1890 self.script = None
1891 self.source_dev = None
1892 self.source_mode = "private"
1893 self.vporttype = None
1894 self.vportparams = []
1895 self.filtername = None
1896 self.filterparams = []
1897 self.driver_name = None
1898 self.driver_iommu = False
1899 self.driver_packed = False
1900 self.vhostuser_mode = None
1901 self.vhostuser_path = None
1902 self.vhostuser_type = None
1903 self.vhost_queues = None
1904 self.vhost_rx_queue_size = None
1905 self.vhost_tx_queue_size = None
1906 self.vif_inbound_peak = None
1907 self.vif_inbound_burst = None
1908 self.vif_inbound_average = None
1909 self.vif_outbound_peak = None
1910 self.vif_outbound_burst = None
1911 self.vif_outbound_average = None
1912 self.vlan = None
1913 self.device_addr = None
1914 self.mtu = None
1915 self.alias = None
1917 def __eq__(self, other):
1918 if not isinstance(other, LibvirtConfigGuestInterface): 1918 ↛ 1919line 1918 didn't jump to line 1919 because the condition on line 1918 was never true
1919 return False
1921 # NOTE(arches) Skip checking target_dev for vhostuser
1922 # vif type; target_dev is not a valid value for vhostuser.
1923 # NOTE(gibi): For macvtap cases the domain has a target_dev
1924 # generated by libvirt. It is not set by the vif driver code
1925 # so it is not in config returned by the vif driver so we
1926 # should not match on that.
1927 return (
1928 self.mac_addr == other.mac_addr and
1929 self.net_type == other.net_type and
1930 self.source_dev == other.source_dev and
1931 (self.net_type == 'vhostuser' or not self.target_dev or
1932 self.target_dev == other.target_dev) and
1933 self.vhostuser_path == other.vhostuser_path)
1935 @property
1936 def uses_virtio(self):
1937 return 'virtio' == self.model
1939 def format_dom(self):
1940 dev = super(LibvirtConfigGuestInterface, self).format_dom()
1942 dev.set("type", self.net_type)
1943 if self.net_type == "hostdev":
1944 dev.set("managed", "yes")
1945 dev.append(etree.Element("mac", address=self.mac_addr))
1946 if self.model:
1947 dev.append(etree.Element("model", type=self.model))
1949 drv_elem = None
1950 if (self.driver_name or
1951 self.driver_iommu or
1952 self.driver_packed or
1953 self.net_type == "vhostuser"):
1955 drv_elem = etree.Element("driver")
1956 if self.driver_name and self.net_type != "vhostuser":
1957 # For vhostuser interface we should not set the driver name.
1958 drv_elem.set("name", self.driver_name)
1959 if self.driver_iommu:
1960 drv_elem.set("iommu", "on")
1961 if self.driver_packed:
1962 drv_elem.set("packed", "on")
1964 if drv_elem is not None:
1965 if self.vhost_queues is not None:
1966 drv_elem.set('queues', str(self.vhost_queues))
1967 if self.vhost_rx_queue_size is not None:
1968 drv_elem.set('rx_queue_size', str(self.vhost_rx_queue_size))
1969 if self.vhost_tx_queue_size is not None:
1970 drv_elem.set('tx_queue_size', str(self.vhost_tx_queue_size))
1972 if (drv_elem.get('name') or drv_elem.get('queues') or
1973 drv_elem.get('rx_queue_size') or
1974 drv_elem.get('tx_queue_size') or
1975 drv_elem.get('iommu') or
1976 drv_elem.get('packed')):
1977 # Append the driver element into the dom only if name
1978 # or queues or tx/rx or iommu attributes are set.
1979 dev.append(drv_elem)
1981 if self.net_type == "ethernet":
1982 if self.script is not None: 1982 ↛ 1983line 1982 didn't jump to line 1983 because the condition on line 1982 was never true
1983 dev.append(etree.Element("script", path=self.script))
1984 if self.mtu is not None:
1985 dev.append(etree.Element("mtu", size=str(self.mtu)))
1986 elif self.net_type == "direct":
1987 dev.append(etree.Element("source", dev=self.source_dev,
1988 mode=self.source_mode))
1989 elif self.net_type == "vdpa": 1989 ↛ 1990line 1989 didn't jump to line 1990 because the condition on line 1989 was never true
1990 dev.append(etree.Element("source", dev=self.source_dev))
1991 elif self.net_type == "hostdev":
1992 source_elem = etree.Element("source")
1993 domain, bus, slot, func = \
1994 pci_utils.get_pci_address_fields(self.source_dev)
1995 addr_elem = etree.Element("address", type='pci')
1996 addr_elem.set("domain", "0x%s" % (domain))
1997 addr_elem.set("bus", "0x%s" % (bus))
1998 addr_elem.set("slot", "0x%s" % (slot))
1999 addr_elem.set("function", "0x%s" % (func))
2000 source_elem.append(addr_elem)
2001 dev.append(source_elem)
2002 elif self.net_type == "vhostuser":
2003 dev.append(etree.Element("source", type=self.vhostuser_type,
2004 mode=self.vhostuser_mode,
2005 path=self.vhostuser_path))
2006 elif self.net_type == "bridge":
2007 dev.append(etree.Element("source", bridge=self.source_dev))
2008 if self.script is not None: 2008 ↛ 2009line 2008 didn't jump to line 2009 because the condition on line 2008 was never true
2009 dev.append(etree.Element("script", path=self.script))
2010 if self.mtu is not None:
2011 dev.append(etree.Element("mtu", size=str(self.mtu)))
2012 else:
2013 dev.append(etree.Element("source", bridge=self.source_dev))
2015 if self.vlan and self.net_type in ("direct", "hostdev"):
2016 vlan_elem = etree.Element("vlan")
2017 tag_elem = etree.Element("tag", id=str(self.vlan))
2018 vlan_elem.append(tag_elem)
2019 dev.append(vlan_elem)
2021 if self.target_dev is not None:
2022 dev.append(etree.Element("target", dev=self.target_dev))
2024 if self.vporttype is not None:
2025 vport = etree.Element("virtualport", type=self.vporttype)
2026 for p in self.vportparams:
2027 param = etree.Element("parameters")
2028 param.set(p['key'], p['value'])
2029 vport.append(param)
2030 dev.append(vport)
2032 if self.filtername is not None:
2033 filter = etree.Element("filterref", filter=self.filtername)
2034 for p in self.filterparams:
2035 filter.append(etree.Element("parameter",
2036 name=p['key'],
2037 value=p['value']))
2038 dev.append(filter)
2040 if self.vif_inbound_average or self.vif_outbound_average:
2041 bandwidth = etree.Element("bandwidth")
2042 if self.vif_inbound_average is not None: 2042 ↛ 2051line 2042 didn't jump to line 2051 because the condition on line 2042 was always true
2043 vif_inbound = etree.Element("inbound",
2044 average=str(self.vif_inbound_average))
2045 if self.vif_inbound_peak is not None: 2045 ↛ 2047line 2045 didn't jump to line 2047 because the condition on line 2045 was always true
2046 vif_inbound.set("peak", str(self.vif_inbound_peak))
2047 if self.vif_inbound_burst is not None: 2047 ↛ 2049line 2047 didn't jump to line 2049 because the condition on line 2047 was always true
2048 vif_inbound.set("burst", str(self.vif_inbound_burst))
2049 bandwidth.append(vif_inbound)
2051 if self.vif_outbound_average is not None: 2051 ↛ 2059line 2051 didn't jump to line 2059 because the condition on line 2051 was always true
2052 vif_outbound = etree.Element("outbound",
2053 average=str(self.vif_outbound_average))
2054 if self.vif_outbound_peak is not None: 2054 ↛ 2056line 2054 didn't jump to line 2056 because the condition on line 2054 was always true
2055 vif_outbound.set("peak", str(self.vif_outbound_peak))
2056 if self.vif_outbound_burst is not None: 2056 ↛ 2058line 2056 didn't jump to line 2058 because the condition on line 2056 was always true
2057 vif_outbound.set("burst", str(self.vif_outbound_burst))
2058 bandwidth.append(vif_outbound)
2059 dev.append(bandwidth)
2061 return dev
2063 def parse_dom(self, xmldoc):
2064 super(LibvirtConfigGuestInterface, self).parse_dom(xmldoc)
2066 self.net_type = xmldoc.get('type')
2068 for c in xmldoc:
2069 if c.tag == 'mac':
2070 self.mac_addr = c.get('address')
2071 elif c.tag == 'model':
2072 self.model = c.get('type')
2073 elif c.tag == 'driver':
2074 self.driver_name = c.get('name')
2075 self.driver_iommu = (c.get('iommu', '') == 'on')
2076 self.driver_packed = (c.get('packed', '') == 'on')
2077 self.vhost_queues = c.get('queues')
2078 self.vhost_rx_queue_size = c.get('rx_queue_size')
2079 self.vhost_tx_queue_size = c.get('tx_queue_size')
2080 elif c.tag == 'source':
2081 if self.net_type == 'direct':
2082 self.source_dev = c.get('dev')
2083 self.source_mode = c.get('mode', 'private')
2084 elif self.net_type == 'vdpa': 2084 ↛ 2085line 2084 didn't jump to line 2085 because the condition on line 2084 was never true
2085 self.source_dev = c.get('dev')
2086 elif self.net_type == 'vhostuser':
2087 self.vhostuser_type = c.get('type')
2088 self.vhostuser_mode = c.get('mode')
2089 self.vhostuser_path = c.get('path')
2090 elif self.net_type == 'hostdev':
2091 for sub in c:
2092 if sub.tag == 'address' and sub.get('type') == 'pci': 2092 ↛ 2091line 2092 didn't jump to line 2091 because the condition on line 2092 was always true
2093 # strip the 0x prefix on each attribute since
2094 # format_dom puts them back on - note that
2095 # LibvirtConfigGuestHostdevPCI does not do this...
2096 self.source_dev = (
2097 pci_utils.get_pci_address(
2098 sub.get('domain')[2:],
2099 sub.get('bus')[2:],
2100 sub.get('slot')[2:],
2101 sub.get('function')[2:]
2102 )
2103 )
2104 else:
2105 self.source_dev = c.get('bridge')
2106 elif c.tag == 'target':
2107 self.target_dev = c.get('dev')
2108 elif c.tag == 'script': 2108 ↛ 2109line 2108 didn't jump to line 2109 because the condition on line 2108 was never true
2109 self.script = c.get('path')
2110 elif c.tag == 'vlan':
2111 # NOTE(mriedem): The vlan element can have multiple tag
2112 # sub-elements but we're currently only storing a single tag
2113 # id in the vlan attribute.
2114 for sub in c: 2114 ↛ 2068line 2114 didn't jump to line 2068 because the loop on line 2114 didn't complete
2115 if sub.tag == 'tag' and sub.get('id'): 2115 ↛ 2114line 2115 didn't jump to line 2114 because the condition on line 2115 was always true
2116 self.vlan = int(sub.get('id'))
2117 break
2118 elif c.tag == 'virtualport':
2119 self.vporttype = c.get('type')
2120 for sub in c:
2121 if sub.tag == 'parameters': 2121 ↛ 2120line 2121 didn't jump to line 2120 because the condition on line 2121 was always true
2122 for k, v in dict(sub.attrib).items():
2123 self.add_vport_param(k, v)
2124 elif c.tag == 'filterref':
2125 self.filtername = c.get('filter')
2126 for sub in c:
2127 if sub.tag == 'parameter': 2127 ↛ 2126line 2127 didn't jump to line 2126 because the condition on line 2127 was always true
2128 self.add_filter_param(sub.get('name'),
2129 sub.get('value'))
2130 elif c.tag == 'bandwidth':
2131 for sub in c:
2132 # Note that only average is mandatory, burst and peak are
2133 # optional (and all are ints).
2134 if sub.tag == 'inbound':
2135 self.vif_inbound_average = int(sub.get('average'))
2136 if sub.get('burst'): 2136 ↛ 2138line 2136 didn't jump to line 2138 because the condition on line 2136 was always true
2137 self.vif_inbound_burst = int(sub.get('burst'))
2138 if sub.get('peak'): 2138 ↛ 2131line 2138 didn't jump to line 2131 because the condition on line 2138 was always true
2139 self.vif_inbound_peak = int(sub.get('peak'))
2140 elif sub.tag == 'outbound': 2140 ↛ 2131line 2140 didn't jump to line 2131 because the condition on line 2140 was always true
2141 self.vif_outbound_average = int(sub.get('average'))
2142 if sub.get('burst'): 2142 ↛ 2144line 2142 didn't jump to line 2144 because the condition on line 2142 was always true
2143 self.vif_outbound_burst = int(sub.get('burst'))
2144 if sub.get('peak'): 2144 ↛ 2131line 2144 didn't jump to line 2131 because the condition on line 2144 was always true
2145 self.vif_outbound_peak = int(sub.get('peak'))
2146 elif c.tag == 'address':
2147 obj = LibvirtConfigGuestDeviceAddress.parse_dom(c)
2148 self.device_addr = obj
2149 elif c.tag == 'mtu':
2150 self.mtu = int(c.get('size'))
2151 elif c.tag == 'alias': 2151 ↛ 2068line 2151 didn't jump to line 2068 because the condition on line 2151 was always true
2152 self.alias = c.get('name')
2154 def add_filter_param(self, key, value):
2155 self.filterparams.append({'key': key, 'value': value})
2157 def add_vport_param(self, key, value):
2158 self.vportparams.append({'key': key, 'value': value})
2161class LibvirtConfigGuestInput(LibvirtConfigGuestDevice):
2163 def __init__(self, **kwargs):
2164 super(LibvirtConfigGuestInput, self).__init__(root_name="input",
2165 **kwargs)
2167 self.type = "tablet"
2168 self.bus = "usb"
2169 self.driver_iommu = False
2171 def format_dom(self):
2172 dev = super(LibvirtConfigGuestInput, self).format_dom()
2174 dev.set("type", self.type)
2175 dev.set("bus", self.bus)
2176 if self.driver_iommu:
2177 dev.append(etree.Element('driver', iommu="on"))
2179 return dev
2182class LibvirtConfigGuestGraphics(LibvirtConfigGuestDevice):
2184 def __init__(self, **kwargs):
2185 super(LibvirtConfigGuestGraphics, self).__init__(root_name="graphics",
2186 **kwargs)
2188 self.type = "vnc"
2189 self.autoport = True
2190 self.keymap = None
2191 self.listen = None
2192 self.secure = None
2194 self.image_compression = None
2195 self.jpeg_compression = None
2196 self.zlib_compression = None
2197 self.playback_compression = None
2198 self.streaming_mode = None
2200 def format_dom(self):
2201 dev = super(LibvirtConfigGuestGraphics, self).format_dom()
2203 dev.set("type", self.type)
2204 dev.set("autoport", self.get_yes_no_str(self.autoport))
2205 if self.keymap:
2206 dev.set("keymap", self.keymap)
2207 if self.listen: 2207 ↛ 2210line 2207 didn't jump to line 2210 because the condition on line 2207 was always true
2208 dev.set("listen", self.listen)
2210 if self.type == "spice":
2211 if self.image_compression is not None:
2212 dev.append(etree.Element(
2213 'image', compression=self.image_compression))
2214 if self.jpeg_compression is not None:
2215 dev.append(etree.Element(
2216 'jpeg', compression=self.jpeg_compression))
2217 if self.zlib_compression is not None:
2218 dev.append(etree.Element(
2219 'zlib', compression=self.zlib_compression))
2220 if self.playback_compression is not None:
2221 dev.append(etree.Element(
2222 'playback', compression=self.get_on_off_str(
2223 self.playback_compression)))
2224 if self.streaming_mode is not None:
2225 dev.append(etree.Element(
2226 'streaming', mode=self.streaming_mode))
2227 if self.secure:
2228 for channel in ['main', 'display', 'inputs', 'cursor',
2229 'playback', 'record', 'smartcard', 'usbredir']:
2230 dev.append(etree.Element('channel', name=channel,
2231 mode='secure'))
2233 return dev
2236class LibvirtConfigSeclabel(LibvirtConfigObject):
2238 def __init__(self, **kwargs):
2239 super(LibvirtConfigSeclabel, self).__init__(root_name="seclabel",
2240 **kwargs)
2241 self.type = 'dynamic'
2242 self.baselabel = None
2244 def format_dom(self):
2245 seclabel = super(LibvirtConfigSeclabel, self).format_dom()
2247 seclabel.set('type', self.type)
2248 if self.baselabel:
2249 seclabel.append(self._text_node("baselabel", self.baselabel))
2251 return seclabel
2254class LibvirtConfigGuestVideo(LibvirtConfigGuestDevice):
2256 def __init__(self, **kwargs):
2257 super(LibvirtConfigGuestVideo, self).__init__(root_name="video",
2258 **kwargs)
2260 self.type = 'virtio'
2261 self.vram = None
2262 self.heads = None
2263 self.driver_iommu = False
2265 @property
2266 def uses_virtio(self):
2267 return 'virtio' == self.type
2269 def format_dom(self):
2270 dev = super(LibvirtConfigGuestVideo, self).format_dom()
2272 model = etree.Element("model")
2273 model.set("type", self.type)
2275 if self.vram:
2276 model.set("vram", str(self.vram))
2278 if self.heads:
2279 model.set("heads", str(self.heads))
2281 dev.append(model)
2283 if self.driver_iommu:
2284 dev.append(etree.Element("driver", iommu="on"))
2286 return dev
2289class LibvirtConfigMemoryBalloon(LibvirtConfigGuestDevice):
2290 def __init__(self, **kwargs):
2291 super(LibvirtConfigMemoryBalloon, self).__init__(
2292 root_name='memballoon',
2293 **kwargs)
2294 self.model = None
2295 self.period = None
2296 self.driver_iommu = False
2298 @property
2299 def uses_virtio(self):
2300 return 'virtio' == self.model
2302 def format_dom(self):
2303 dev = super(LibvirtConfigMemoryBalloon, self).format_dom()
2304 dev.set('model', str(self.model))
2305 if self.period is not None:
2306 dev.append(etree.Element('stats', period=str(self.period)))
2307 if self.driver_iommu:
2308 dev.append(etree.Element('driver', iommu='on'))
2309 return dev
2312class LibvirtConfigGuestController(LibvirtConfigGuestDevice):
2314 def __init__(self, **kwargs):
2315 super(LibvirtConfigGuestController,
2316 self).__init__(root_name="controller", **kwargs)
2318 self.type = None
2319 self.index = None
2320 self.model = None
2321 self.driver_iommu = False
2323 @property
2324 def uses_virtio(self):
2325 model_is_virtio = 'virtio-scsi' == self.model
2326 type_is_virtio = 'virtio-serial' == self.type
2327 return model_is_virtio or type_is_virtio
2329 def format_dom(self):
2330 controller = super(LibvirtConfigGuestController, self).format_dom()
2331 controller.set("type", self.type)
2333 if self.index is not None: 2333 ↛ 2336line 2333 didn't jump to line 2336 because the condition on line 2333 was always true
2334 controller.set("index", str(self.index))
2336 if self.model:
2337 controller.set("model", str(self.model))
2339 if self.driver_iommu:
2340 controller.append(etree.Element("driver", iommu="on"))
2342 return controller
2345class LibvirtConfigGuestUSBHostController(LibvirtConfigGuestController):
2347 def __init__(self, **kwargs):
2348 super(LibvirtConfigGuestUSBHostController, self).__init__(**kwargs)
2349 self.type = 'usb'
2352class LibvirtConfigGuestPCIeRootController(LibvirtConfigGuestController):
2354 def __init__(self, **kwargs):
2355 super(LibvirtConfigGuestPCIeRootController, self).\
2356 __init__(**kwargs)
2357 self.type = 'pci'
2358 self.model = 'pcie-root'
2361class LibvirtConfigGuestPCIeRootPortController(LibvirtConfigGuestController):
2363 def __init__(self, **kwargs):
2364 super(LibvirtConfigGuestPCIeRootPortController, self).\
2365 __init__(**kwargs)
2366 self.type = 'pci'
2367 self.model = 'pcie-root-port'
2370class LibvirtConfigGuestHostdev(LibvirtConfigGuestDevice):
2371 def __init__(self, **kwargs):
2372 super(LibvirtConfigGuestHostdev, self).__init__(
2373 root_name="hostdev", **kwargs,
2374 )
2375 self.mode = None
2376 self.type = None
2377 # managed attribute is only used by PCI devices but mediated devices
2378 # need to say managed=no
2379 self.managed = "yes"
2381 def format_dom(self):
2382 dev = super(LibvirtConfigGuestHostdev, self).format_dom()
2383 dev.set("mode", self.mode)
2384 dev.set("type", self.type)
2385 dev.set("managed", self.managed)
2386 return dev
2388 def parse_dom(self, xmldoc):
2389 super(LibvirtConfigGuestHostdev, self).parse_dom(xmldoc)
2390 self.mode = xmldoc.get('mode')
2391 self.type = xmldoc.get('type')
2392 self.managed = xmldoc.get('managed')
2393 return list(xmldoc)
2396class LibvirtConfigGuestHostdevPCI(LibvirtConfigGuestHostdev):
2397 def __init__(self, **kwargs):
2398 super(LibvirtConfigGuestHostdevPCI, self).\
2399 __init__(**kwargs)
2401 self.mode = 'subsystem'
2402 self.type = 'pci'
2404 # These are returned from libvirt as hexadecimal strings with 0x prefix
2405 # even if they have a different meaningful range: domain 16 bit,
2406 # bus 8 bit, slot 5 bit, and function 3 bit
2407 # On the other hand nova generates these values without the 0x prefix
2408 self.domain = None
2409 self.bus = None
2410 self.slot = None
2411 self.function = None
2413 self.alias = None
2415 def __eq__(self, other):
2416 if not isinstance(other, LibvirtConfigGuestHostdevPCI): 2416 ↛ 2417line 2416 didn't jump to line 2417 because the condition on line 2416 was never true
2417 return False
2419 # NOTE(gibi): nova generates hexa string without 0x prefix but
2420 # libvirt uses that prefix when returns the config so we need to
2421 # normalize the strings before comparison
2422 return (
2423 int(self.domain, 16) == int(other.domain, 16) and
2424 int(self.bus, 16) == int(other.bus, 16) and
2425 int(self.slot, 16) == int(other.slot, 16) and
2426 int(self.function, 16) == int(other.function, 16))
2428 def format_dom(self):
2429 dev = super(LibvirtConfigGuestHostdevPCI, self).format_dom()
2431 address = etree.Element(
2432 "address",
2433 domain=self.domain if self.domain.startswith('0x')
2434 else '0x' + self.domain,
2435 bus=self.bus if self.bus.startswith('0x') else '0x' + self.bus,
2436 slot=self.slot if self.slot.startswith('0x') else '0x' + self.slot,
2437 function=self.function if self.function.startswith('0x')
2438 else '0x' + self.function)
2439 source = etree.Element("source")
2440 source.append(address)
2441 dev.append(source)
2442 return dev
2444 def parse_dom(self, xmldoc):
2445 childs = super(LibvirtConfigGuestHostdevPCI, self).parse_dom(xmldoc)
2446 for c in childs:
2447 if c.tag == "source":
2448 for sub in c:
2449 if sub.tag == 'address':
2450 self.domain = sub.get('domain')
2451 self.bus = sub.get('bus')
2452 self.slot = sub.get('slot')
2453 self.function = sub.get('function')
2454 elif c.tag == 'alias':
2455 self.alias = c.get('name')
2458class LibvirtConfigGuestHostdevMDEV(LibvirtConfigGuestHostdev):
2459 def __init__(self, **kwargs):
2460 super(LibvirtConfigGuestHostdevMDEV, self).__init__(**kwargs)
2462 self.mode = 'subsystem'
2463 self.type = 'mdev'
2464 self.managed = 'no'
2466 # model attribute is only supported by mediated devices
2467 self.model = 'vfio-pci'
2468 self.uuid = None
2470 def format_dom(self):
2471 dev = super(LibvirtConfigGuestHostdevMDEV, self).format_dom()
2472 if self.model: 2472 ↛ 2475line 2472 didn't jump to line 2475 because the condition on line 2472 was always true
2473 dev.set("model", self.model)
2475 address = etree.Element("address", uuid=self.uuid)
2476 source = etree.Element("source")
2477 source.append(address)
2478 dev.append(source)
2479 return dev
2481 def parse_dom(self, xmldoc):
2482 children = super(LibvirtConfigGuestHostdevMDEV, self).parse_dom(xmldoc)
2483 if xmldoc.get('model'): 2483 ↛ 2485line 2483 didn't jump to line 2485 because the condition on line 2483 was always true
2484 self.model = xmldoc.get('model')
2485 for c in children: 2485 ↛ exitline 2485 didn't return from function 'parse_dom' because the loop on line 2485 didn't complete
2486 if c.tag == "source": 2486 ↛ 2485line 2486 didn't jump to line 2485 because the condition on line 2486 was always true
2487 for sub in c: 2487 ↛ 2485line 2487 didn't jump to line 2485 because the loop on line 2487 didn't complete
2488 if sub.tag == 'address': 2488 ↛ 2487line 2488 didn't jump to line 2487 because the condition on line 2488 was always true
2489 self.uuid = sub.get('uuid')
2490 return
2493class LibvirtConfigGuestCharBase(LibvirtConfigGuestDevice):
2495 def __init__(self, **kwargs):
2496 super(LibvirtConfigGuestCharBase, self).__init__(**kwargs)
2498 self.type = "pty"
2499 self.source_path = None
2500 self.listen_port = None
2501 self.listen_host = None
2502 self.log = None
2504 def format_dom(self):
2505 dev = super(LibvirtConfigGuestCharBase, self).format_dom()
2507 dev.set("type", self.type)
2509 if self.type == "file":
2510 dev.append(etree.Element("source", path=self.source_path))
2511 elif self.type == "unix":
2512 dev.append(etree.Element("source", mode="bind",
2513 path=self.source_path))
2514 elif self.type == "tcp":
2515 dev.append(etree.Element("source", mode="bind",
2516 host=self.listen_host,
2517 service=str(self.listen_port)))
2519 if self.log:
2520 dev.append(self.log.format_dom())
2522 return dev
2525class LibvirtConfigGuestChar(LibvirtConfigGuestCharBase):
2527 def __init__(self, **kwargs):
2528 super(LibvirtConfigGuestChar, self).__init__(**kwargs)
2530 self.target_port = None
2531 self.target_type = None
2533 def format_dom(self):
2534 dev = super(LibvirtConfigGuestChar, self).format_dom()
2536 if self.target_port is not None or self.target_type is not None:
2537 target = etree.Element("target")
2538 if self.target_port is not None:
2539 target.set("port", str(self.target_port))
2540 if self.target_type is not None:
2541 target.set("type", self.target_type)
2542 dev.append(target)
2544 return dev
2547class LibvirtConfigGuestCharDeviceLog(LibvirtConfigObject):
2548 """Represents a sub-element to a character device."""
2550 def __init__(self, **kwargs):
2551 super(LibvirtConfigGuestCharDeviceLog, self).__init__(root_name="log",
2552 **kwargs)
2553 self.file = None
2554 self.append = "off"
2556 def parse_dom(self, xmldoc):
2557 super(LibvirtConfigGuestCharDeviceLog, self).parse_dom(xmldoc)
2558 self.file = xmldoc.get("file")
2559 self.append = xmldoc.get("append")
2561 def format_dom(self):
2562 log = super(LibvirtConfigGuestCharDeviceLog, self).format_dom()
2563 log.set("file", self.file)
2564 log.set("append", self.append)
2565 return log
2568class LibvirtConfigGuestSerial(LibvirtConfigGuestChar):
2570 def __init__(self, **kwargs):
2571 super(LibvirtConfigGuestSerial, self).__init__(root_name="serial",
2572 **kwargs)
2575class LibvirtConfigGuestConsole(LibvirtConfigGuestChar):
2577 def __init__(self, **kwargs):
2578 super(LibvirtConfigGuestConsole, self).__init__(root_name="console",
2579 **kwargs)
2582class LibvirtConfigGuestChannel(LibvirtConfigGuestCharBase):
2584 def __init__(self, **kwargs):
2585 super(LibvirtConfigGuestChannel, self).__init__(root_name="channel",
2586 **kwargs)
2588 self.target_type = "virtio"
2589 self.target_name = None
2591 def format_dom(self):
2592 dev = super(LibvirtConfigGuestChannel, self).format_dom()
2594 target = etree.Element("target", type=self.target_type)
2595 if self.target_name is not None:
2596 target.set("name", self.target_name)
2597 dev.append(target)
2599 return dev
2602class LibvirtConfigGuestWatchdog(LibvirtConfigGuestDevice):
2603 def __init__(self, **kwargs):
2604 super(LibvirtConfigGuestWatchdog, self).__init__(root_name="watchdog",
2605 **kwargs)
2607 self.model = 'i6300esb'
2608 self.action = 'reset'
2610 def format_dom(self):
2611 dev = super(LibvirtConfigGuestWatchdog, self).format_dom()
2613 dev.set('model', self.model)
2614 dev.set('action', self.action)
2616 return dev
2619class LibvirtConfigGuestCPUTuneVCPUPin(LibvirtConfigObject):
2621 def __init__(self, **kwargs):
2622 super(LibvirtConfigGuestCPUTuneVCPUPin, self).__init__(
2623 root_name="vcpupin",
2624 **kwargs)
2626 self.id = None
2627 self.cpuset = None
2629 def format_dom(self):
2630 root = super(LibvirtConfigGuestCPUTuneVCPUPin, self).format_dom()
2632 root.set("vcpu", str(self.id))
2633 if self.cpuset is not None: 2633 ↛ 2637line 2633 didn't jump to line 2637 because the condition on line 2633 was always true
2634 root.set("cpuset",
2635 hardware.format_cpu_spec(self.cpuset))
2637 return root
2640class LibvirtConfigGuestCPUTuneEmulatorPin(LibvirtConfigObject):
2642 def __init__(self, **kwargs):
2643 super(LibvirtConfigGuestCPUTuneEmulatorPin, self).__init__(
2644 root_name="emulatorpin",
2645 **kwargs)
2647 self.cpuset = None
2649 def format_dom(self):
2650 root = super(LibvirtConfigGuestCPUTuneEmulatorPin, self).format_dom()
2652 if self.cpuset is not None: 2652 ↛ 2656line 2652 didn't jump to line 2656 because the condition on line 2652 was always true
2653 root.set("cpuset",
2654 hardware.format_cpu_spec(self.cpuset))
2656 return root
2659class LibvirtConfigGuestCPUTuneVCPUSched(LibvirtConfigObject):
2661 def __init__(self, **kwargs):
2662 super(LibvirtConfigGuestCPUTuneVCPUSched, self).__init__(
2663 root_name="vcpusched",
2664 **kwargs)
2666 self.vcpus = None
2667 self.scheduler = None
2668 self.priority = None
2670 def format_dom(self):
2671 root = super(LibvirtConfigGuestCPUTuneVCPUSched, self).format_dom()
2673 if self.vcpus is not None: 2673 ↛ 2676line 2673 didn't jump to line 2676 because the condition on line 2673 was always true
2674 root.set("vcpus",
2675 hardware.format_cpu_spec(self.vcpus))
2676 if self.scheduler is not None: 2676 ↛ 2678line 2676 didn't jump to line 2678 because the condition on line 2676 was always true
2677 root.set("scheduler", self.scheduler)
2678 if self.priority is not None: 2678 ↛ 2681line 2678 didn't jump to line 2681 because the condition on line 2678 was always true
2679 root.set("priority", str(self.priority))
2681 return root
2684class LibvirtConfigGuestCPUTune(LibvirtConfigObject):
2686 def __init__(self, **kwargs):
2687 super(LibvirtConfigGuestCPUTune, self).__init__(root_name="cputune",
2688 **kwargs)
2689 self.shares = None
2690 self.quota = None
2691 self.period = None
2692 self.vcpupin = []
2693 self.emulatorpin = None
2694 self.vcpusched = []
2696 def format_dom(self):
2697 root = super(LibvirtConfigGuestCPUTune, self).format_dom()
2699 if self.shares is not None:
2700 root.append(self._text_node("shares", str(self.shares)))
2701 if self.quota is not None:
2702 root.append(self._text_node("quota", str(self.quota)))
2703 if self.period is not None:
2704 root.append(self._text_node("period", str(self.period)))
2706 if self.emulatorpin is not None:
2707 root.append(self.emulatorpin.format_dom())
2708 for vcpu in self.vcpupin:
2709 root.append(vcpu.format_dom())
2710 for sched in self.vcpusched:
2711 root.append(sched.format_dom())
2713 return root
2716class LibvirtConfigGuestMemoryBacking(LibvirtConfigObject):
2718 def __init__(self, **kwargs):
2719 super(LibvirtConfigGuestMemoryBacking, self).__init__(
2720 root_name="memoryBacking", **kwargs)
2722 self.hugepages = []
2723 self.sharedpages = True
2724 self.locked = False
2725 self.filesource = False
2726 self.sharedaccess = False
2727 self.allocateimmediate = False
2728 self.discard = False
2730 def format_dom(self):
2731 root = super(LibvirtConfigGuestMemoryBacking, self).format_dom()
2733 if self.hugepages:
2734 hugepages = etree.Element("hugepages")
2735 for item in self.hugepages:
2736 hugepages.append(item.format_dom())
2737 root.append(hugepages)
2738 if not self.sharedpages:
2739 root.append(etree.Element("nosharepages"))
2740 if self.locked:
2741 root.append(etree.Element("locked"))
2742 if self.filesource:
2743 root.append(etree.Element("source", type="file"))
2744 if self.sharedaccess:
2745 root.append(etree.Element("access", mode="shared"))
2746 if self.allocateimmediate:
2747 root.append(etree.Element("allocation", mode="immediate"))
2748 if self.discard:
2749 root.append(etree.Element("discard"))
2751 return root
2754class LibvirtConfigGuestMemoryBackingPage(LibvirtConfigObject):
2756 def __init__(self, **kwargs):
2757 super(LibvirtConfigGuestMemoryBackingPage, self).__init__(
2758 root_name="page", **kwargs)
2760 self.size_kb = None
2761 self.nodeset = None
2763 def format_dom(self):
2764 page = super(LibvirtConfigGuestMemoryBackingPage, self).format_dom()
2766 page.set("size", str(self.size_kb))
2767 page.set("nodeset", hardware.format_cpu_spec(self.nodeset))
2768 page.set("unit", "KiB")
2770 return page
2773class LibvirtConfigGuestMemoryTune(LibvirtConfigObject):
2775 def __init__(self, **kwargs):
2776 super(LibvirtConfigGuestMemoryTune, self).__init__(
2777 root_name="memtune", **kwargs)
2779 self.hard_limit = None
2780 self.soft_limit = None
2781 self.swap_hard_limit = None
2782 self.min_guarantee = None
2784 def format_dom(self):
2785 root = super(LibvirtConfigGuestMemoryTune, self).format_dom()
2787 if self.hard_limit is not None:
2788 root.append(self._text_node("hard_limit",
2789 str(self.hard_limit),
2790 unit="KiB"))
2791 if self.soft_limit is not None:
2792 root.append(self._text_node("soft_limit",
2793 str(self.soft_limit),
2794 unit="KiB"))
2795 if self.swap_hard_limit is not None:
2796 root.append(self._text_node("swap_hard_limit",
2797 str(self.swap_hard_limit),
2798 unit="KiB"))
2799 if self.min_guarantee is not None:
2800 root.append(self._text_node("min_guarantee",
2801 str(self.min_guarantee),
2802 unit="KiB"))
2804 return root
2807class LibvirtConfigGuestNUMATuneMemory(LibvirtConfigObject):
2809 def __init__(self, **kwargs):
2810 super(LibvirtConfigGuestNUMATuneMemory, self).__init__(
2811 root_name="memory", **kwargs)
2813 self.mode = "strict"
2814 self.nodeset = []
2816 def format_dom(self):
2817 root = super(LibvirtConfigGuestNUMATuneMemory, self).format_dom()
2819 root.set("mode", self.mode)
2820 root.set("nodeset", hardware.format_cpu_spec(self.nodeset))
2822 return root
2825class LibvirtConfigGuestNUMATuneMemNode(LibvirtConfigObject):
2827 def __init__(self, **kwargs):
2828 super(LibvirtConfigGuestNUMATuneMemNode, self).__init__(
2829 root_name="memnode", **kwargs)
2831 self.cellid = 0
2832 self.mode = "strict"
2833 self.nodeset = []
2835 def format_dom(self):
2836 root = super(LibvirtConfigGuestNUMATuneMemNode, self).format_dom()
2838 root.set("cellid", str(self.cellid))
2839 root.set("mode", self.mode)
2840 root.set("nodeset", hardware.format_cpu_spec(self.nodeset))
2842 return root
2845class LibvirtConfigGuestNUMATune(LibvirtConfigObject):
2847 def __init__(self, **kwargs):
2848 super(LibvirtConfigGuestNUMATune, self).__init__(
2849 root_name="numatune", **kwargs)
2851 self.memory = None
2852 self.memnodes = []
2854 def format_dom(self):
2855 root = super(LibvirtConfigGuestNUMATune, self).format_dom()
2857 if self.memory is not None:
2858 root.append(self.memory.format_dom())
2859 for node in self.memnodes:
2860 root.append(node.format_dom())
2862 return root
2865class LibvirtConfigGuestFeature(LibvirtConfigObject):
2867 def __init__(self, name, **kwargs):
2868 super(LibvirtConfigGuestFeature, self).__init__(root_name=name,
2869 **kwargs)
2872class LibvirtConfigGuestFeatureACPI(LibvirtConfigGuestFeature):
2874 def __init__(self, **kwargs):
2875 super(LibvirtConfigGuestFeatureACPI, self).__init__("acpi",
2876 **kwargs)
2879class LibvirtConfigGuestFeatureAPIC(LibvirtConfigGuestFeature):
2881 def __init__(self, **kwargs):
2882 super(LibvirtConfigGuestFeatureAPIC, self).__init__("apic",
2883 **kwargs)
2886class LibvirtConfigGuestFeatureKvmHidden(LibvirtConfigGuestFeature):
2888 def __init__(self, **kwargs):
2889 super(LibvirtConfigGuestFeatureKvmHidden, self).__init__("kvm",
2890 **kwargs)
2892 def format_dom(self):
2893 root = super(LibvirtConfigGuestFeatureKvmHidden, self).format_dom()
2895 root.append(etree.Element("hidden", state="on"))
2897 return root
2900class LibvirtConfigGuestFeatureSMM(LibvirtConfigGuestFeature):
2902 def __init__(self, **kwargs):
2903 super(LibvirtConfigGuestFeatureSMM, self).__init__("smm", **kwargs)
2905 def format_dom(self):
2906 root = super(LibvirtConfigGuestFeatureSMM, self).format_dom()
2908 root.append(etree.Element("smm", state="on"))
2910 return root
2913class LibvirtConfigGuestFeatureTCG(LibvirtConfigGuestFeature):
2915 def __init__(self, cache_size, **kwargs):
2916 super(LibvirtConfigGuestFeatureTCG, self).__init__("tcg", **kwargs)
2918 self.cache_size = str(cache_size)
2920 def format_dom(self):
2921 root = super(LibvirtConfigGuestFeatureTCG, self).format_dom()
2922 root.append(self._text_node("tb-cache", self.cache_size,
2923 unit="MiB"))
2925 return root
2928class LibvirtConfigGuestFeaturePMU(LibvirtConfigGuestFeature):
2930 def __init__(self, state, **kwargs):
2931 super(LibvirtConfigGuestFeaturePMU, self).__init__("pmu", **kwargs)
2932 # NOTE(sean-k-mooney): bool_from_string is needed to handle the raw
2933 # flavor exta_sepc value. bool_from_string internally checks if the
2934 # value is already a bool and returns it. As such it's safe to use
2935 # with the image metadata property too, so we call it unconditionally.
2936 self.state = strutils.bool_from_string(state)
2938 def format_dom(self):
2939 root = super(LibvirtConfigGuestFeaturePMU, self).format_dom()
2940 root.attrib['state'] = "on" if self.state else "off"
2941 return root
2944class LibvirtConfigGuestFeatureIOAPIC(LibvirtConfigGuestFeature):
2946 def __init__(self, **kwargs):
2947 super().__init__("ioapic", **kwargs)
2948 self.driver = "qemu"
2950 def format_dom(self):
2951 root = super().format_dom()
2952 root.set('driver', self.driver)
2953 return root
2956class LibvirtConfigGuestFeatureHyperV(LibvirtConfigGuestFeature):
2958 # QEMU requires at least this value to be set
2959 MIN_SPINLOCK_RETRIES = 4095
2960 # The spoofed vendor_id can be any alphanumeric string
2961 SPOOFED_VENDOR_ID = "1234567890ab"
2963 def __init__(self, **kwargs):
2964 super(LibvirtConfigGuestFeatureHyperV, self).__init__("hyperv",
2965 **kwargs)
2967 self.relaxed = False
2968 self.vapic = False
2969 self.spinlocks = False
2970 self.spinlock_retries = self.MIN_SPINLOCK_RETRIES
2971 self.vpindex = False
2972 self.runtime = False
2973 self.synic = False
2974 self.reset = False
2975 self.frequencies = False
2976 self.reenlightenment = False
2977 self.tlbflush = False
2978 self.ipi = False
2979 self.evmcs = False
2980 self.vendorid_spoof = False
2981 self.vendorid = self.SPOOFED_VENDOR_ID
2983 def format_dom(self):
2984 root = super(LibvirtConfigGuestFeatureHyperV, self).format_dom()
2986 if self.relaxed: 2986 ↛ 2988line 2986 didn't jump to line 2988 because the condition on line 2986 was always true
2987 root.append(etree.Element("relaxed", state="on"))
2988 if self.vapic:
2989 root.append(etree.Element("vapic", state="on"))
2990 if self.spinlocks:
2991 root.append(etree.Element("spinlocks", state="on",
2992 retries=str(self.spinlock_retries)))
2993 if self.vendorid_spoof:
2994 root.append(etree.Element("vendor_id", state="on",
2995 value=self.vendorid))
2996 if self.vpindex:
2997 root.append(etree.Element('vpindex', state='on'))
2998 if self.runtime:
2999 root.append(etree.Element('runtime', state='on'))
3000 if self.synic:
3001 root.append(etree.Element('synic', state='on'))
3002 if self.reset:
3003 root.append(etree.Element('reset', state='on'))
3004 if self.frequencies:
3005 root.append(etree.Element('frequencies', state='on'))
3006 if self.reenlightenment:
3007 root.append(etree.Element('reenlightenment', state='on'))
3008 if self.tlbflush:
3009 root.append(etree.Element('tlbflush', state='on'))
3010 if self.ipi:
3011 root.append(etree.Element('ipi', state='on'))
3012 if self.evmcs:
3013 root.append(etree.Element('evmcs', state='on'))
3015 return root
3018class LibvirtConfigGuestSEVLaunchSecurity(LibvirtConfigObject):
3020 def __init__(self, **kwargs):
3021 super(LibvirtConfigGuestSEVLaunchSecurity, self).__init__(
3022 root_name='launchSecurity', **kwargs)
3024 self.cbitpos = None
3025 self.reduced_phys_bits = None
3027 def format_dom(self):
3028 root = super(LibvirtConfigGuestSEVLaunchSecurity, self).format_dom()
3030 root.set('type', 'sev')
3031 policy = etree.Element('policy')
3032 policy.text = '0x0033' # hardcoded default according to the spec
3033 root.append(policy)
3035 cbitpos = etree.Element('cbitpos')
3036 cbitpos.text = str(self.cbitpos)
3037 root.append(cbitpos)
3039 reducedPhysBits = etree.Element('reducedPhysBits')
3040 reducedPhysBits.text = str(self.reduced_phys_bits)
3041 root.append(reducedPhysBits)
3043 return root
3046class LibvirtConfigGuestFeatureVMCoreInfo(LibvirtConfigGuestFeature):
3048 def __init__(self, **kwargs):
3049 super().__init__('vmcoreinfo', **kwargs)
3052class LibvirtConfigGuest(LibvirtConfigObject):
3054 def __init__(self, **kwargs):
3055 super(LibvirtConfigGuest, self).__init__(root_name="domain",
3056 **kwargs)
3058 self.virt_type = None
3059 self.uuid = None
3060 self.name = None
3061 self.memory = 500 * units.Mi
3062 self.max_memory_size = None
3063 self.max_memory_slots = 0
3064 self.membacking = None
3065 self.memtune = None
3066 self.numatune = None
3067 self.vcpus = 1
3068 self.cpuset = None
3069 self.cpu = None
3070 self.cputune = None
3071 self.features = []
3072 self.clock = None
3073 self.sysinfo = None
3074 self.os_type = None
3075 self.os_loader = None
3076 self.os_firmware = None
3077 self.os_loader_type = None
3078 self.os_loader_secure = None
3079 self.os_loader_stateless = None
3080 self.os_nvram = None
3081 self.os_nvram_template = None
3082 self.os_kernel = None
3083 self.os_initrd = None
3084 self.os_cmdline = None
3085 self.os_init_env = {}
3086 self.os_root = None
3087 self.os_init_path = None
3088 self.os_boot_dev = []
3089 self.os_smbios = None
3090 self.os_arch = None
3091 self.os_mach_type = None
3092 self.os_bootmenu = False
3093 self.devices = []
3094 self.metadata = []
3095 self.idmaps = []
3096 self.perf_events = []
3097 self.launch_security = None
3099 def _format_basic_props(self, root):
3100 root.append(self._text_node("uuid", self.uuid))
3101 root.append(self._text_node("name", self.name))
3102 root.append(self._text_node("memory", self.memory))
3103 if self.max_memory_size is not None:
3104 max_memory = self._text_node("maxMemory", self.max_memory_size)
3105 max_memory.set("slots", str(self.max_memory_slots))
3106 root.append(max_memory)
3107 if self.membacking is not None:
3108 root.append(self.membacking.format_dom())
3109 if self.memtune is not None:
3110 root.append(self.memtune.format_dom())
3111 if self.numatune is not None:
3112 root.append(self.numatune.format_dom())
3113 if self.cpuset is not None:
3114 vcpu = self._text_node("vcpu", self.vcpus)
3115 vcpu.set("cpuset", hardware.format_cpu_spec(self.cpuset))
3116 root.append(vcpu)
3117 else:
3118 root.append(self._text_node("vcpu", self.vcpus))
3120 if len(self.metadata) > 0:
3121 metadata = etree.Element("metadata")
3122 for m in self.metadata:
3123 metadata.append(m.format_dom())
3124 root.append(metadata)
3126 def _format_os(self, root):
3127 os = etree.Element("os")
3129 if self.os_firmware is not None:
3130 os.set("firmware", self.os_firmware)
3132 type_node = self._text_node("type", self.os_type)
3133 if self.os_arch is not None:
3134 type_node.set("arch", self.os_arch)
3135 if self.os_mach_type is not None:
3136 type_node.set("machine", self.os_mach_type)
3137 os.append(type_node)
3139 if self.os_kernel is not None:
3140 os.append(self._text_node("kernel", self.os_kernel))
3142 if (
3143 self.os_loader is not None or
3144 self.os_loader_type is not None or
3145 self.os_loader_secure is not None or
3146 self.os_loader_stateless is not None
3147 ):
3148 loader = self._text_node("loader", self.os_loader)
3149 if self.os_loader_type is not None:
3150 loader.set("type", self.os_loader_type)
3151 loader.set("readonly", "yes")
3152 if self.os_loader_secure is not None: 3152 ↛ 3155line 3152 didn't jump to line 3155 because the condition on line 3152 was always true
3153 loader.set(
3154 "secure", self.get_yes_no_str(self.os_loader_secure))
3155 if self.os_loader_stateless is not None:
3156 loader.set(
3157 "stateless", self.get_yes_no_str(self.os_loader_stateless))
3158 os.append(loader)
3160 if (
3161 self.os_nvram is not None or
3162 self.os_nvram_template is not None
3163 ):
3164 nvram = self._text_node("nvram", self.os_nvram)
3165 nvram.set("template", self.os_nvram_template)
3166 os.append(nvram)
3168 if self.os_initrd is not None:
3169 os.append(self._text_node("initrd", self.os_initrd))
3170 if self.os_cmdline is not None:
3171 os.append(self._text_node("cmdline", self.os_cmdline))
3172 if self.os_root is not None: 3172 ↛ 3173line 3172 didn't jump to line 3173 because the condition on line 3172 was never true
3173 os.append(self._text_node("root", self.os_root))
3174 if self.os_init_path is not None:
3175 os.append(self._text_node("init", self.os_init_path))
3176 for name, value in self.os_init_env.items():
3177 initenv = self._text_node("initenv", value)
3178 initenv.set("name", name)
3179 os.append(initenv)
3181 for boot_dev in self.os_boot_dev:
3182 os.append(etree.Element("boot", dev=boot_dev))
3184 if self.os_smbios is not None:
3185 os.append(self.os_smbios.format_dom())
3187 if self.os_bootmenu:
3188 os.append(etree.Element("bootmenu", enable="yes"))
3189 root.append(os)
3191 def _format_features(self, root):
3192 if len(self.features) > 0:
3193 features = etree.Element("features")
3194 for feat in self.features:
3195 features.append(feat.format_dom())
3196 root.append(features)
3198 def _format_devices(self, root):
3199 if len(self.devices) == 0:
3200 return
3201 devices = etree.Element("devices")
3202 for dev in self.devices:
3203 devices.append(dev.format_dom())
3204 root.append(devices)
3206 def _format_idmaps(self, root):
3207 if len(self.idmaps) == 0:
3208 return
3209 idmaps = etree.Element("idmap")
3210 for idmap in self.idmaps:
3211 idmaps.append(idmap.format_dom())
3212 root.append(idmaps)
3214 def _format_perf_events(self, root):
3215 if len(self.perf_events) == 0:
3216 return
3217 perfs = etree.Element("perf")
3218 for pe in self.perf_events:
3219 event = etree.Element("event", name=pe, enabled="yes")
3220 perfs.append(event)
3221 root.append(perfs)
3223 def _format_sev(self, root):
3224 if self.launch_security is not None:
3225 root.append(self.launch_security.format_dom())
3227 def format_dom(self):
3228 root = super(LibvirtConfigGuest, self).format_dom()
3230 root.set("type", self.virt_type)
3232 self._format_basic_props(root)
3234 if self.sysinfo is not None:
3235 root.append(self.sysinfo.format_dom())
3237 self._format_os(root)
3238 self._format_features(root)
3240 if self.cputune is not None:
3241 root.append(self.cputune.format_dom())
3243 if self.clock is not None:
3244 root.append(self.clock.format_dom())
3246 if self.cpu is not None:
3247 root.append(self.cpu.format_dom())
3249 self._format_devices(root)
3251 self._format_idmaps(root)
3253 self._format_perf_events(root)
3255 self._format_sev(root)
3257 return root
3259 def _parse_basic_props(self, xmldoc):
3260 # memmbacking, memtune, numatune, metadata are skipped just because
3261 # corresponding config types do not implement parse_dom method
3262 if xmldoc.tag == 'uuid':
3263 self.uuid = xmldoc.text
3264 elif xmldoc.tag == 'name':
3265 self.name = xmldoc.text
3266 elif xmldoc.tag == 'memory':
3267 self.memory = int(xmldoc.text)
3268 elif xmldoc.tag == 'vcpu':
3269 self.vcpus = int(xmldoc.text)
3270 if xmldoc.get('cpuset') is not None:
3271 self.cpuset = hardware.parse_cpu_spec(xmldoc.get('cpuset'))
3273 def _parse_os(self, xmldoc):
3274 if xmldoc.get('firmware'): 3274 ↛ 3275line 3274 didn't jump to line 3275 because the condition on line 3274 was never true
3275 self.os_firmware = xmldoc.get('firmware')
3277 # smbios is skipped just because LibvirtConfigGuestSMBIOS
3278 # does not implement parse_dom method
3279 for c in xmldoc:
3280 if c.tag == 'type':
3281 self.os_type = c.text
3282 self.os_mach_type = c.get('machine')
3283 elif c.tag == 'kernel':
3284 self.os_kernel = c.text
3285 elif c.tag == 'loader':
3286 self.os_loader = c.text
3287 if c.get('type') == 'pflash':
3288 self.os_loader_type = 'pflash'
3289 elif c.tag == 'initrd':
3290 self.os_initrd = c.text
3291 elif c.tag == 'cmdline':
3292 self.os_cmdline = c.text
3293 elif c.tag == 'root':
3294 self.os_root = c.text
3295 elif c.tag == 'init':
3296 self.os_init_path = c.text
3297 elif c.tag == 'boot':
3298 self.os_boot_dev.append(c.get('dev'))
3299 elif c.tag == 'bootmenu':
3300 if c.get('enable') == 'yes': 3300 ↛ 3279line 3300 didn't jump to line 3279 because the condition on line 3300 was always true
3301 self.os_bootmenu = True
3302 elif c.tag == 'initenv':
3303 self.os_init_env[c.get('name')] = c.text
3305 def parse_dom(self, xmldoc):
3306 self.virt_type = xmldoc.get('type')
3307 # Note: This cover only for: LibvirtConfigGuestDisks
3308 # LibvirtConfigGuestFilesys
3309 # LibvirtConfigGuestHostdevPCI
3310 # LibvirtConfigGuestHostdevMDEV
3311 # LibvirtConfigGuestInterface
3312 # LibvirtConfigGuestUidMap
3313 # LibvirtConfigGuestGidMap
3314 # LibvirtConfigGuestCPU
3315 # LibvirtConfigGuestVPMEM
3316 # LibvirtConfigGuestIOMMU
3317 for c in xmldoc:
3318 if c.tag == 'devices':
3319 for d in c:
3320 if d.tag == 'disk':
3321 obj = LibvirtConfigGuestDisk()
3322 obj.parse_dom(d)
3323 self.devices.append(obj)
3324 elif d.tag == 'filesystem':
3325 obj = LibvirtConfigGuestFilesys()
3326 obj.parse_dom(d)
3327 self.devices.append(obj)
3328 elif d.tag == 'hostdev' and d.get('type') == 'pci':
3329 obj = LibvirtConfigGuestHostdevPCI()
3330 obj.parse_dom(d)
3331 self.devices.append(obj)
3332 elif d.tag == 'hostdev' and d.get('type') == 'mdev':
3333 obj = LibvirtConfigGuestHostdevMDEV()
3334 obj.parse_dom(d)
3335 self.devices.append(obj)
3336 elif d.tag == 'interface':
3337 obj = LibvirtConfigGuestInterface()
3338 obj.parse_dom(d)
3339 self.devices.append(obj)
3340 elif d.tag == 'memory' and d.get('model') == 'nvdimm': 3340 ↛ 3341line 3340 didn't jump to line 3341 because the condition on line 3340 was never true
3341 obj = LibvirtConfigGuestVPMEM()
3342 obj.parse_dom(d)
3343 self.devices.append(obj)
3344 elif d.tag == 'iommu': 3344 ↛ 3345line 3344 didn't jump to line 3345 because the condition on line 3344 was never true
3345 obj = LibvirtConfigGuestIOMMU()
3346 obj.parse_dom(d)
3347 self.devices.append(obj)
3348 if c.tag == 'idmap': 3348 ↛ 3349line 3348 didn't jump to line 3349 because the condition on line 3348 was never true
3349 for idmap in c:
3350 obj = None
3351 if idmap.tag == 'uid':
3352 obj = LibvirtConfigGuestUIDMap()
3353 elif idmap.tag == 'gid':
3354 obj = LibvirtConfigGuestGIDMap()
3356 if obj:
3357 obj.parse_dom(idmap)
3358 self.idmaps.append(obj)
3359 elif c.tag == 'cpu':
3360 obj = LibvirtConfigGuestCPU()
3361 obj.parse_dom(c)
3362 self.cpu = obj
3363 elif c.tag == 'perf':
3364 for p in c:
3365 if p.get('enabled') and p.get('enabled') == 'yes':
3366 self.add_perf_event(p.get('name'))
3367 elif c.tag == 'os':
3368 self._parse_os(c)
3369 else:
3370 self._parse_basic_props(c)
3372 def add_feature(self, dev: LibvirtConfigGuestFeature) -> None:
3373 self.features.append(dev)
3375 def add_device(self, dev: LibvirtConfigGuestDevice) -> None:
3376 self.devices.append(dev)
3378 def add_perf_event(self, event):
3379 self.perf_events.append(event)
3381 def set_clock(self, clk):
3382 self.clock = clk
3385class LibvirtConfigGuestSnapshot(LibvirtConfigObject):
3387 def __init__(self, **kwargs):
3388 super(LibvirtConfigGuestSnapshot, self).__init__(
3389 root_name="domainsnapshot",
3390 **kwargs)
3392 self.name = None
3393 self.disks = []
3395 def format_dom(self):
3396 ss = super(LibvirtConfigGuestSnapshot, self).format_dom()
3398 if self.name:
3399 ss.append(self._text_node("name", self.name))
3401 disks = etree.Element('disks')
3403 for disk in self.disks:
3404 disks.append(disk.format_dom())
3406 ss.append(disks)
3408 return ss
3410 def add_disk(self, disk):
3411 self.disks.append(disk)
3414class LibvirtConfigNodeDevice(LibvirtConfigObject):
3415 """Libvirt Node Devices parser."""
3417 def __init__(self, **kwargs):
3418 super(LibvirtConfigNodeDevice, self).__init__(root_name="device",
3419 **kwargs)
3420 self.name = None
3421 self.parent = None
3422 self.pci_capability = None
3423 self.mdev_information = None
3424 self.vdpa_capability = None
3425 self.vpd_capability = None
3427 def format_dom(self):
3428 dev = super().format_dom()
3429 if self.name:
3430 dev.append(self._text_node('name', str(self.name)))
3431 if self.parent:
3432 dev.append(self._text_node('parent', str(self.parent)))
3433 if self.mdev_information:
3434 dev.append(self.mdev_information.format_dom())
3435 return dev
3437 def parse_dom(self, xmldoc):
3438 super(LibvirtConfigNodeDevice, self).parse_dom(xmldoc)
3440 for c in xmldoc:
3441 if c.tag == "name":
3442 self.name = c.text
3443 elif c.tag == "parent":
3444 self.parent = c.text
3445 elif c.tag == "capability" and c.get("type") in ['pci', 'net']:
3446 pcicap = LibvirtConfigNodeDevicePciCap()
3447 pcicap.parse_dom(c)
3448 self.pci_capability = pcicap
3449 elif c.tag == "capability" and c.get("type") in ['mdev']:
3450 mdev_info = LibvirtConfigNodeDeviceMdevInformation()
3451 mdev_info.parse_dom(c)
3452 self.mdev_information = mdev_info
3453 elif c.tag == "capability" and c.get("type") in ['vdpa']:
3454 vdpa_caps = LibvirtConfigNodeDeviceVDPACap()
3455 vdpa_caps.parse_dom(c)
3456 self.vdpa_capability = vdpa_caps
3459class LibvirtConfigNodeDeviceVDPACap(LibvirtConfigObject):
3460 def __init__(self, **kwargs):
3461 super().__init__(
3462 root_name="capability", **kwargs)
3463 self.dev_path = None
3465 def parse_dom(self, xmldoc):
3466 super().parse_dom(xmldoc)
3467 for c in xmldoc:
3468 if c.tag == "chardev": 3468 ↛ 3467line 3468 didn't jump to line 3467 because the condition on line 3468 was always true
3469 self.dev_path = c.text
3472class LibvirtConfigNodeDevicePciCap(LibvirtConfigObject):
3473 """Libvirt Node Devices pci capability parser."""
3475 def __init__(self, **kwargs):
3476 super(LibvirtConfigNodeDevicePciCap, self).__init__(
3477 root_name="capability", **kwargs)
3478 self.domain = None
3479 self.bus = None
3480 self.slot = None
3481 self.function = None
3482 self.product = None
3483 self.product_id = None
3484 self.vendor = None
3485 self.vendor_id = None
3486 self.numa_node = None
3487 self.fun_capability = []
3488 self.mdev_capability = []
3489 self.vpd_capability = None
3490 self.interface = None
3491 self.address = None
3492 self.link_state = None
3493 self.features = []
3495 def parse_dom(self, xmldoc):
3496 super(LibvirtConfigNodeDevicePciCap, self).parse_dom(xmldoc)
3498 for c in xmldoc:
3499 if c.tag == "domain":
3500 self.domain = int(c.text)
3501 elif c.tag == "slot":
3502 self.slot = int(c.text)
3503 elif c.tag == "bus":
3504 self.bus = int(c.text)
3505 elif c.tag == "function":
3506 self.function = int(c.text)
3507 elif c.tag == "product":
3508 self.product = c.text
3509 self.product_id = int(c.get('id'), 16)
3510 elif c.tag == "vendor":
3511 self.vendor = c.text
3512 self.vendor_id = int(c.get('id'), 16)
3513 elif c.tag == "numa":
3514 self.numa_node = int(c.get('node'))
3515 elif c.tag == "interface":
3516 self.interface = c.text
3517 elif c.tag == "address":
3518 self.address = c.text
3519 elif c.tag == "link":
3520 self.link_state = c.get('state')
3521 elif c.tag == "feature":
3522 self.features.append(c.get('name'))
3523 elif c.tag == "capability" and c.get('type') in \
3524 ('virt_functions', 'phys_function'):
3525 funcap = LibvirtConfigNodeDevicePciSubFunctionCap()
3526 funcap.parse_dom(c)
3527 self.fun_capability.append(funcap)
3528 elif c.tag == "capability" and c.get('type') in ('mdev_types',):
3529 mdevcap = LibvirtConfigNodeDeviceMdevCapableSubFunctionCap()
3530 mdevcap.parse_dom(c)
3531 self.mdev_capability.append(mdevcap)
3532 elif c.tag == "capability" and c.get('type') in ('vpd',):
3533 vpdcap = LibvirtConfigNodeDeviceVpdCap()
3534 vpdcap.parse_dom(c)
3535 self.vpd_capability = vpdcap
3537 def pci_address(self):
3538 return "%04x:%02x:%02x.%01x" % (
3539 self.domain, self.bus, self.slot, self.function)
3542class LibvirtConfigNodeDevicePciSubFunctionCap(LibvirtConfigObject):
3543 def __init__(self, **kwargs):
3544 super(LibvirtConfigNodeDevicePciSubFunctionCap, self).__init__(
3545 root_name="capability", **kwargs)
3546 self.type = None
3547 self.device_addrs = list() # list of tuple (domain,bus,slot,function)
3549 def parse_dom(self, xmldoc):
3550 super(LibvirtConfigNodeDevicePciSubFunctionCap, self).parse_dom(xmldoc)
3551 self.type = xmldoc.get("type")
3552 for c in xmldoc:
3553 if c.tag == "address": 3553 ↛ 3552line 3553 didn't jump to line 3552 because the condition on line 3553 was always true
3554 self.device_addrs.append((int(c.get('domain'), 16),
3555 int(c.get('bus'), 16),
3556 int(c.get('slot'), 16),
3557 int(c.get('function'), 16)))
3560class LibvirtConfigNodeDeviceMdevCapableSubFunctionCap(LibvirtConfigObject):
3561 def __init__(self, **kwargs):
3562 super(LibvirtConfigNodeDeviceMdevCapableSubFunctionCap, self).__init__(
3563 root_name="capability", **kwargs)
3564 # mdev_types is a list of dictionaries where each item looks like:
3565 # {'type': 'nvidia-11', 'name': 'GRID M60-0B', 'deviceAPI': 'vfio-pci',
3566 # 'availableInstances': 16}
3567 self.mdev_types = list()
3569 def parse_dom(self, xmldoc):
3570 super(LibvirtConfigNodeDeviceMdevCapableSubFunctionCap,
3571 self).parse_dom(xmldoc)
3572 for c in xmldoc:
3573 if c.tag == "type": 3573 ↛ 3572line 3573 didn't jump to line 3572 because the condition on line 3573 was always true
3574 mdev_type = {'type': c.get('id')}
3575 for e in c:
3576 mdev_type[e.tag] = (int(e.text)
3577 if e.tag == 'availableInstances'
3578 else e.text)
3579 self.mdev_types.append(mdev_type)
3582class LibvirtConfigNodeDeviceMdevInformation(LibvirtConfigObject):
3583 def __init__(self, **kwargs):
3584 super(LibvirtConfigNodeDeviceMdevInformation, self).__init__(
3585 root_name="capability", **kwargs)
3586 self.type = None
3587 self.iommu_group = None
3588 self.uuid = None
3590 def format_dom(self):
3591 dev = super().format_dom()
3592 dev.set('type', 'mdev')
3593 if self.type: 3593 ↛ 3597line 3593 didn't jump to line 3597 because the condition on line 3593 was always true
3594 mdev_type = self._new_node('type')
3595 mdev_type.set('id', self.type)
3596 dev.append(mdev_type)
3597 if self.uuid:
3598 dev.append(self._text_node('uuid', self.uuid))
3599 if self.iommu_group: 3599 ↛ 3603line 3599 didn't jump to line 3603 because the condition on line 3599 was always true
3600 iommu_group = self._new_node('iommuGroup')
3601 iommu_group.set('number', str(self.iommu_group))
3602 dev.append(iommu_group)
3603 return dev
3605 def parse_dom(self, xmldoc):
3606 super(LibvirtConfigNodeDeviceMdevInformation,
3607 self).parse_dom(xmldoc)
3608 for c in xmldoc:
3609 if c.tag == "type":
3610 self.type = c.get('id')
3611 if c.tag == "iommuGroup":
3612 self.iommu_group = int(c.get('number'))
3613 if c.tag == "uuid":
3614 self.uuid = c.text
3617class LibvirtConfigNodeDeviceVpdCap(LibvirtConfigObject):
3619 def __init__(self, **kwargs):
3620 super().__init__(
3621 root_name="capability", **kwargs)
3622 self._card_name = None
3623 self._change_level = None
3624 self._manufacture_id = None
3625 self._part_number = None
3626 self._serial_number = None
3627 self._asset_tag = None
3628 self._ro_vendor_fields = {}
3629 self._rw_vendor_fields = {}
3630 self._rw_system_fields = {}
3632 @staticmethod
3633 def _process_custom_field(fields_dict, field_element):
3634 index = field_element.get('index')
3635 if index: 3635 ↛ exitline 3635 didn't return from function '_process_custom_field' because the condition on line 3635 was always true
3636 fields_dict[index] = field_element.text
3638 def _parse_ro_fields(self, fields_element):
3639 for e in fields_element:
3640 if e.tag == 'change_level':
3641 self._change_level = e.text
3642 elif e.tag == 'manufacture_id':
3643 self._manufacture_id = e.text
3644 elif e.tag == 'part_number':
3645 self._part_number = e.text
3646 elif e.tag == 'serial_number':
3647 self._serial_number = e.text
3648 elif e.tag == 'vendor_field': 3648 ↛ 3639line 3648 didn't jump to line 3639 because the condition on line 3648 was always true
3649 self._process_custom_field(self._ro_vendor_fields, e)
3651 def _parse_rw_fields(self, fields_element):
3652 for e in fields_element:
3653 if e.tag == 'asset_tag':
3654 self._asset_tag = e.text
3655 elif e.tag == 'vendor_field':
3656 self._process_custom_field(self._rw_vendor_fields, e)
3657 elif e.tag == 'system_field': 3657 ↛ 3652line 3657 didn't jump to line 3652 because the condition on line 3657 was always true
3658 self._process_custom_field(self._rw_system_fields, e)
3660 def parse_dom(self, xmldoc):
3661 super(LibvirtConfigNodeDeviceVpdCap, self).parse_dom(xmldoc)
3662 for c in xmldoc:
3663 if c.tag == "name":
3664 self._card_name = c.text
3665 if c.tag == "fields":
3666 access = c.get('access')
3667 if access: 3667 ↛ 3662line 3667 didn't jump to line 3662 because the condition on line 3667 was always true
3668 if access == 'readonly':
3669 self._parse_ro_fields(c)
3670 elif access == 'readwrite': 3670 ↛ 3673line 3670 didn't jump to line 3673 because the condition on line 3670 was always true
3671 self._parse_rw_fields(c)
3672 else:
3673 continue
3675 @property
3676 def card_name(self):
3677 return self._card_name
3679 @property
3680 def change_level(self):
3681 return self._change_level
3683 @property
3684 def manufacture_id(self):
3685 return self._manufacture_id
3687 @property
3688 def part_number(self):
3689 return self._part_number
3691 @property
3692 def card_serial_number(self):
3693 return self._serial_number
3695 @property
3696 def asset_tag(self):
3697 return self._asset_tag
3699 @property
3700 def ro_vendor_fields(self):
3701 return self._ro_vendor_fields
3703 @property
3704 def rw_vendor_fields(self):
3705 return self._rw_vendor_fields
3707 @property
3708 def rw_system_fields(self):
3709 return self._rw_system_fields
3712class LibvirtConfigGuestRng(LibvirtConfigGuestDevice):
3714 def __init__(self, **kwargs):
3715 super(LibvirtConfigGuestRng, self).__init__(root_name="rng",
3716 **kwargs)
3718 self.device_model = 'virtio'
3719 self.model = 'random'
3720 self.backend = None
3721 self.rate_period = None
3722 self.rate_bytes = None
3723 self.driver_iommu = False
3725 @property
3726 def uses_virtio(self):
3727 return 'virtio' == self.device_model
3729 def format_dom(self):
3730 dev = super(LibvirtConfigGuestRng, self).format_dom()
3731 dev.set('model', self.device_model)
3733 backend = etree.Element("backend")
3734 backend.set("model", self.model)
3735 backend.text = self.backend
3737 if self.rate_period and self.rate_bytes:
3738 rate = etree.Element("rate")
3739 rate.set("period", str(self.rate_period))
3740 rate.set("bytes", str(self.rate_bytes))
3741 dev.append(rate)
3743 dev.append(backend)
3745 if self.driver_iommu:
3746 dev.append(etree.Element('driver', iommu="on"))
3748 return dev
3751class LibvirtConfigGuestMetaNovaInstance(LibvirtConfigObject):
3753 def __init__(self):
3754 super(LibvirtConfigGuestMetaNovaInstance,
3755 self).__init__(root_name="instance",
3756 ns_prefix="nova",
3757 ns_uri=NOVA_NS)
3759 self.package = None
3760 self.flavor = None
3761 self.name = None
3762 self.creationTime = None
3763 self.owner = None
3764 self.roottype = None
3765 self.rootid = None
3766 self.ports = None
3768 def format_dom(self):
3769 meta = super(LibvirtConfigGuestMetaNovaInstance, self).format_dom()
3771 pkg = self._new_node("package")
3772 pkg.set("version", self.package)
3773 meta.append(pkg)
3774 if self.name is not None: 3774 ↛ 3776line 3774 didn't jump to line 3776 because the condition on line 3774 was always true
3775 meta.append(self._text_node("name", self.name))
3776 if self.creationTime is not None: 3776 ↛ 3780line 3776 didn't jump to line 3780 because the condition on line 3776 was always true
3777 timestr = time.strftime("%Y-%m-%d %H:%M:%S",
3778 time.gmtime(self.creationTime))
3779 meta.append(self._text_node("creationTime", timestr))
3780 if self.flavor is not None: 3780 ↛ 3782line 3780 didn't jump to line 3782 because the condition on line 3780 was always true
3781 meta.append(self.flavor.format_dom())
3782 if self.owner is not None: 3782 ↛ 3785line 3782 didn't jump to line 3785 because the condition on line 3782 was always true
3783 meta.append(self.owner.format_dom())
3785 if self.roottype is not None and self.rootid is not None: 3785 ↛ 3790line 3785 didn't jump to line 3790 because the condition on line 3785 was always true
3786 root = self._new_node("root")
3787 root.set("type", self.roottype)
3788 root.set("uuid", str(self.rootid))
3789 meta.append(root)
3790 if self.ports is not None: 3790 ↛ 3793line 3790 didn't jump to line 3793 because the condition on line 3790 was always true
3791 meta.append(self.ports.format_dom())
3793 return meta
3796class LibvirtConfigGuestMetaNovaFlavor(LibvirtConfigObject):
3798 def __init__(self):
3799 super(LibvirtConfigGuestMetaNovaFlavor,
3800 self).__init__(root_name="flavor",
3801 ns_prefix="nova",
3802 ns_uri=NOVA_NS)
3804 self.name = None
3805 self.memory = None
3806 self.disk = None
3807 self.swap = None
3808 self.ephemeral = None
3809 self.vcpus = None
3811 def format_dom(self):
3812 meta = super(LibvirtConfigGuestMetaNovaFlavor, self).format_dom()
3813 meta.set("name", self.name)
3814 if self.memory is not None: 3814 ↛ 3816line 3814 didn't jump to line 3816 because the condition on line 3814 was always true
3815 meta.append(self._text_node("memory", str(self.memory)))
3816 if self.disk is not None: 3816 ↛ 3818line 3816 didn't jump to line 3818 because the condition on line 3816 was always true
3817 meta.append(self._text_node("disk", str(self.disk)))
3818 if self.swap is not None: 3818 ↛ 3820line 3818 didn't jump to line 3820 because the condition on line 3818 was always true
3819 meta.append(self._text_node("swap", str(self.swap)))
3820 if self.ephemeral is not None: 3820 ↛ 3822line 3820 didn't jump to line 3822 because the condition on line 3820 was always true
3821 meta.append(self._text_node("ephemeral", str(self.ephemeral)))
3822 if self.vcpus is not None: 3822 ↛ 3824line 3822 didn't jump to line 3824 because the condition on line 3822 was always true
3823 meta.append(self._text_node("vcpus", str(self.vcpus)))
3824 return meta
3827class LibvirtConfigGuestMetaNovaOwner(LibvirtConfigObject):
3829 def __init__(self):
3830 super(LibvirtConfigGuestMetaNovaOwner,
3831 self).__init__(root_name="owner",
3832 ns_prefix="nova",
3833 ns_uri=NOVA_NS)
3835 self.userid = None
3836 self.username = None
3837 self.projectid = None
3838 self.projectname = None
3840 def format_dom(self):
3841 meta = super(LibvirtConfigGuestMetaNovaOwner, self).format_dom()
3842 if self.userid is not None and self.username is not None:
3843 user = self._text_node("user", self.username)
3844 user.set("uuid", self.userid)
3845 meta.append(user)
3846 if self.projectid is not None and self.projectname is not None:
3847 project = self._text_node("project", self.projectname)
3848 project.set("uuid", self.projectid)
3849 meta.append(project)
3850 return meta
3853class LibvirtConfigSecret(LibvirtConfigObject):
3855 def __init__(self):
3856 super(LibvirtConfigSecret,
3857 self).__init__(root_name="secret")
3858 self.ephemeral = False
3859 self.private = False
3860 self.description = None
3861 self.uuid = None
3862 self.usage_type = None
3863 self.usage_id = None
3865 def format_dom(self):
3866 root = super(LibvirtConfigSecret, self).format_dom()
3867 root.set("ephemeral", self.get_yes_no_str(self.ephemeral))
3868 root.set("private", self.get_yes_no_str(self.private))
3869 if self.description is not None:
3870 root.append(self._text_node("description", str(self.description)))
3871 if self.uuid is not None:
3872 root.append(self._text_node("uuid", str(self.uuid)))
3873 usage = self._new_node("usage")
3874 usage.set("type", self.usage_type)
3875 if self.usage_type in ('ceph', 'vtpm'):
3876 usage.append(self._text_node('name', str(self.usage_id)))
3877 elif self.usage_type == 'iscsi':
3878 usage.append(self._text_node('target', str(self.usage_id)))
3879 elif self.usage_type == 'volume': 3879 ↛ 3881line 3879 didn't jump to line 3881 because the condition on line 3879 was always true
3880 usage.append(self._text_node('volume', str(self.usage_id)))
3881 root.append(usage)
3882 return root
3885class LibvirtConfigGuestVPMEM(LibvirtConfigGuestDevice):
3886 def __init__(self, **kwargs):
3887 super(LibvirtConfigGuestVPMEM, self).__init__(
3888 root_name="memory", **kwargs)
3890 self.model = "nvdimm"
3891 self.access = "shared"
3892 self.source_path = ""
3893 self.align_size = 0
3894 self.pmem = True
3896 self.target_size = 0
3897 self.target_node = 0
3898 self.label_size = 2 * units.Ki
3900 def format_dom(self):
3901 memory = super(LibvirtConfigGuestVPMEM, self).format_dom()
3903 memory.set("model", self.model)
3904 memory.set("access", self.access)
3906 source = etree.Element("source")
3907 source.append(self._text_node("path", self.source_path))
3908 source.append(self._text_node("alignsize", self.align_size))
3909 if self.pmem is True: 3909 ↛ 3912line 3909 didn't jump to line 3912 because the condition on line 3909 was always true
3910 source.append(etree.Element("pmem"))
3912 target = etree.Element("target")
3913 target.append(self._text_node("size", self.target_size))
3914 target.append(self._text_node("node", self.target_node))
3915 label = etree.Element("label")
3916 label.append(self._text_node("size", self.label_size))
3917 target.append(label)
3919 memory.append(source)
3920 memory.append(target)
3922 return memory
3924 def parse_dom(self, xmldoc):
3925 super(LibvirtConfigGuestVPMEM, self).parse_dom(xmldoc)
3926 self.model = xmldoc.get("model")
3927 self.access = xmldoc.get("access")
3929 for c in list(xmldoc):
3930 if c.tag == "source":
3931 for sub in list(c):
3932 if sub.tag == "path":
3933 self.source_path = sub.text
3934 if sub.tag == "alignsize":
3935 self.align_size = sub.text
3936 elif c.tag == "target":
3937 for sub in list(c):
3938 if sub.tag == "size":
3939 self.target_size = sub.text
3942class LibvirtConfigGuestIOMMU(LibvirtConfigGuestDevice):
3943 """https://libvirt.org/formatdomain.html#iommu-devices"""
3945 def __init__(self, **kwargs):
3946 super().__init__(root_name="iommu", **kwargs)
3948 self.model: str = fields.VIOMMUModel.AUTO
3949 self.interrupt_remapping: bool = False
3950 self.caching_mode: bool = False
3951 self.eim: bool = False
3952 self.iotlb: bool = False
3954 def format_dom(self):
3955 iommu = super().format_dom()
3956 iommu.set("model", self.model)
3958 driver = etree.Element("driver")
3959 driver.set("intremap", self.get_on_off_str(self.interrupt_remapping))
3960 driver.set("caching_mode", self.get_on_off_str(self.caching_mode))
3962 # Set aw_bits to None when the Libvirt version not satisfy
3963 # MIN_LIBVIRT_VIOMMU_AW_BITS in driver. When it's None, means it's not
3964 # supported to have aw_bits.
3965 if hasattr(self, "aw_bits"): 3965 ↛ 3967line 3965 didn't jump to line 3967 because the condition on line 3965 was always true
3966 driver.set("aw_bits", str(self.aw_bits))
3967 driver.set("eim", self.get_on_off_str(self.eim))
3968 driver.set("iotlb", self.get_on_off_str(self.iotlb))
3969 iommu.append(driver)
3971 return iommu
3973 def parse_dom(self, xmldoc):
3974 super().parse_dom(xmldoc)
3975 self.model = xmldoc.get("model")
3977 driver = xmldoc.find("./driver")
3978 if driver:
3979 self.interrupt_remapping = self.parse_on_off_str(
3980 driver.get("intremap"))
3981 self.caching_mode = self.parse_on_off_str(
3982 driver.get("caching_mode"))
3983 if driver.get("aw_bits") is not None:
3984 self.aw_bits = int(driver.get("aw_bits"))
3985 self.iotlb = self.parse_on_off_str(driver.get("iotlb"))
3986 self.eim = self.parse_on_off_str(driver.get("eim"))
3989class LibvirtConfigGuestMetaNovaPorts(LibvirtConfigObject):
3991 def __init__(self, ports=None):
3992 super(LibvirtConfigGuestMetaNovaPorts, self).__init__(
3993 root_name="ports", ns_prefix="nova", ns_uri=NOVA_NS)
3995 self.ports = ports
3997 def format_dom(self):
3998 meta = self._new_node("ports")
3999 for port in self.ports or []:
4000 meta.append(port.format_dom())
4001 return meta
4004class LibvirtConfigGuestMetaNovaPort(LibvirtConfigObject):
4006 def __init__(self, uuid, ips=None):
4007 super(LibvirtConfigGuestMetaNovaPort, self).__init__(
4008 root_name="port", ns_prefix="nova", ns_uri=NOVA_NS)
4010 self.uuid = uuid
4011 self.ips = ips
4013 def format_dom(self):
4014 meta = self._new_node("port")
4015 meta.set("uuid", str(self.uuid))
4016 for ip in self.ips or []:
4017 meta.append(ip.format_dom())
4018 return meta
4021class LibvirtConfigGuestMetaNovaIp(LibvirtConfigObject):
4023 def __init__(self, ip_type, address, ip_version):
4024 super(LibvirtConfigGuestMetaNovaIp, self).__init__(
4025 root_name="ip", ns_prefix="nova", ns_uri=NOVA_NS)
4027 self.ip_type = ip_type
4028 self.address = address
4029 self.ip_version = ip_version
4031 def format_dom(self):
4032 meta = self._new_node("ip")
4033 meta.set("type", str(self.ip_type))
4034 meta.set("address", str(self.address))
4035 meta.set("ipVersion", str(self.ip_version))
4036 return meta