legacy: rewrite ogGetImageInfo

Rewrites this legacy script behavior using native Python code, using
subprocess module when executing programs like partclone.info or lzop

ogGetImageInfo is a bash script that retrieves information regarding an
OpenGnsys partition image, specifically:

- clonator
- compressor
- filesystem
- datasize (size of the partition image)

This rewrite only supports partclone and lzop compressed images. This is
standard behavior, we have no reports of other programs or compression
algorithms in use.

Keep this legacy function with hungarian notation to emphasize this is
still a legacy component that may be replaced in the future.
more_events
Jose M. Guisado 2023-03-01 17:59:04 +01:00
parent a1edbe904b
commit c9a3a763dd
2 changed files with 108 additions and 18 deletions

View File

@ -205,7 +205,7 @@ class ogThread():
return return
kibi = 1024 kibi = 1024
datasize = int(image_info['datasize']) * kibi datasize = int(image_info.datasize) * kibi
json_body = jsonBody() json_body = jsonBody()
json_body.add_element('disk', request.getDisk()) json_body.add_element('disk', request.getDisk())
@ -215,9 +215,9 @@ class ogThread():
json_body.add_element('name', request.getName()) json_body.add_element('name', request.getName())
json_body.add_element('repository', request.getRepo()) json_body.add_element('repository', request.getRepo())
json_body.add_element('software', software) json_body.add_element('software', software)
json_body.add_element('clonator', image_info['clonator']) json_body.add_element('clonator', image_info.clonator)
json_body.add_element('compressor', image_info['compressor']) json_body.add_element('compressor', image_info.compressor)
json_body.add_element('filesystem', image_info['filesystem']) json_body.add_element('filesystem', image_info.filesystem)
json_body.add_element('datasize', datasize) json_body.add_element('datasize', datasize)
response = restResponse(ogResponses.OK, json_body) response = restResponse(ogResponses.OK, json_body)

View File

@ -5,28 +5,118 @@ import subprocess
import shlex import shlex
import shutil import shutil
from subprocess import PIPE, DEVNULL, CalledProcessError from subprocess import PIPE, DEVNULL, STDOUT, CalledProcessError
from src.utils.fs import umount 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}', def __init__(self, filesystem=None, datasize=None):
stdout=PIPE, shell=True, self.filesystem = filesystem
encoding='utf-8') self.datasize = datasize
self.clonator = 'PARTCLONE'
self.compressor = 'LZOP'
if proc.stdout.count(':') != 3:
return ''
image_info = {} def human_to_kb(size, unit):
(image_info['clonator'], """
image_info['compressor'], Returns the KB conversion of a human readable string size and unit.
image_info['filesystem'], """
image_info['datasize']) = proc.stdout.rstrip().split(':', 4) size = float(size.replace(',', '.'))
image_info['clientname'] = os.getenv('HOSTNAME') 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 return image_info