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:
@@ -21,7 +21,7 @@ from nova.virt import images
|
|||||||
|
|
||||||
|
|
||||||
class ImageUtilsTestCase(test.TestCase):
|
class ImageUtilsTestCase(test.TestCase):
|
||||||
def test_qemu_info(self):
|
def test_qemu_info_canon(self):
|
||||||
path = "disk.config"
|
path = "disk.config"
|
||||||
example_output = """image: disk.config
|
example_output = """image: disk.config
|
||||||
file format: raw
|
file format: raw
|
||||||
@@ -35,14 +35,35 @@ blah BLAH: bb
|
|||||||
'qemu-img', 'info', path).AndReturn((example_output, ''))
|
'qemu-img', 'info', path).AndReturn((example_output, ''))
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
image_info = images.qemu_img_info(path)
|
image_info = images.qemu_img_info(path)
|
||||||
self.assertEquals('disk.config', image_info['image'])
|
self.assertEquals('disk.config', image_info.image)
|
||||||
self.assertEquals('raw', image_info['file format'])
|
self.assertEquals('raw', image_info.file_format)
|
||||||
self.assertEquals('64M (67108864 bytes)', image_info['virtual size'])
|
self.assertEquals(67108864, image_info.virtual_size)
|
||||||
self.assertEquals('96K', image_info['disk size'])
|
self.assertEquals(98304, image_info.disk_size)
|
||||||
self.assertEquals('bb', image_info['blah blah'])
|
self.assertEquals(65536, image_info.cluster_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"
|
path = "disk.config"
|
||||||
example_output = """image: disk.config
|
example_output = """image: disk.config
|
||||||
file format: raw
|
file format: raw
|
||||||
@@ -52,18 +73,63 @@ disk size: 96K
|
|||||||
Snapshot list:
|
Snapshot list:
|
||||||
ID TAG VM SIZE DATE VM CLOCK
|
ID TAG VM SIZE DATE VM CLOCK
|
||||||
1 d9a9784a500742a7bb95627bb3aace38 0 2012-08-20 10:52:46 00:00:00.000
|
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')
|
self.mox.StubOutWithMock(utils, 'execute')
|
||||||
utils.execute('env', 'LC_ALL=C', 'LANG=C',
|
utils.execute('env', 'LC_ALL=C', 'LANG=C',
|
||||||
'qemu-img', 'info', path).AndReturn((example_output, ''))
|
'qemu-img', 'info', path).AndReturn((example_output, ''))
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
image_info = images.qemu_img_info(path)
|
image_info = images.qemu_img_info(path)
|
||||||
self.assertEquals('disk.config', image_info['image'])
|
self.assertEquals('disk.config', image_info.image)
|
||||||
self.assertEquals('raw', image_info['file format'])
|
self.assertEquals('raw', image_info.file_format)
|
||||||
self.assertEquals('64M (67108864 bytes)', image_info['virtual size'])
|
self.assertEquals(67108864, image_info.virtual_size)
|
||||||
self.assertEquals('96K', image_info['disk size'])
|
self.assertEquals(98304, image_info.disk_size)
|
||||||
self.assertEquals("65536", image_info['cluster_size'])
|
self.assertEquals(1, len(image_info.snapshots))
|
||||||
# This would be triggered if the split encountered this section
|
self.assertEquals('/b/3a988059e51a_2',
|
||||||
self.assertNotIn('snapshot list', image_info)
|
image_info.backing_file)
|
||||||
bad_cap = '1 d9a9784a500742a7bb95627bb3aace38 0 2012-08-20 10'
|
|
||||||
self.assertNotIn(bad_cap, image_info)
|
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))
|
||||||
|
|||||||
@@ -63,6 +63,16 @@ FLAGS.register_opt(
|
|||||||
cfg.BoolOpt('disable_process_locking', default=False,
|
cfg.BoolOpt('disable_process_locking', default=False,
|
||||||
help='Whether to disable inter-process locks'))
|
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):
|
def vpn_ping(address, port, timeout=0.05, session_id=None):
|
||||||
"""Sends a vpn negotiation packet and returns the server session.
|
"""Sends a vpn negotiation packet and returns the server session.
|
||||||
@@ -574,6 +584,34 @@ def utf8(value):
|
|||||||
return 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):
|
def delete_if_exists(pathname):
|
||||||
"""delete a file, but ignore file not found error"""
|
"""delete a file, but ignore file not found error"""
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user