summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Still <mikal@stillhq.com>2012-11-21 21:43:12 +1100
committerMichael Still <michael.still@canonical.com>2012-11-23 07:09:53 +1100
commitfc4f4bd09a0ef3a65514c5dc733c7b2fd6ac7ead (patch)
tree2bded36ce01d5b8a94724f46b113d5f9260e8c4c
parent2d6abe49c35ab5c6200164455631a259eefe7457 (diff)
downloadnova-fc4f4bd09a0ef3a65514c5dc733c7b2fd6ac7ead.tar.gz
nova-fc4f4bd09a0ef3a65514c5dc733c7b2fd6ac7ead.tar.xz
nova-fc4f4bd09a0ef3a65514c5dc733c7b2fd6ac7ead.zip
Truncate large console logs in libvirt.
Resolves bug 1081436 where they were returning a 5.5gb console log to the user. Change-Id: I0d98c83e801f8936d35789b5e8f8283f49483c4e
-rw-r--r--nova/tests/fake_libvirt_utils.py5
-rw-r--r--nova/tests/test_libvirt.py39
-rw-r--r--nova/tests/test_utils.py27
-rw-r--r--nova/tests/test_virt_drivers.py5
-rw-r--r--nova/utils.py21
-rw-r--r--nova/virt/libvirt/driver.py18
6 files changed, 98 insertions, 17 deletions
diff --git a/nova/tests/fake_libvirt_utils.py b/nova/tests/fake_libvirt_utils.py
index 020ff8192..0092e1161 100644
--- a/nova/tests/fake_libvirt_utils.py
+++ b/nova/tests/fake_libvirt_utils.py
@@ -86,7 +86,10 @@ def extract_snapshot(disk_path, source_fmt, snapshot_name, out_path, dest_fmt):
class File(object):
def __init__(self, path, mode=None):
- self.fp = StringIO.StringIO(files[path])
+ if path in files:
+ self.fp = StringIO.StringIO(files[path])
+ else:
+ self.fp = StringIO.StringIO(files[os.path.split(path)[-1]])
def __enter__(self):
return self.fp
diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py
index 070024fac..768406e9c 100644
--- a/nova/tests/test_libvirt.py
+++ b/nova/tests/test_libvirt.py
@@ -2304,6 +2304,7 @@ class LibvirtConnTestCase(test.TestCase):
CONF.base_dir_name))
def test_get_console_output_file(self):
+ fake_libvirt_utils.files['console.log'] = '01234567890'
with utils.tempdir() as tmpdir:
self.flags(instances_path=tmpdir)
@@ -2313,11 +2314,7 @@ class LibvirtConnTestCase(test.TestCase):
instance = db.instance_create(self.context, instance_ref)
console_dir = (os.path.join(tmpdir, instance['name']))
- os.mkdir(console_dir)
console_log = '%s/console.log' % (console_dir)
- f = open(console_log, "w")
- f.write("foo")
- f.close()
fake_dom_xml = """
<domain type='kvm'>
<devices>
@@ -2340,10 +2337,18 @@ class LibvirtConnTestCase(test.TestCase):
libvirt_driver.libvirt_utils = fake_libvirt_utils
conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
- output = conn.get_console_output(instance)
- self.assertEquals("foo", output)
+
+ try:
+ prev_max = libvirt_driver.MAX_CONSOLE_BYTES
+ libvirt_driver.MAX_CONSOLE_BYTES = 5
+ output = conn.get_console_output(instance)
+ finally:
+ libvirt_driver.MAX_CONSOLE_BYTES = prev_max
+
+ self.assertEquals('67890', output)
def test_get_console_output_pty(self):
+ fake_libvirt_utils.files['pty'] = '01234567890'
with utils.tempdir() as tmpdir:
self.flags(instances_path=tmpdir)
@@ -2353,11 +2358,7 @@ class LibvirtConnTestCase(test.TestCase):
instance = db.instance_create(self.context, instance_ref)
console_dir = (os.path.join(tmpdir, instance['name']))
- os.mkdir(console_dir)
pty_file = '%s/fake_pty' % (console_dir)
- f = open(pty_file, "w")
- f.write("foo")
- f.close()
fake_dom_xml = """
<domain type='kvm'>
<devices>
@@ -2376,17 +2377,27 @@ class LibvirtConnTestCase(test.TestCase):
return FakeVirtDomain(fake_dom_xml)
def _fake_flush(self, fake_pty):
- with open(fake_pty, 'r') as fp:
- return fp.read()
+ return 'foo'
+
+ def _fake_append_to_file(self, data, fpath):
+ return 'pty'
self.create_fake_libvirt_mock()
libvirt_driver.LibvirtDriver._conn.lookupByName = fake_lookup
libvirt_driver.LibvirtDriver._flush_libvirt_console = _fake_flush
+ libvirt_driver.LibvirtDriver._append_to_file = _fake_append_to_file
libvirt_driver.libvirt_utils = fake_libvirt_utils
conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
- output = conn.get_console_output(instance)
- self.assertEquals("foo", output)
+
+ try:
+ prev_max = libvirt_driver.MAX_CONSOLE_BYTES
+ libvirt_driver.MAX_CONSOLE_BYTES = 5
+ output = conn.get_console_output(instance)
+ finally:
+ libvirt_driver.MAX_CONSOLE_BYTES = prev_max
+
+ self.assertEquals('67890', output)
def test_get_host_ip_addr(self):
conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
diff --git a/nova/tests/test_utils.py b/nova/tests/test_utils.py
index b0f3e9fac..8bf6df8b5 100644
--- a/nova/tests/test_utils.py
+++ b/nova/tests/test_utils.py
@@ -774,3 +774,30 @@ class MkfsTestCase(test.TestCase):
utils.mkfs('ext4', '/my/block/dev', 'ext4-vol')
utils.mkfs('msdos', '/my/msdos/block/dev', 'msdos-vol')
utils.mkfs('swap', '/my/swap/block/dev', 'swap-vol')
+
+
+class LastBytesTestCase(test.TestCase):
+ """Test the last_bytes() utility method."""
+
+ def setUp(self):
+ super(LastBytesTestCase, self).setUp()
+ self.f = StringIO.StringIO('1234567890')
+
+ def test_truncated(self):
+ self.f.seek(0, os.SEEK_SET)
+ out, remaining = utils.last_bytes(self.f, 5)
+ self.assertEqual(out, '67890')
+ self.assertTrue(remaining > 0)
+
+ def test_read_all(self):
+ self.f.seek(0, os.SEEK_SET)
+ out, remaining = utils.last_bytes(self.f, 1000)
+ self.assertEqual(out, '1234567890')
+ self.assertFalse(remaining > 0)
+
+ def test_seek_too_far_real_file(self):
+ # StringIO doesn't raise IOError if you see past the start of the file.
+ flo = tempfile.TemporaryFile()
+ content = '1234567890'
+ flo.write(content)
+ self.assertEqual((content, 0), utils.last_bytes(flo, 1000))
diff --git a/nova/tests/test_virt_drivers.py b/nova/tests/test_virt_drivers.py
index 9d48cdf06..e09f96721 100644
--- a/nova/tests/test_virt_drivers.py
+++ b/nova/tests/test_virt_drivers.py
@@ -14,8 +14,11 @@
# License for the specific language governing permissions and limitations
# under the License.
+import __builtin__
import base64
+import mox
import netaddr
+import StringIO
import sys
import traceback
@@ -25,6 +28,7 @@ from nova import exception
from nova.openstack.common import importutils
from nova.openstack.common import log as logging
from nova import test
+from nova.tests import fake_libvirt_utils
from nova.tests.image import fake as fake_image
from nova.tests import utils as test_utils
from nova.virt import fake
@@ -428,6 +432,7 @@ class _VirtDriverTestCase(_FakeDriverBackendTestCase):
@catch_notimplementederror
def test_get_console_output(self):
+ fake_libvirt_utils.files['dummy.log'] = ''
instance_ref, network_info = self._get_running_instance()
console_output = self.connection.get_console_output(instance_ref)
self.assertTrue(isinstance(console_output, basestring))
diff --git a/nova/utils.py b/nova/utils.py
index 464629d95..c94cd2c3e 100644
--- a/nova/utils.py
+++ b/nova/utils.py
@@ -1180,3 +1180,24 @@ def mkfs(fs, path, label=None):
args.extend([label_opt, label])
args.append(path)
execute(*args)
+
+
+def last_bytes(file_like_object, num):
+ """Return num bytes from the end of the file, and remaining byte count.
+
+ :param file_like_object: The file to read
+ :param num: The number of bytes to return
+
+ :returns (data, remaining)
+ """
+
+ try:
+ file_like_object.seek(-num, os.SEEK_END)
+ except IOError, e:
+ if e.errno == 22:
+ file_like_object.seek(0, os.SEEK_SET)
+ else:
+ raise
+
+ remaining = file_like_object.tell()
+ return (file_like_object.read(), remaining)
diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py
index 14e8a75d2..69e4921bc 100644
--- a/nova/virt/libvirt/driver.py
+++ b/nova/virt/libvirt/driver.py
@@ -195,6 +195,8 @@ DEFAULT_FIREWALL_DRIVER = "%s.%s" % (
libvirt_firewall.__name__,
libvirt_firewall.IptablesFirewallDriver.__name__)
+MAX_CONSOLE_BYTES = 102400
+
def patch_tpool_proxy():
"""eventlet.tpool.Proxy doesn't work with old-style class in __str__()
@@ -1145,7 +1147,14 @@ class LibvirtDriver(driver.ComputeDriver):
if not path:
continue
libvirt_utils.chown(path, os.getuid())
- return libvirt_utils.load_file(path)
+
+ with libvirt_utils.file_open(path, 'rb') as fp:
+ log_data, remaining = utils.last_bytes(fp,
+ MAX_CONSOLE_BYTES)
+ if remaining > 0:
+ LOG.info(_('Truncated console log returned, %d bytes '
+ 'ignored'), remaining, instance=instance)
+ return log_data
# Try 'pty' types
if console_types.get('pty'):
@@ -1166,7 +1175,12 @@ class LibvirtDriver(driver.ComputeDriver):
console_log = self._get_console_log_path(instance['name'])
fpath = self._append_to_file(data, console_log)
- return libvirt_utils.load_file(fpath)
+ with libvirt_utils.file_open(fpath, 'rb') as fp:
+ log_data, remaining = utils.last_bytes(fp, MAX_CONSOLE_BYTES)
+ if remaining > 0:
+ LOG.info(_('Truncated console log returned, %d bytes ignored'),
+ remaining, instance=instance)
+ return log_data
@staticmethod
def get_host_ip_addr():