diff options
-rw-r--r-- | src/ogRest.py | 8 | ||||
-rw-r--r-- | src/utils/legacy.py | 118 |
2 files changed, 108 insertions, 18 deletions
diff --git a/src/ogRest.py b/src/ogRest.py index 8e54612..02d3d0c 100644 --- a/src/ogRest.py +++ b/src/ogRest.py @@ -205,7 +205,7 @@ class ogThread(): return kibi = 1024 - datasize = int(image_info['datasize']) * kibi + datasize = int(image_info.datasize) * kibi json_body = jsonBody() json_body.add_element('disk', request.getDisk()) @@ -215,9 +215,9 @@ class ogThread(): json_body.add_element('name', request.getName()) json_body.add_element('repository', request.getRepo()) json_body.add_element('software', software) - json_body.add_element('clonator', image_info['clonator']) - json_body.add_element('compressor', image_info['compressor']) - json_body.add_element('filesystem', image_info['filesystem']) + json_body.add_element('clonator', image_info.clonator) + json_body.add_element('compressor', image_info.compressor) + json_body.add_element('filesystem', image_info.filesystem) json_body.add_element('datasize', datasize) response = restResponse(ogResponses.OK, json_body) diff --git a/src/utils/legacy.py b/src/utils/legacy.py index 509b9b0..51d98f3 100644 --- a/src/utils/legacy.py +++ b/src/utils/legacy.py @@ -5,28 +5,118 @@ import subprocess import shlex import shutil -from subprocess import PIPE, DEVNULL, CalledProcessError +from subprocess import PIPE, DEVNULL, STDOUT, CalledProcessError from src.utils.fs import umount -def ogGetImageInfo(path): +class ImageInfo: """ - Bash function 'ogGetImageInfo' wrapper (client/engine/Image.lib) + Class that stores the OpenGnsys partition image information. """ - proc = subprocess.run(f'ogGetImageInfo {path}', - stdout=PIPE, shell=True, - encoding='utf-8') + def __init__(self, filesystem=None, datasize=None): + self.filesystem = filesystem + self.datasize = datasize + self.clonator = 'PARTCLONE' + self.compressor = 'LZOP' - if proc.stdout.count(':') != 3: - return '' - image_info = {} - (image_info['clonator'], - image_info['compressor'], - image_info['filesystem'], - image_info['datasize']) = proc.stdout.rstrip().split(':', 4) - image_info['clientname'] = os.getenv('HOSTNAME') +def human_to_kb(size, unit): + """ + Returns the KB conversion of a human readable string size and unit. + """ + size = float(size.replace(',', '.')) + if unit == 'GB': + return size * 1000000 + if unit == 'MB': + return size * 1000 + return 0 + + +def fill_imageinfo(line, image_info): + """ + Updates ImageInfo object with information processed from + a single partclone.info output line. + + ImageInfo object may not be updated if the line is invalid or does not + contain filesystem or device size information. + """ + if 'File system' in line: + filesystem = line.rstrip().split(' ')[-1] + image_info.filesystem = filesystem + elif 'Device size' in line: + l = [word for word in line.rstrip().split(' ') if word][2:4] + device_size = human_to_kb(*l) + image_info.datasize = device_size + + +def process_output_partcloneinfo(output): + """ + Parses image information from partclone.info output. + + Returns an ImageInfo object. + """ + image_info = ImageInfo() + for n, line in enumerate(output.split('\n')): + if n < 2: + continue + if image_info.datasize and image_info.filesystem: + break + fill_imageinfo(line, image_info) + + if not image_info.datasize: + raise ValueError("Missing device size from partclone.info output") + elif not image_info.filesystem: + raise ValueError("Missing filesystem from partclone.info output") + + return image_info + + +def process_image_partcloneinfo(filename): + """ + Decompress using lzop and executes partclone.info to + fetch a partition image's information. + + Returns partclone.info stdout and stderr. + """ + cmd1 = f'{shutil.which("lzop")} -dc {filename}' + cmd2 = f'{shutil.which("partclone.info")} -s -' + args1 = shlex.split(cmd1) + args2 = shlex.split(cmd2) + p1 = subprocess.Popen(args1, stdout=PIPE, stderr=DEVNULL) + p2 = subprocess.Popen(args2, stdout=PIPE, stdin=p1.stdout, + stderr=STDOUT, encoding='utf-8') + p1.stdout.close() + p2_out, p2_err = p2.communicate() + + if p2.returncode != 0: + raise ValueError('Unable to process image {filename}') + + return p2_out + + +def ogGetImageInfo(filename): + """ + Obtain filesystem and device size information of an OpenGnsys partition + image. + + This method supports compressed images with lzop that have been created + with partclone. + + Returns an ImageInfo object. + + >>> image_info = ogGetImageInfo('/opt/opengnsys/images/foobar.img') + >>> image_info.filesystem + >>> 'NTFS' + >>> image_info.datasize + >>> 140000000 + >>> image_info.compressor + >>> 'LZOP' + >>> image_info.clonator + >>> 'PARTCLONE' + """ + out = process_image_partcloneinfo(filename) + image_info = process_output_partcloneinfo(out) return image_info |