update
This commit is contained in:
parent
533f7982c8
commit
97bd3a1c88
155
services/cmd/handler.py
Normal file
155
services/cmd/handler.py
Normal 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)
|
Loading…
Reference in New Issue
Block a user