Skip to content

Commit cf69701

Browse files
authored
Merge pull request #310 from AdamWill/image-size-bytes
Allow image size specification using any SI or IEC unit
2 parents e02561d + b609f75 commit cf69701

12 files changed

+117
-32
lines changed

oz/Fedora.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -298,11 +298,11 @@ def _modify_iso(self):
298298
initrdline += " inst.nosave=output_ks"
299299
self._modify_isolinux(initrdline)
300300

301-
def generate_diskimage(self, size=10, force=False):
301+
def generate_diskimage(self, size=10*1024*1024*1024, force=False):
302302
"""
303303
Method to generate a diskimage. By default, a blank diskimage of
304-
10GB will be created; the caller can override this with the size
305-
parameter, specified in GB. If force is False (the default), then
304+
10 GiB will be created; the caller can override this with the size
305+
parameter, specified in bytes. If force is False (the default), then
306306
a diskimage will not be created if a cached JEOS is found. If
307307
force is True, a diskimage will be created regardless of whether a
308308
cached JEOS exists. See the oz-install man page for more

oz/Guest.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,7 @@ def _generate_xml(self, bootdev, installdev, kernel=None, initrd=None,
572572

573573
return xml
574574

575-
def _internal_generate_diskimage(self, size=10, force=False,
575+
def _internal_generate_diskimage(self, size=10*1024*1024*1024, force=False,
576576
create_partition=False,
577577
image_filename=None,
578578
backing_filename=None):
@@ -588,7 +588,7 @@ def _internal_generate_diskimage(self, size=10, force=False,
588588
# we'll copy the JEOS itself later on
589589
return
590590

591-
self.log.info("Generating %dGB diskimage for %s", size, self.tdl.name)
591+
self.log.info("Generating %s diskimage for %s", oz.ozutil.sizeof_fmt(int(size)), self.tdl.name)
592592

593593
diskimage = self.diskimage
594594
if image_filename:
@@ -629,17 +629,17 @@ def _internal_generate_diskimage(self, size=10, force=False,
629629
# allows creation without an explicit capacity element.
630630
qcow_size = oz.ozutil.check_qcow_size(backing_filename)
631631
if qcow_size:
632-
capacity = qcow_size / 1024 / 1024 / 1024
632+
capacity = qcow_size
633633
backing_format = 'qcow2'
634634
else:
635-
capacity = os.path.getsize(backing_filename) / 1024 / 1024 / 1024
635+
capacity = os.path.getsize(backing_filename)
636636
backing_format = 'raw'
637637
backing = oz.ozutil.lxml_subelement(vol, "backingStore")
638638
oz.ozutil.lxml_subelement(backing, "path", backing_filename)
639639
oz.ozutil.lxml_subelement(backing, "format", None,
640640
{"type": backing_format})
641641

642-
oz.ozutil.lxml_subelement(vol, "capacity", str(int(capacity)), {'unit': 'G'})
642+
oz.ozutil.lxml_subelement(vol, "capacity", str(int(capacity)), {'unit': 'B'})
643643
vol_xml = lxml.etree.tostring(vol, pretty_print=True, encoding="unicode")
644644

645645
# sigh. Yes, this is racy; if a pool is defined during this loop, we
@@ -719,11 +719,11 @@ def _vol_create_cb(args):
719719
g_handle.create_msdos_partition_table()
720720
g_handle.cleanup()
721721

722-
def generate_diskimage(self, size=10, force=False):
722+
def generate_diskimage(self, size=10*1024*1024*1024, force=False):
723723
"""
724724
Method to generate a diskimage. By default, a blank diskimage of
725-
10GB will be created; the caller can override this with the size
726-
parameter, specified in GB. If force is False (the default), then
725+
10 GiB will be created; the caller can override this with the size
726+
parameter, specified in bytes. If force is False (the default), then
727727
a diskimage will not be created if a cached JEOS is found. If
728728
force is True, a diskimage will be created regardless of whether a
729729
cached JEOS exists. See the oz-install man page for more

oz/TDL.py

+33-14
Original file line numberDiff line numberDiff line change
@@ -327,20 +327,39 @@ def _parse_disksize(self):
327327
# a sensible default
328328
return None
329329

330-
match = re.match(r'([0-9]*) *([GT]?)$', size)
331-
if not match or len(match.groups()) != 2:
332-
raise oz.OzException.OzException("Invalid disk size; it must be specified as a size in gigabytes, optionally suffixed with 'G' or 'T'")
333-
334-
number = match.group(1)
335-
suffix = match.group(2)
336-
337-
if not suffix or suffix == 'G':
338-
# for backwards compatibility, we assume G when there is no suffix
339-
size = number
340-
elif suffix == 'T':
341-
size = str(int(number) * 1024)
342-
343-
return size
330+
# drop spaces and downcase
331+
size = size.replace(" ", "").lower()
332+
# isolate digits
333+
number = ""
334+
suffix = ""
335+
for (idx, char) in enumerate(size):
336+
if char.isdigit():
337+
number += char
338+
else:
339+
suffix = size[idx:]
340+
break
341+
342+
if not suffix:
343+
# for backwards compatibility, we assume GiB when there is no suffix
344+
suffix = "gib"
345+
346+
# also for backwards compatibility with an earlier attempt to support
347+
# suffixes, treat "T" and "G" as "TiB" and "GiB"
348+
units = {"b": 1, "g": 2**30, "t": 2**40}
349+
tenscale = 3
350+
twoscale = 10
351+
for (i, pref) in enumerate(("k", "m", "g", "t", "p", "e", "z", "y"), start=1):
352+
# this is giving us {"gib": 2 ** 30, "gb": 10 ** 9}, etc
353+
units[pref + "b"] = (10 ** (i*tenscale))
354+
units[pref + "ib"] = (2 ** (i*twoscale))
355+
356+
factor = units.get(suffix)
357+
if not number or not factor:
358+
raise oz.OzException.OzException(
359+
"Invalid disk size; it must be specified as an integer size with an optional SI or IEC unit suffix, e.g. '10TB' or '16GiB'"
360+
)
361+
362+
return str(int(number) * factor)
344363

