This commit is contained in:
KaySar12 2025-04-14 09:32:05 +07:00
parent 533f7982c8
commit 97bd3a1c88

155
services/cmd/handler.py Normal file
View File

@ -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)