libvirt: read rotated "console.log" files

A libvirt guest can output its console into a "console.log" file.
This change enhances the reading of this file in case there is log
rotation on this file. This will be the case in a following change
which make use of the "virtlogd" deamon of libvirt 1.3.0 and beyond.
If no log-rotation is used, the method will behave as before. This
change makes the later virtlogd change easier to review.

Change-Id: Ica2c91ad309df8e66433fe0c7fe2b799a23c0096
This commit is contained in:
Markus Zoeller 2016-10-11 18:05:51 +02:00
parent 54a400e996
commit e781123e50
2 changed files with 78 additions and 8 deletions

View File

@ -10798,7 +10798,8 @@ class LibvirtConnTestCase(test.NoDBTestCase):
self.assertEqual('', output)
def test_get_console_output_pty(self):
@mock.patch('os.path.exists', return_value=True)
def test_get_console_output_pty(self, mocked_path_exists):
fake_libvirt_utils.files['pty'] = '01234567890'
with utils.tempdir() as tmpdir:
@ -10872,6 +10873,66 @@ class LibvirtConnTestCase(test.NoDBTestCase):
self.assertRaises(exception.ConsoleNotAvailable,
drvr.get_console_output, self.context, instance)
@mock.patch('nova.virt.libvirt.host.Host.get_domain')
@mock.patch.object(libvirt_guest.Guest, "get_xml_desc")
def test_get_console_output_logrotate(self, mock_get_xml, get_domain):
fake_libvirt_utils.files['console.log'] = 'uvwxyz'
fake_libvirt_utils.files['console.log.0'] = 'klmnopqrst'
fake_libvirt_utils.files['console.log.1'] = 'abcdefghij'
def mock_path_exists(path):
return os.path.basename(path) in fake_libvirt_utils.files
xml = """
<domain type='kvm'>
<devices>
<disk type='file'>
<source file='filename'/>
</disk>
<console type='file'>
<source path='console.log'/>
<target port='0'/>
</console>
</devices>
</domain>
"""
mock_get_xml.return_value = xml
get_domain.return_value = mock.MagicMock()
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
instance = objects.Instance(**self.test_instance)
def _get_logd_output(bytes_to_read):
with utils.tempdir() as tmp_dir:
self.flags(instances_path=tmp_dir)
log_data = ""
try:
prev_max = libvirt_driver.MAX_CONSOLE_BYTES
libvirt_driver.MAX_CONSOLE_BYTES = bytes_to_read
with mock.patch('os.path.exists',
side_effect=mock_path_exists):
log_data = drvr.get_console_output(self.context,
instance)
finally:
libvirt_driver.MAX_CONSOLE_BYTES = prev_max
return log_data
# span across only 1 file (with remaining bytes)
self.assertEqual('wxyz', _get_logd_output(4))
# span across only 1 file (exact bytes)
self.assertEqual('uvwxyz', _get_logd_output(6))
# span across 2 files (with remaining bytes)
self.assertEqual('opqrstuvwxyz', _get_logd_output(12))
# span across all files (exact bytes)
self.assertEqual('abcdefghijklmnopqrstuvwxyz', _get_logd_output(26))
# span across all files with more bytes than available
self.assertEqual('abcdefghijklmnopqrstuvwxyz', _get_logd_output(30))
# files are not available
fake_libvirt_utils.files = {}
self.assertEqual('', _get_logd_output(30))
# reset the file for other tests
fake_libvirt_utils.files['console.log'] = '01234567890'
def test_get_host_ip_addr(self):
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
ip = drvr.get_host_ip_addr()

View File

@ -2646,12 +2646,21 @@ class LibvirtDriver(driver.ComputeDriver):
return fpath
def _get_console_output_file(self, instance, path):
def _get_console_output_file(self, instance, console_log):
bytes_to_read = MAX_CONSOLE_BYTES
log_data = "" # The last N read bytes
i = 0 # in case there is a log rotation (like "virtlogd")
path = console_log
while bytes_to_read > 0 and os.path.exists(path):
libvirt_utils.chown(path, os.getuid())
with libvirt_utils.file_open(path, 'rb') as fp:
log_data, remaining = utils.last_bytes(fp,
MAX_CONSOLE_BYTES)
read_log_data, remaining = utils.last_bytes(fp, bytes_to_read)
# We need the log file content in chronological order,
# that's why we *prepend* the log data.
log_data = read_log_data + log_data
bytes_to_read -= len(read_log_data)
path = console_log + "." + str(i)
i += 1
if remaining > 0:
LOG.info(_LI('Truncated console log returned, '
'%d bytes ignored'), remaining,