blob: 98d6cc48f3384834cc32556be910fed3ab295848 [file] [log] [blame]
Tomasz Wiszkowski68ce8232017-06-27 15:05:39 -07001"""libvirt interface.
2
3Primary purpose of this class is to aid communication between libvirt and other classes.
4libvirt's preferred method of delivery of larger object is, sadly, xml (rather than objects).
5"""
6
7# pylint: disable=no-self-use
8
9from xml.etree import ElementTree
Tomasz Wiszkowski68ce8232017-06-27 15:05:39 -070010import libvirt
Tomasz Wiszkowski7e96e9d2017-08-09 16:20:47 -070011import logging
Tomasz Wiszkowski68ce8232017-06-27 15:05:39 -070012
13class LibVirtClient(object):
14 """Client of the libvirt library.
15 """
16 def __init__(self):
17 # Open channel to QEmu instance running locally.
18 self.lvch = libvirt.open('qemu:///system')
19 if self.lvch is None:
20 raise Exception('Could not open libvirt channel. Did you install libvirt package?')
21
22 self.capabilities = None
Tomasz Wiszkowski7e96e9d2017-08-09 16:20:47 -070023 self._log = logging.getLogger()
Tomasz Wiszkowski68ce8232017-06-27 15:05:39 -070024
25 # Parse host capabilities. Confirm our CPU is capable of executing movbe instruction
26 # which allows further compatibility with atom cpus.
27 self.host_capabilities = ElementTree.fromstring(self.lvch.getCapabilities())
Tomasz Wiszkowski7e96e9d2017-08-09 16:20:47 -070028 self._log.info('Starting cuttlefish on %s', self.get_hostname())
29 self._log.info('Max number of virtual CPUs: %d', self.get_max_vcpus())
30 self._log.info('Supported virtualization type: %s', self.get_virtualization_type())
Tomasz Wiszkowski68ce8232017-06-27 15:05:39 -070031
32
33 def get_hostname(self):
34 """Return name of the host that will run guest images.
35
36 Returns:
37 hostname as string.
38 """
39 return self.lvch.getHostname()
40
41
42 def get_max_vcpus(self):
43 """Query max number of VCPUs that can be used by virtual instance.
44
45 Returns:
46 number of VCPUs that can be used by virtual instance.
47 """
48 return self.lvch.getMaxVcpus(None)
49
50
51 def get_virtualization_type(self):
52 """Query virtualization type supported by host.
53
54 Returns:
55 string describing supported virtualization type.
56 """
57 return self.lvch.getType()
58
59
60 def get_instance(self, name):
61 """Get libvirt instance matching supplied name.
62
63 Args:
64 name Name of the virtual instance.
65 Returns:
66 libvirt instance or None, if no instance by that name was found.
67 """
68 return self.lvch.lookupByName(name)
69
70
71 def create_instance(self, description):
72 """Create new instance based on the XML description.
73
74 Args:
75 description XML string describing instance.
76 Returns:
77 libvirt domain representing started domain. Domain will be automatically
78 destroyed when this handle is orphaned.
79 """
80 return self.lvch.createXML(description,
81 libvirt.VIR_DOMAIN_START_AUTODESTROY)
82
83
84 def get_cpu_features(self):
85 """Get host capabilities from libvirt.
86
87 Returns:
88 set of CPU features reported by the host.
89 """
90 caps = self.capabilities or set()
91 try:
92 if self.capabilities is None:
93 features = self.host_capabilities.findall('./host/cpu/feature')
94 if features is None:
Tomasz Wiszkowski7e96e9d2017-08-09 16:20:47 -070095 self._log.warning('no \'host.cpu.feature\' nodes reported by libvirt.')
Tomasz Wiszkowski68ce8232017-06-27 15:05:39 -070096 return caps
97
98 for feature in features:
99 caps.add(feature.get('name'))
100 return caps
101
102 finally:
103 # Make sure to update self.capabilities with empty set if anything goes wrong.
104 self.capabilities = caps
105
106
Tomasz Wiszkowski7e96e9d2017-08-09 16:20:47 -0700107 def build_instance_name(self, instance_number):
Tomasz Wiszkowski68ce8232017-06-27 15:05:39 -0700108 """Convert instance number to an instance id (or domain).
109
110 Args:
111 instance_number Number of Cuttlefish instance.
112 Returns:
113 string representing instance (domain) name.
114 """
115 return 'android_cuttlefish_{}'.format(instance_number)