|
|
|
#!/usr/bin/env python3
|
|
|
|
# coding: utf-8
|
|
|
|
|
|
|
|
import argparse
|
|
|
|
import logging
|
|
|
|
import os
|
|
|
|
import shutil
|
|
|
|
import signal
|
|
|
|
import subprocess
|
|
|
|
import tempfile
|
|
|
|
|
|
|
|
from apps.libs.process.ssh import kill_ansible_ssh_process
|
|
|
|
|
|
|
|
ANSIBLE_RUNNER_COMMAND = "ansible-runner"
|
|
|
|
|
|
|
|
PROJECT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
APPS_DIR = os.path.join(PROJECT_DIR, 'apps')
|
|
|
|
TEMP_DIR = os.path.join(PROJECT_DIR, "tmp")
|
|
|
|
|
|
|
|
DEFAULT_SHARE_DIR = os.path.join(PROJECT_DIR, "data", "share")
|
|
|
|
DEFAULT_ANSIBLE_MODULES_DIR = os.path.join(APPS_DIR, "libs", "ansible", "modules")
|
|
|
|
DEFAULT_CONTROL_SOCK_PATH = os.path.join(DEFAULT_SHARE_DIR, "control.sock")
|
|
|
|
|
|
|
|
DEFAULT_TCP_LISTEN_ADDRESS = "0.0.0.0:7521"
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
os.chdir(APPS_DIR)
|
|
|
|
|
|
|
|
|
|
|
|
class ReceptorService:
|
|
|
|
def __init__(self):
|
|
|
|
self.pid_file = os.path.join(TEMP_DIR, "receptor.pid")
|
|
|
|
self.receptor_command = [
|
|
|
|
'receptor',
|
|
|
|
'--local-only',
|
|
|
|
'--node', 'id=primary',
|
|
|
|
'--log-level', 'level=Error',
|
|
|
|
'--control-service',
|
|
|
|
'service=control',
|
|
|
|
'tcplisten={}'.format(DEFAULT_TCP_LISTEN_ADDRESS),
|
|
|
|
'--work-command',
|
|
|
|
'worktype={}'.format(ANSIBLE_RUNNER_COMMAND),
|
|
|
|
'command={}'.format(ANSIBLE_RUNNER_COMMAND),
|
|
|
|
'params=worker',
|
|
|
|
'allowruntimeparams=true',
|
|
|
|
'--work-command',
|
|
|
|
'worktype={}'.format("kill"),
|
|
|
|
'command={}'.format("python"),
|
|
|
|
"params={} kill".format(os.path.join(PROJECT_DIR, "receptor")),
|
|
|
|
'allowruntimeparams=true'
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def before_start():
|
|
|
|
os.makedirs(os.path.join(DEFAULT_SHARE_DIR), exist_ok=True)
|
|
|
|
status_dir = os.path.join(tempfile.gettempdir(), "receptor")
|
|
|
|
if os.path.exists(status_dir):
|
|
|
|
shutil.rmtree(status_dir)
|
|
|
|
|
|
|
|
def start(self):
|
|
|
|
self.before_start()
|
|
|
|
if os.path.exists(self.pid_file):
|
|
|
|
with open(self.pid_file, 'r') as f:
|
|
|
|
pid_str = f.read()
|
|
|
|
try:
|
|
|
|
pid = int(pid_str)
|
|
|
|
os.kill(pid, 0)
|
|
|
|
print("\n- Receptor service is already running.")
|
|
|
|
return
|
|
|
|
except ProcessLookupError:
|
|
|
|
print("\n- PID file exists but process does not, starting Receptor...")
|
|
|
|
except ValueError:
|
|
|
|
print("\n- PID file is corrupted, starting Receptor...")
|
|
|
|
os.remove(self.pid_file)
|
|
|
|
|
|
|
|
os.environ.setdefault('ANSIBLE_LIBRARY', DEFAULT_ANSIBLE_MODULES_DIR)
|
|
|
|
os.environ.update({'PYTHONPATH': APPS_DIR})
|
|
|
|
process = subprocess.Popen(self.receptor_command)
|
|
|
|
with open(self.pid_file, 'w') as f:
|
|
|
|
f.write(str(process.pid))
|
|
|
|
print("\n- Receptor service started successfully.")
|
|
|
|
|
|
|
|
def exit_handler(signum, frame):
|
|
|
|
process.terminate()
|
|
|
|
process.kill()
|
|
|
|
|
|
|
|
signal.signal(signal.SIGINT, exit_handler)
|
|
|
|
signal.signal(signal.SIGTERM, exit_handler)
|
|
|
|
process.wait()
|
|
|
|
|
|
|
|
def stop(self):
|
|
|
|
if not os.path.exists(self.pid_file):
|
|
|
|
print("\n- Receptor service is not running.")
|
|
|
|
return
|
|
|
|
with open(self.pid_file, 'r') as f:
|
|
|
|
pid = int(f.read())
|
|
|
|
try:
|
|
|
|
os.kill(pid, signal.SIGTERM)
|
|
|
|
os.remove(self.pid_file)
|
|
|
|
print("\n- Receptor service stopped successfully.")
|
|
|
|
except ProcessLookupError:
|
|
|
|
print("\n- Failed to stop Receptor service: Process does not exist.")
|
|
|
|
os.remove(self.pid_file)
|
|
|
|
|
|
|
|
def restart(self):
|
|
|
|
self.stop()
|
|
|
|
self.start()
|
|
|
|
|
|
|
|
def status(self):
|
|
|
|
if os.path.exists(self.pid_file):
|
|
|
|
with open(self.pid_file, 'r') as f:
|
|
|
|
pid_str = f.read()
|
|
|
|
try:
|
|
|
|
pid = int(pid_str)
|
|
|
|
os.kill(pid, 0)
|
|
|
|
print("\n- Receptor service is running.")
|
|
|
|
return
|
|
|
|
except ProcessLookupError:
|
|
|
|
print("\n- Receptor service is not running.")
|
|
|
|
else:
|
|
|
|
print("\n- Receptor service is not running.")
|
|
|
|
|
|
|
|
|
|
|
|
def handle_receptor_action(args):
|
|
|
|
action = args.action
|
|
|
|
srv = ReceptorService()
|
|
|
|
if action == "start":
|
|
|
|
srv.start()
|
|
|
|
elif action == 'stop':
|
|
|
|
srv.stop()
|
|
|
|
elif action == "restart":
|
|
|
|
srv.restart()
|
|
|
|
elif action == "status":
|
|
|
|
srv.status()
|
|
|
|
elif action == "kill":
|
|
|
|
kill_progress_tree()
|
|
|
|
|
|
|
|
|
|
|
|
def kill_progress_tree(pid=None):
|
|
|
|
if not pid:
|
|
|
|
try:
|
|
|
|
pid_input = input()
|
|
|
|
pid = int(pid_input)
|
|
|
|
logger.info("progress {} will be kill".format(pid))
|
|
|
|
kill_ansible_ssh_process(pid)
|
|
|
|
except Exception as e:
|
|
|
|
logger.error(e)
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
parser = argparse.ArgumentParser(
|
|
|
|
description="""
|
|
|
|
Jumpserver receptor service control tools;
|
|
|
|
"""
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
'action', type=str,
|
|
|
|
choices=("start", "stop", "restart", "status", "kill"),
|
|
|
|
help="Action to run"
|
|
|
|
)
|
|
|
|
|
|
|
|
# parser.add_argument('--pid', type=int, default=42, help='what PID you want to kill')
|
|
|
|
|
|
|
|
args = parser.parse_args()
|
|
|
|
handle_receptor_action(args)
|