# # Copyright (C) 2023 Soleta Networks # # This program is free software: you can redistribute it and/or modify it under # the terms of the GNU Affero General Public License as published by the # Free Software Foundation; either version 3 of the License, or # (at your option) any later version. import hashlib import logging import os import shlex import shutil import subprocess import urllib.request def _compute_md5(path, bs=2**20): m = hashlib.md5() with open(path, 'rb') as f: while True: buf = f.read(bs) if not buf: break m.update(buf) return m.hexdigest() def tip_fetch_csum(tip_addr, image_name): """ """ url = f'http://{tip_addr}:9999/{image_name}.img.full.sum' try: with urllib.request.urlopen(f'{url}') as resp: r = resp.readline().rstrip().decode('utf-8') except urllib.error.URLError as e: raise urllib.error.URLError(f'URL error when fetching checksum: {e.reason}') from e except urllib.error.HTTPError as e: raise urllib.error.URLError(f'HTTP Error when fetching checksum: {e.reason}') from e return r def tip_write_csum(image_name): """ TODO: Check for CACHE partition """ image_path = f'/opt/opengnsys/cache/opt/opengnsys/images/{image_name}.img' if not os.path.exists(image_path): raise RuntimeError(f'Invalid image path {image_path} for tiptorrent checksum writing') filename = image_path + ".full.sum" csum = _compute_md5(image_path) with open(filename, 'w') as f: f.write(csum) return csum def tip_check_csum(tip_addr, image_name): """ """ logging.info(f'Verifying checksum for {image_name}.img, please wait...') image_path = f'/opt/opengnsys/cache/opt/opengnsys/images/{image_name}.img' if not os.path.exists(image_path): raise RuntimeError(f'Invalid image path {image_path} for tiptorrent image csum comparison') cache_csum = _compute_md5(image_path) remote_csum = tip_fetch_csum(tip_addr, image_name) logging.debug(f'cache_csum: {cache_csum}') logging.debug(f'remote_csum: {remote_csum}') return cache_csum == remote_csum def tip_client_get(tip_addr, image_name): """ """ logging.info(f'Fetching image {image_name} from tiptorrent server at {tip_addr}') logging.info('*DO NOT REBOOT OR POWEROFF* the client during this time') cmd = f'tiptorrent-client {tip_addr} {image_name}.img' logfile = open('/tmp/command.log', 'wb', 0) try: proc = subprocess.Popen(shlex.split(cmd), stdout=logfile, cwd='/opt/opengnsys/cache/opt/opengnsys/images/') proc.communicate() except OSError as e: raise OSError('Unexpected error running tiptorrent subprocess: {e}') from e finally: logfile.close() if proc.returncode != 0: raise RuntimeError(f'Error fetching image {image_name} via tiptorrent') else: logging.info('Calculating checksum...') logging.info('*DO NOT REBOOT OR POWEROFF* the client during this time') tip_write_csum(image_name)