Move to a more canonicalized output from qemu-img info.

Move to a form that is all lower cased, dashes->underscores, underscores
instead of spaces which allows for better integration with python. Also
make the parser more robust to failures when encountering new fields such
as snapshot lists. Provide a new qemu img info object that can be used
to do the parsing and access the underlying attributes.

Change-Id: Ie098dbd9f06dd4ef966768e2caa128f1d09b019c
This commit is contained in:
Joshua Harlow
2012-09-17 14:53:12 -07:00
parent cd1ed94c87
commit 62d63b904e
2 changed files with 121 additions and 17 deletions

View File

@@ -21,7 +21,7 @@ from nova.virt import images
class ImageUtilsTestCase(test.TestCase):
def test_qemu_info(self):
def test_qemu_info_canon(self):
path = "disk.config"
example_output = """image: disk.config
file format: raw
@@ -35,14 +35,35 @@ blah BLAH: bb
'qemu-img', 'info', path).AndReturn((example_output, ''))
self.mox.ReplayAll()
image_info = images.qemu_img_info(path)
self.assertEquals('disk.config', image_info['image'])
self.assertEquals('raw', image_info['file format'])
self.assertEquals('64M (67108864 bytes)', image_info['virtual size'])
self.assertEquals('96K', image_info['disk size'])
self.assertEquals('bb', image_info['blah blah'])
self.assertEquals("65536", image_info['cluster_size'])
self.assertEquals('disk.config', image_info.image)
self.assertEquals('raw', image_info.file_format)
self.assertEquals(67108864, image_info.virtual_size)
self.assertEquals(98304, image_info.disk_size)
self.assertEquals(65536, image_info.cluster_size)
def test_qemu_info_snap(self):
def test_qemu_info_canon2(self):
path = "disk.config"
example_output = """image: disk.config
file format: QCOW2
virtual size: 67108844
cluster_size: 65536
disk size: 963434
backing file: /var/lib/nova/a328c7998805951a_2
"""
self.mox.StubOutWithMock(utils, 'execute')
utils.execute('env', 'LC_ALL=C', 'LANG=C',
'qemu-img', 'info', path).AndReturn((example_output, ''))
self.mox.ReplayAll()
image_info = images.qemu_img_info(path)
self.assertEquals('disk.config', image_info.image)
self.assertEquals('qcow2', image_info.file_format)
self.assertEquals(67108844, image_info.virtual_size)
self.assertEquals(963434, image_info.disk_size)
self.assertEquals(65536, image_info.cluster_size)
self.assertEquals('/var/lib/nova/a328c7998805951a_2',
image_info.backing_file)
def test_qemu_backing_file_actual(self):
path = "disk.config"
example_output = """image: disk.config
file format: raw
@@ -52,18 +73,63 @@ disk size: 96K
Snapshot list:
ID TAG VM SIZE DATE VM CLOCK
1 d9a9784a500742a7bb95627bb3aace38 0 2012-08-20 10:52:46 00:00:00.000
backing file: /var/lib/nova/a328c7998805951a_2 (actual path: /b/3a988059e51a_2)
"""
self.mox.StubOutWithMock(utils, 'execute')
utils.execute('env', 'LC_ALL=C', 'LANG=C',
'qemu-img', 'info', path).AndReturn((example_output, ''))
self.mox.ReplayAll()
image_info = images.qemu_img_info(path)
self.assertEquals('disk.config', image_info['image'])
self.assertEquals('raw', image_info['file format'])
self.assertEquals('64M (67108864 bytes)', image_info['virtual size'])
self.assertEquals('96K', image_info['disk size'])
self.assertEquals("65536", image_info['cluster_size'])
# This would be triggered if the split encountered this section
self.assertNotIn('snapshot list', image_info)
bad_cap = '1 d9a9784a500742a7bb95627bb3aace38 0 2012-08-20 10'
self.assertNotIn(bad_cap, image_info)
self.assertEquals('disk.config', image_info.image)
self.assertEquals('raw', image_info.file_format)
self.assertEquals(67108864, image_info.virtual_size)
self.assertEquals(98304, image_info.disk_size)
self.assertEquals(1, len(image_info.snapshots))
self.assertEquals('/b/3a988059e51a_2',
image_info.backing_file)
def test_qemu_info_convert(self):
path = "disk.config"
example_output = """image: disk.config
file format: raw
virtual size: 64M
disk size: 96K
Snapshot list:
ID TAG VM SIZE DATE VM CLOCK
1 d9a9784a500742a7bb95627bb3aace38 0 2012-08-20 10:52:46 00:00:00.000
3 d9a9784a500742a7bb95627bb3aace38 0 2012-08-20 10:52:46 00:00:00.000
4 d9a9784a500742a7bb95627bb3aace38 0 2012-08-20 10:52:46 00:00:00.000
junk stuff: bbb
"""
self.mox.StubOutWithMock(utils, 'execute')
utils.execute('env', 'LC_ALL=C', 'LANG=C',
'qemu-img', 'info', path).AndReturn((example_output, ''))
self.mox.ReplayAll()
image_info = images.qemu_img_info(path)
self.assertEquals('disk.config', image_info.image)
self.assertEquals('raw', image_info.file_format)
self.assertEquals(67108864, image_info.virtual_size)
self.assertEquals(98304, image_info.disk_size)
def test_qemu_info_snaps(self):
path = "disk.config"
example_output = """image: disk.config
file format: raw
virtual size: 64M (67108864 bytes)
disk size: 96K
Snapshot list:
ID TAG VM SIZE DATE VM CLOCK
1 d9a9784a500742a7bb95627bb3aace38 0 2012-08-20 10:52:46 00:00:00.000
3 d9a9784a500742a7bb95627bb3aace38 0 2012-08-20 10:52:46 00:00:00.000
4 d9a9784a500742a7bb95627bb3aace38 0 2012-08-20 10:52:46 00:00:00.000
"""
self.mox.StubOutWithMock(utils, 'execute')
utils.execute('env', 'LC_ALL=C', 'LANG=C',
'qemu-img', 'info', path).AndReturn((example_output, ''))
self.mox.ReplayAll()
image_info = images.qemu_img_info(path)
self.assertEquals('disk.config', image_info.image)
self.assertEquals('raw', image_info.file_format)
self.assertEquals(67108864, image_info.virtual_size)
self.assertEquals(98304, image_info.disk_size)
self.assertEquals(3, len(image_info.snapshots))

View File

@@ -63,6 +63,16 @@ FLAGS.register_opt(
cfg.BoolOpt('disable_process_locking', default=False,
help='Whether to disable inter-process locks'))
# Used for looking up extensions of text
# to their 'multiplied' byte amount
BYTE_MULTIPLIERS = {
'': 1,
't': 1024 ** 4,
'g': 1024 ** 3,
'm': 1024 ** 2,
'k': 1024,
}
def vpn_ping(address, port, timeout=0.05, session_id=None):
"""Sends a vpn negotiation packet and returns the server session.
@@ -574,6 +584,34 @@ def utf8(value):
return value
def to_bytes(text, default=0):
"""Try to turn a string into a number of bytes. Looks at the last
characters of the text to determine what conversion is needed to
turn the input text into a byte number.
Supports: B/b, K/k, M/m, G/g, T/t (or the same with b/B on the end)
"""
# Take off everything not number 'like' (which should leave
# only the byte 'identifier' left)
mult_key_org = text.lstrip('-1234567890')
mult_key = mult_key_org.lower()
mult_key_len = len(mult_key)
if mult_key.endswith("b"):
mult_key = mult_key[0:-1]
try:
multiplier = BYTE_MULTIPLIERS[mult_key]
if mult_key_len:
# Empty cases shouldn't cause text[0:-0]
text = text[0:-mult_key_len]
return int(text) * multiplier
except KeyError:
msg = _('Unknown byte multiplier: %s') % mult_key_org
raise TypeError(msg)
except ValueError:
return default
def delete_if_exists(pathname):
"""delete a file, but ignore file not found error"""