addr = migration.serial_listen_addr(data)
self.assertIsNone(addr)
+ def test_serial_listen_ports(self):
+ data = objects.LibvirtLiveMigrateData(
+ serial_listen_ports=[1, 2, 3])
+ ports = migration.serial_listen_ports(data)
+ self.assertEqual([1, 2, 3], ports)
+
+ def test_serial_listen_ports_emtpy(self):
+ data = objects.LibvirtLiveMigrateData()
+ ports = migration.serial_listen_ports(data)
+ self.assertEqual([], ports)
+
@mock.patch('lxml.etree.tostring')
@mock.patch.object(migration, '_update_perf_events_xml')
@mock.patch.object(migration, '_update_graphics_xml')
def test_update_serial_xml_serial(self):
data = objects.LibvirtLiveMigrateData(
- serial_listen_addr='127.0.0.100')
+ serial_listen_addr='127.0.0.100',
+ serial_listen_ports=[2001])
xml = """<domain>
<devices>
<serial type="tcp">
- <source host="127.0.0.1"/>
+ <source host="127.0.0.1" service="2000"/>
+ <target type="serial" port="0"/>
</serial>
</devices>
</domain>"""
doc = etree.fromstring(xml)
res = etree.tostring(migration._update_serial_xml(doc, data))
- new_xml = xml.replace("127.0.0.1", "127.0.0.100")
+ new_xml = xml.replace("127.0.0.1", "127.0.0.100").replace(
+ "2000", "2001")
self.assertThat(res, matchers.XMLMatches(new_xml))
def test_update_serial_xml_console(self):
data = objects.LibvirtLiveMigrateData(
- serial_listen_addr='127.0.0.100')
+ serial_listen_addr='127.0.0.100',
+ serial_listen_ports=[299, 300])
xml = """<domain>
<devices>
<console type="tcp">
- <source host="127.0.0.1"/>
+ <source host="127.0.0.1" service="2001"/>
+ <target type="serial" port="0"/>
+ </console>
+ <console type="tcp">
+ <source host="127.0.0.1" service="2002"/>
+ <target type="serial" port="1"/>
+ </console>
+ </devices>
+</domain>"""
+ doc = etree.fromstring(xml)
+ res = etree.tostring(migration._update_serial_xml(doc, data))
+ new_xml = xml.replace("127.0.0.1", "127.0.0.100").replace(
+ "2001", "299").replace("2002", "300")
+
+ self.assertThat(res, matchers.XMLMatches(new_xml))
+
+ def test_update_serial_xml_without_ports(self):
+ # This test is for backwards compatibility when we don't
+ # get the serial ports from the target node.
+ data = objects.LibvirtLiveMigrateData(
+ serial_listen_addr='127.0.0.100',
+ serial_listen_ports=[])
+ xml = """<domain>
+ <devices>
+ <console type="tcp">
+ <source host="127.0.0.1" service="2001"/>
+ <target type="serial" port="0"/>
+ </console>
+ <console type="tcp">
+ <source host="127.0.0.1" service="2002"/>
+ <target type="serial" port="1"/>
</console>
</devices>
</domain>"""
return listen_addr
+# TODO(sahid): remove me for Q*
+def serial_listen_ports(migrate_data):
+ """Returns ports serial from a LibvirtLiveMigrateData"""
+ ports = []
+ if migrate_data.obj_attr_is_set('serial_listen_ports'):
+ ports = migrate_data.serial_listen_ports
+ return ports
+
+
def get_updated_guest_xml(guest, migrate_data, get_volume_config):
xml_doc = etree.fromstring(guest.get_xml_desc(dump_migratable=True))
xml_doc = _update_graphics_xml(xml_doc, migrate_data)
def _update_serial_xml(xml_doc, migrate_data):
listen_addr = serial_listen_addr(migrate_data)
- for dev in xml_doc.findall("./devices/serial[@type='tcp']/source"):
- if dev.get('host') is not None:
- dev.set('host', listen_addr)
- for dev in xml_doc.findall("./devices/console[@type='tcp']/source"):
- if dev.get('host') is not None:
- dev.set('host', listen_addr)
+ listen_ports = serial_listen_ports(migrate_data)
+
+ def set_listen_addr_and_port(source, listen_addr, serial_listen_ports):
+ # The XML nodes can be empty, which would make checks like
+ # "if source.get('host'):" different to an explicit check for
+ # None. That's why we have to check for None in this method.
+ if source.get('host') is not None:
+ source.set('host', listen_addr)
+ device = source.getparent()
+ target = device.find("target")
+ if target is not None and source.get('service') is not None:
+ port_index = int(target.get('port'))
+ # NOTE (markus_z): Previous releases might not give us the
+ # ports yet, that's why we have this check here.
+ if len(serial_listen_ports) > port_index:
+ source.set('service', str(serial_listen_ports[port_index]))
+
+ # This updates all "LibvirtConfigGuestSerial" devices
+ for source in xml_doc.findall("./devices/serial[@type='tcp']/source"):
+ set_listen_addr_and_port(source, listen_addr, listen_ports)
+
+ # This updates all "LibvirtConfigGuestConsole" devices
+ for source in xml_doc.findall("./devices/console[@type='tcp']/source"):
+ set_listen_addr_and_port(source, listen_addr, listen_ports)
+
return xml_doc