345364
def _parse_commands(self, xpath):
346365
"""

oz/Windows.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,12 @@ def _generate_new_iso(self):
7878
self.iso_contents],
7979
printfn=self.log.debug)
8080

81-
def generate_diskimage(self, size=10, force=False):
81+
def generate_diskimage(self, size=10*1024*1024*1024, force=False):
8282
"""
8383
Method to generate a diskimage. By default, a blank diskimage of
84-
10GB will be created; the caller can override this with the size
85-
parameter, specified in GB. If force is False (the default), then
86-
a diskimage will not be created if a cached JEOS is found. If
84+
10 GiB will be created; the caller can override this with the size
85+
parameter, specified in bytes. If force is False (the default),
86+
then a diskimage will not be created if a cached JEOS is found. If
8787
force is True, a diskimage will be created regardless of whether a
8888
cached JEOS exists. See the oz-install man page for more
8989
information about JEOS caching.

oz/ozutil.py

+17
Original file line numberDiff line numberDiff line change
@@ -1178,3 +1178,20 @@ def get_free_port():
11781178
sock.close()
11791179

11801180
return listen_port
1181+
1182+
1183+
def sizeof_fmt(num, suffix="B"):
1184+
"""
1185+
Give a convenient human-readable representation of a large size in
1186+
bytes. Initially by Fred Cirera:
1187+
https://web.archive.org/web/20111010015624/http://blogmag.net/blog/read/38/Print_human_readable_file_size
1188+
edited by multiple contributors at:
1189+
https://stackoverflow.com/questions/1094841
1190+
Per Richard Fontana this is too trivial to be copyrightable, so
1191+
there are no licensing concerns
1192+
"""
1193+
for unit in ("", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"):
1194+
if abs(num) < 1024.0:
1195+
return "%3.1f%s%s" % (num, unit, suffix)
1196+
num /= 1024.0
1197+
return "%.1f%s%s" % (num, 'Yi', suffix)

oz/tdl.rng

+1-1
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@
325325

326326
<define name='disk_size'>
327327
<data type="string">
328-
<param name="pattern">([0-9]*) *([GT]?)</param>
328+
<param name="pattern">([0-9]*) *([kKmMgGtTpPeEzZyY]?[iI]?[bB]?)</param>
329329
</data>
330330
</define>
331331

tests/guest/test_guest.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,8 @@ def test_geteltorito_bogus_bootp(tmpdir):
352352
def test_init_guest():
353353
guest = setup_guest(tdlxml2)
354354

355-
assert guest.disksize == 20
355+
# size without units is taken to be GiB
356+
assert guest.disksize == 20*(2**30)
356357
assert guest.image_name() == 'tester'
357358
assert guest.output_image_path() in (
358359
# user's image storage
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<template>
2+
<name>help</name>
3+
<os>
4+
<name>Fedora</name>
5+
<version>12</version>
6+
<arch>i386</arch>
7+
<install type='url'>
8+
<url>http://download.fedoraproject.org/pub/fedora/linux/releases/12/Fedora/x86_64/os/</url>
9+
</install>
10+
</os>
11+
<description>My Fedora 12 JEOS image</description>
12+
<disk>
13+
<size>2EiB</size>
14+
</disk>
15+
</template>
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<template>
2+
<name>help</name>
3+
<os>
4+
<name>Fedora</name>
5+
<version>12</version>
6+
<arch>i386</arch>
7+
<install type='url'>
8+
<url>http://download.fedoraproject.org/pub/fedora/linux/releases/12/Fedora/x86_64/os/</url>
9+
</install>
10+
</os>
11+
<description>My Fedora 12 JEOS image</description>
12+
<disk>
13+
<size>10ZB</size>
14+
</disk>
15+
</template>

tests/tdl/test-65-disk-size-byte.tdl

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<template>
2+
<name>help</name>
3+
<os>
4+
<name>Fedora</name>
5+
<version>12</version>
6+
<arch>i386</arch>
7+
<install type='url'>
8+
<url>http://download.fedoraproject.org/pub/fedora/linux/releases/12/Fedora/x86_64/os/</url>
9+
</install>
10+
</os>
11+
<description>My Fedora 12 JEOS image</description>
12+
<disk>
13+
<size>10000000 B</size>
14+
</disk>
15+
</template>

tests/tdl/test_tdl.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,11 @@
9292
"test-55-files-http-url.tdl": True,
9393
"test-56-invalid-disk-size.tdl": False,
9494
"test-57-invalid-disk-size.tdl": False,
95-
"test-58-disk-size-terabyte.tdl": True,
95+
"test-58-disk-size-tebibyte-compat.tdl": True,
9696
"test-59-command-sorting.tdl": True,
97+
"test-63-disk-size-exbibyte.tdl": True,
98+
"test-64-disk-size-zettabyte.tdl": True,
99+
"test-65-disk-size-byte.tdl": True,
97100
}
98101

99102
# Test that iterates over all .tdl files

0 commit comments

Comments
 (0)