From a383028a6bea69c9f23e1a1e6dd2732b0b8e382a Mon Sep 17 00:00:00 2001
From: Pavel Kirilin <win10@list.ru>
Date: Thu, 30 Jan 2020 03:21:45 +0400
Subject: [PATCH] Added systemctl support. Description: - Added systemctl
 status to check service state. - Added systemctl start, stop, restart
 actions. - Added systemctl cat to show System-unit configuration.

---
 src/actions/__init__.py      |   1 +
 src/actions/basic_actions.py |   1 +
 src/actions/systemctl.py     | 112 +++++++++++++++++++++++++++++++++++
 3 files changed, 114 insertions(+)
 create mode 100644 src/actions/systemctl.py

diff --git a/src/actions/__init__.py b/src/actions/__init__.py
index f689a29..23a65a8 100644
--- a/src/actions/__init__.py
+++ b/src/actions/__init__.py
@@ -4,6 +4,7 @@ from .interactive_session import *
 from .permissions import *
 from .server_management import *
 from .stats import *
+from .systemctl import *
 from ..models.crud.server_crud import fn_get_all_chat_ids
 
 
diff --git a/src/actions/basic_actions.py b/src/actions/basic_actions.py
index 5c35909..9b48d46 100644
--- a/src/actions/basic_actions.py
+++ b/src/actions/basic_actions.py
@@ -21,6 +21,7 @@ async def overall_help(message: Message, state=None):
         # '* meme admin commands - Manage stored commands\n\n'
         '* meme admin exec {alias} {command} - Execute single command\n\n'
         '* meme admin docker - Manage docker on remote server\n\n'
+        '* meme admin sys - Manage systemctl on remote server\n\n'
         '* meme admin stats - See server statistics\n\n'
         '```',
         parse_mode=ParseMode.MARKDOWN
diff --git a/src/actions/systemctl.py b/src/actions/systemctl.py
new file mode 100644
index 0000000..8a92240
--- /dev/null
+++ b/src/actions/systemctl.py
@@ -0,0 +1,112 @@
+import logging
+import re
+
+from aiogram.types import Message, ParseMode
+
+from src.models.server import ServerPermissions
+from src.utils.debug_mode import debug_message
+from src.utils.decorators import (
+    bot_action
+)
+from src.utils.server_utils import get_server_by_alias
+from src.utils.ssh import run_ssh_command
+
+logger = logging.getLogger(__name__)
+
+
+@bot_action(r'meme admin sys( help)?$')
+async def overall_help(message: Message, state=None):
+    await message.reply(
+        '```\n'
+        '* sys stats {alias} {service} - Check status of the service\n\n'
+        '* sys start {alias} {service} - Start the service\n\n'
+        '* sys stop {alias} {service} - Stop the service\n\n'
+        '* sys restart {alias} {service} - Restart the service\n\n'
+        '* sys cat {alias} {service} - Show one or more service unit files\n\n'
+        '```',
+        parse_mode=ParseMode.MARKDOWN
+    )
+
+
+@bot_action(r'meme admin sys stats',
+            params=[
+                ('alias', r'[\w\d]+'),
+                ('service', r'[\w\d]+\.service')
+            ])
+async def status(message: Message, alias, service, state):
+    server = await get_server_by_alias(message,
+                                       server_alias=alias,
+                                       minimal_permission=ServerPermissions.SERVICES)
+    service_info = await run_ssh_command(server, f'systemctl status {service}')
+    description = re.search(r'(.*) - (?P<description>.*)', service_info.splitlines()[0])
+    startup_file = re.search(r'(.*)Loaded: loaded \((?P<file>.*\.service)', service_info)
+    service_state = re.search(r'(.*)Active: (?P<state>.*) since (.*); (?P<uptime>.*)', service_info)
+    pid = re.search(r'(.*)Main PID: (?P<pid>.*)', service_info)
+    tasks = re.search(r'(.*)Tasks: (?P<tasks>.*)', service_info)
+    memory = re.search(r'(.*)Memory: (?P<memory>.*)', service_info)
+    res_message = "```\n"
+    await debug_message(message, service_info)
+    for regex in [description, startup_file, service_state, pid, tasks, memory]:
+        if regex is None:
+            continue
+        for key, val in regex.groupdict().items():
+            res_message += f'{key}: {val}\n\n'
+    res_message += '```'
+    await message.reply(res_message, parse_mode=ParseMode.MARKDOWN)
+
+
+@bot_action(r'meme admin sys start',
+            params=[
+                ('alias', r'[\w\d]+'),
+                ('service', r'[\w\d]+\.service')
+            ])
+async def start(message: Message, alias, service, state):
+    server = await get_server_by_alias(message,
+                                       server_alias=alias,
+                                       minimal_permission=ServerPermissions.SERVICES)
+    await run_ssh_command(server, f'systemctl start {service}')
+    await message.reply("Service started")
+
+
+@bot_action(r'meme admin sys stop',
+            params=[
+                ('alias', r'[\w\d]+'),
+                ('service', r'[\w\d]+\.service')
+            ])
+async def stop(message: Message, alias, service, state):
+    server = await get_server_by_alias(message,
+                                       server_alias=alias,
+                                       minimal_permission=ServerPermissions.SERVICES)
+    await run_ssh_command(server, f'systemctl stop {service}')
+    await message.reply("Service stopped")
+
+
+@bot_action(r'meme admin sys restart',
+            params=[
+                ('alias', r'[\w\d]+'),
+                ('service', r'[\w\d]+\.service')
+            ])
+async def restart(message: Message, alias, service, state):
+    server = await get_server_by_alias(message,
+                                       server_alias=alias,
+                                       minimal_permission=ServerPermissions.SERVICES)
+    await run_ssh_command(server, f'systemctl restart {service}')
+    await message.reply("Service restarted")
+
+
+@bot_action(r'meme admin sys cat',
+            params=[
+                ('alias', r'[\w\d]+'),
+                ('service', r'[\w\d]+\.service')
+            ])
+async def cat(message: Message, alias, service, state):
+    server = await get_server_by_alias(message,
+                                       server_alias=alias,
+                                       minimal_permission=ServerPermissions.SERVICES)
+    out = await run_ssh_command(server, f'systemctl cat {service}')
+    await message.reply(
+        '```\n'
+        f'{out}'
+        '```',
+        parse_mode=ParseMode.MARKDOWN
+    )
-- 
GitLab