refs #2385 Fix restoration

pull/96/head
Vadim vtroshchinskiy 2025-07-17 10:01:46 +02:00
parent 7315ebe2ff
commit 0d3ffe0180
2 changed files with 142 additions and 10 deletions

View File

@ -63,12 +63,11 @@ class OgLogger(logging.StreamHandler):
case logging.CRITICAL:
SystemLib.ogRaiseError()
print("HERE!")
SystemLib.ogEcho(log_types, log_level, record.getMessage())
def commit_image(disk_num, partition_num, repo, image_name, msg):
def commit_image(disk_num, partition_num, image_name, msg):
ntfs_impl = NTFSImplementation.NTFS3G
og_git = OpengnsysGitLibrary(ntfs_implementation = ntfs_impl)
@ -76,17 +75,21 @@ def commit_image(disk_num, partition_num, repo, image_name, msg):
device = DiskLib.ogDiskToDev(disk_num, partition_num)
og_git.commit(device = device, message = msg)
og_git.push()
og_git.push(device = device)
return 0
def main():
if len(sys.argv) != 6:
sys.exit(SystemLib.ogRaiseError([], ogGlobals.OG_ERR_FORMAT, "Incorrect number of arguments. Usage: ModificarImagenGit.py disk_num partition_num image_name repo msg"))
if len(sys.argv) != 5:
import json
args = json.dumps(sys.argv)
sys.exit(SystemLib.ogRaiseError([], ogGlobals.OG_ERR_FORMAT, f"Incorrect number of arguments. Usage: ModificarImagenGit.py disk_num partition_num image_name repo msg. Received args: {args}"))
# repo - repositorio, ip address. Opcional porque oglive lo recibe como parametro de kernel
# tag - tag a crear automaticamente. Opcional, no necesitamos crear un tag siempre.
disk_num, partition_num, image_name, repo, msg = sys.argv[1:6]
disk_num, partition_num, image_name, msg = sys.argv[1:5]
opengnsys_log_dir = "/opt/opengnsys/log"
@ -111,10 +114,10 @@ def main():
logger.info("Starting ModificarImagenGit")
retval = commit_image(disk_num, partition_num, repo, image_name, msg)
retval = commit_image(disk_num, partition_num, image_name, msg)
logger.info("ModificarImagenGit done, return code %i", retval)
sys.exit(retval)
if __name__ == "__main__":

View File

