From 97bd3a1c88679d2c6d390f6f2f33cc6ecc57dfed Mon Sep 17 00:00:00 2001 From: KaySar12 Date: Mon, 14 Apr 2025 09:32:05 +0700 Subject: [PATCH] update --- services/cmd/handler.py | 155 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 services/cmd/handler.py diff --git a/services/cmd/handler.py b/services/cmd/handler.py new file mode 100644 index 0000000..64b9ab9 --- /dev/null +++ b/services/cmd/handler.py @@ -0,0 +1,155 @@ +import subprocess +import lib.color_log as color_log +import shutil +import os +import shlex +from services.odoo.connection import OdooConnection + + +class SSHHandler: + def __init__(self, config_path="config/settings.yaml"): + self.config = OdooConnection(config_path) + + def _check_sshpass(): + """Check if sshpass is installed in the system.""" + return shutil.which("sshpass") is not None + + def _build_command(host, cmd, ssh_user="root", ssh_key_path=None, passphrase=None): + """ + Build an SSH command with the given parameters. + + Args: + host (str): The target host + cmd (str): The command to execute + ssh_user (str): SSH user (default: root) + ssh_key_path (str, optional): Path to SSH key file + passphrase (str, optional): Passphrase for SSH key + + Returns: + tuple: (args, env) where args is a list of command arguments, and env is a dictionary of environment variables + """ + # For local execution + if host in ["localhost", "127.0.0.1"]: + return ["bash", "-c", cmd], None + + # Build SSH command as a list of arguments + args = [ + "ssh", + "-o", + "StrictHostKeyChecking=no", + "-o", + "UserKnownHostsFile=/dev/null", + "-t", + ] + if ssh_key_path: + args.extend(["-i", ssh_key_path]) + args.append(f"{ssh_user}@{host}") + # Quote the command safely for remote execution + remote_cmd = f"sudo -s bash -c {shlex.quote(cmd)}" + args.append(remote_cmd) + + env = None + # Handle passphrase securely with sshpass + if passphrase: + if not SSHHandler._check_sshpass(): + raise RuntimeError( + "sshpass is required for passphrase authentication but not installed" + ) + args = ["sshpass", "-e"] + args + env = {"SSHPASS": passphrase} + + return args, env + + def execute_command(args, instance_name, capture_output=True, env=None): + """ + Execute a command and handle errors. + + Args: + args (list): List of command arguments + instance_name (str): Name of the instance (for logging) + capture_output (bool): Whether to capture command output + env (dict, optional): Environment variables to set for the command + + Returns: + str: Command output if capture_output is True + + Raises: + subprocess.CalledProcessError: If command execution fails + """ + try: + # Log the command being executed + color_log.Show("INFO", f"Executing command: {' '.join(args)}") + + # Create a copy of the current environment + cmd_env = os.environ.copy() + # Update with any additional environment variables + if env: + cmd_env.update(env) + + # Execute the command with subprocess + result = subprocess.run( + args, check=True, capture_output=capture_output, text=True, env=cmd_env + ) + + # Handle output if captured + if capture_output: + if result.stdout: + print(result.stdout.strip()) + if result.stderr: + print(result.stderr.strip()) + + color_log.Show("OK", f"Command executed successfully for {instance_name}") + return result.stdout if capture_output else None + + except subprocess.CalledProcessError as e: + # Handle errors and log output + if capture_output: + if e.stdout: + print(e.stdout.strip()) + if e.stderr: + print(e.stderr.strip()) + + color_log.Show( + "FAILED", + f"Error executing command for {instance_name}: {e}", + ) + raise + + def run_ssh_command( + host, + cmd, + instance_name, + ssh_user="root", + ssh_key_path=None, + passphrase=None, + capture_output=True, + env=None, + ): + """ + Execute a command on a remote host via SSH or locally if host is localhost. + + Args: + host (str): The target host + cmd (str): The command to execute + instance_name (str): Name of the instance (for logging) + ssh_user (str): SSH user (default: root) + ssh_key_path (str, optional): Path to SSH key file + passphrase (str, optional): Passphrase for SSH key + capture_output (bool): Whether to capture command output + env (dict, optional): Additional environment variables to set for the command + + Returns: + str: Command output if capture_output is True + """ + # Build the command and get any required environment variables + args, cmd_env = SSHHandler._build_command( + host, cmd, ssh_user, ssh_key_path, passphrase + ) + # Merge command-specific env with user-provided env + if cmd_env: + if env is None: + env = cmd_env + else: + env.update(cmd_env) + # Execute the command + return SSHHandler.execute_command(args, instance_name, capture_output, env)