summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJose M. Guisado <jguisado@soleta.eu>2023-03-01 17:59:04 +0100
committerJose M. Guisado <jguisado@soleta.eu>2023-03-02 13:15:10 +0100
commitc9a3a763ddf91ccf3d382a29996c4f2f5e767d9a (patch)
tree8ec89b9b32cd8567b3110785699b786333000317
parenta1edbe904b3019ec77b54fdd48c01183f4c73483 (diff)
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.
-rw-r--r--src/ogRest.py8
-rw-r--r--src/utils/legacy.py118
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