@ -5,6 +5,7 @@ import os
import json
import blkid
import time
import signal
from GitLib.ntfs import *
@ -33,6 +34,120 @@ class FilesystemLibrary:
subprocess.run(["/usr/sbin/modprobe", module], check=True)
def _read_file(self, file):
data = ""
try:
with open(file, "r", encoding='utf-8') as f:
data = f.read()
except IOError as io_err:
self.logger.debug("IO Error reading file %s: %s", file, io_err)
return data
def _read_link(self, file):
data = ""
try:
data = os.readlink(file)
except IOError as io_err:
self.logger.debug("IO Error reading link %s: %s", file, io_err)
return data
def lsof(self, path):
"""
Lists processes that are using files or directories under the specified path.
This method inspects the /proc filesystem to find processes whose executable,
current working directory, or open file descriptors reference the given path.
It returns a dictionary mapping process IDs (as strings) to a dictionary
containing the command name.
Args:
path (str): The file system path to check for usage by running processes.
Returns:
dict: A dictionary where keys are process IDs (str) and values are dicts
with at least the key "cmd" (the command name or executable path).
Note:
This method requires sufficient permissions to access /proc and process
information. It may raise exceptions if permissions are insufficient or
if processes terminate during inspection.
"""
proc_path = "/proc"
pids_using_path = {}
self.logger.debug("Checking for processes using %s", path)
for pid_dir in os.listdir(proc_path):
if not pid_dir.isdigit():
continue # Not a pid directory
pid_dir_path = os.path.join(proc_path, pid_dir)
fd_path = os.path.join(pid_dir_path, "fd")
command_name = self._read_link(os.path.join(pid_dir_path, "exe"))
working_dir = self._read_link(os.path.join(pid_dir_path, "cwd"))
cmdline = self._read_file(os.path.join(pid_dir_path, "cmdline")).split("\0")
if command_name.startswith(path):
self.logger.debug("PID %s (%s) is running from within %s: %s", pid_dir, command_name, path, command_name)
pids_using_path[pid_dir] = { "cmd" : command_name, "args" : cmdline}
elif working_dir.startswith(path):
self.logger.debug("PID %s (%s) is has a working directory within %s: %s", pid_dir, command_name, path, working_dir)
pids_using_path[pid_dir] = { "cmd" : command_name, "args" : cmdline}
else:
for fd_file in os.listdir(fd_path):
fd_file_full_path = os.path.join(fd_path, fd_file)
target = self._read_link(fd_file_full_path)
if target.startswith(path):
self.logger.debug("PID %s (%s) is has an open file within %s: %s", pid_dir, command_name, path, target)
pids_using_path[pid_dir] = { "cmd" : command_name, "args" : cmdline}
return pids_using_path
def kill_path_users(self, path, use_sigkill = False):
"""
Terminates all processes that are currently using the specified filesystem path.
This method uses the `lsof` utility to identify processes that have open files or directories
under the given `path`. For each identified process, it sends either a SIGTERM or SIGKILL signal
to terminate the process, depending on the `use_sigkill` flag.
Args:
path (str): The filesystem path to check for open files.
use_sigkill (bool, optional): If True, sends SIGKILL to forcibly terminate processes.
If False (default), sends SIGTERM to allow processes to terminate gracefully.
Logs:
Information about each process being terminated, including the PID, command, and arguments.
"""
self.logger.info("Killing any processes using %s, sigkill = %s", path, str(use_sigkill))
lsof_data = self.lsof(path)
for pid, pid_data in lsof_data.items():
try:
if use_sigkill:
self.logger.info("Killing process %s with SIGKILL: command %s, args %s", pid, pid_data["cmd"], pid_data["args"])
os.kill(int(pid), signal.SIGKILL)
else:
self.logger.info("Killing process %s with SIGTERM: command %s, args %s", pid, pid_data["cmd"], pid_data["args"])
os.kill(int(pid), signal.SIGTERM)
except OSError as os_error:
self.logger.warning("Failed to send signal to pid %s: %s", pid, os_error)
# _parse_mounts
def update_mounts(self):
"""
@ -94,6 +209,7 @@ class FilesystemLibrary:
norm = os.path.normpath(device)
self.logger.debug(f"Checking if {device} is mounted")
self.update_mounts()
for mountpoint, mount in self.mounts.items():
#self.logger.debug(f"Item: {mount}")
#self.logger.debug(f"Checking: " + mount['device'])
@ -172,7 +288,12 @@ class FilesystemLibrary:
done = False
start_time = time.time()
timeout = 60*15
# How long to wait for the filesystem to unmount
timeout = 60
# How long to wait before starting to send SIGKILL to users
force_timeout = 5
while not done and (time.time() - start_time) < timeout:
@ -180,8 +301,16 @@ class FilesystemLibrary:
if ret.returncode == 0:
done=True
else:
elapsed = (time.time() - start_time)
if "target is busy" in ret.stderr:
self.logger.debug("Filesystem busy, waiting. %.1f seconds left", timeout - (time.time() - start_time))
self.logger.debug("Filesystem busy, waiting. %.1f seconds left", timeout - elapsed)
if elapsed > force_timeout:
self.kill_path_users(mountpoint, use_sigkill=True)
else:
self.kill_path_users(mountpoint, use_sigkill=False)
time.sleep(0.1)
else:
raise subprocess.CalledProcessError(ret.returncode, ret.args, output=ret.stdout, stderr=ret.stderr)