diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..4cf16a5 --- /dev/null +++ b/.env.example @@ -0,0 +1,2 @@ +TOKEN= +ADMIN_ID= diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1d4a7d0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +/.env +.idea +venv +__pycache__/ +*.py[cod] +*$py.class \ No newline at end of file diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/handlers/__init__.py b/app/handlers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/handlers/docker_commands.py b/app/handlers/docker_commands.py new file mode 100644 index 0000000..340a88c --- /dev/null +++ b/app/handlers/docker_commands.py @@ -0,0 +1,48 @@ +import subprocess + +from aiogram.types import Message, CallbackQuery + +from app.keyboards.docker_keyboards import container_names_keyboard, container_actions_keyboard + + +async def get_containers(message: Message): + sub = subprocess.check_output("docker ps -a").decode() + keyboard = container_names_keyboard(sub) + await message.answer( + text=f"
{sub}
",
+ parse_mode="HTML",
+ reply_markup=keyboard.as_markup()
+ )
+
+
+async def container_actions(call: CallbackQuery):
+ name = call.data.split("_")[-1]
+ keyboard = container_actions_keyboard(name)
+ await call.message.answer(
+ text=f"Выберите действие для контейнера {name}",
+ parse_mode="HTML",
+ reply_markup=keyboard.as_markup()
+ )
+
+
+async def do_container_action(call: CallbackQuery):
+ _, action, name = call.data.split("_")
+ match action:
+ case "start":
+ subprocess.run(f"docker start {name}")
+ message = f"Контейнер {name} успешно запущен"
+ case "stop":
+ subprocess.run(f"docker stop {name}")
+ message = f"Контейнер {name} успешно остановлен"
+ case "restart":
+ subprocess.run(f"docker restart {name}")
+ message = f"Контейнер {name} успешно перезапущен"
+ case "delete":
+ subprocess.run(f"docker rm -f {name}")
+ message = f"Контейнер {name} успешно удалён"
+ case _:
+ message = f"Произошла необъяснимая ошибка"
+
+ await call.message.answer(
+ text=message,
+ )
diff --git a/app/handlers/user_command.py b/app/handlers/user_command.py
new file mode 100644
index 0000000..8e6e67f
--- /dev/null
+++ b/app/handlers/user_command.py
@@ -0,0 +1,11 @@
+import subprocess
+
+from aiogram.types import Message
+
+
+async def execute_command(message: Message):
+ user_command = message.text.split()[1:]
+ print(user_command)
+ sub = subprocess.check_output(user_command)
+ # print(sub)
+ await message.answer(f"{sub.decode()}
", parse_mode="HTML")
diff --git a/app/keyboards/__init__.py b/app/keyboards/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/app/keyboards/docker_keyboards.py b/app/keyboards/docker_keyboards.py
new file mode 100644
index 0000000..224a9ff
--- /dev/null
+++ b/app/keyboards/docker_keyboards.py
@@ -0,0 +1,42 @@
+from aiogram.types import InlineKeyboardButton
+from aiogram.utils.keyboard import InlineKeyboardBuilder
+
+
+def container_names_keyboard(stdout: str):
+ container_names = [line.split(" ")[-1].strip() for line in stdout.splitlines()[1:]]
+ builder = InlineKeyboardBuilder()
+ for name in container_names:
+ data = f"container_{name}"
+ builder.add(
+ InlineKeyboardButton(
+ text=name,
+ callback_data=data,
+ )
+ )
+ builder.adjust(1)
+
+ return builder
+
+
+def container_actions_keyboard(name: str):
+ builder = InlineKeyboardBuilder()
+
+ builder.add(InlineKeyboardButton(
+ text="Запустить контейнер",
+ callback_data=f"action_start_{name}",
+ ))
+ builder.add(InlineKeyboardButton(
+ text="Остановить контейнер",
+ callback_data=f"action_stop_{name}",
+ ))
+ builder.add(InlineKeyboardButton(
+ text="Перезапустить контейнер",
+ callback_data=f"action_restart_{name}",
+ ))
+ builder.add(InlineKeyboardButton(
+ text="Удалить контейнер",
+ callback_data=f"action_delete_{name}",
+ ))
+ builder.adjust(1)
+
+ return builder
diff --git a/app/settings.py b/app/settings.py
new file mode 100644
index 0000000..cb96309
--- /dev/null
+++ b/app/settings.py
@@ -0,0 +1,16 @@
+import os
+from dataclasses import dataclass
+
+from aiogram import Bot
+from dotenv import load_dotenv
+
+load_dotenv()
+
+
+@dataclass
+class Secrets:
+ token: str = os.environ.get("TOKEN")
+ admin_id: int = os.environ.get("ADMIN_ID")
+
+
+bot = Bot(token=Secrets.token)
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..fa8f2b0
--- /dev/null
+++ b/main.py
@@ -0,0 +1,27 @@
+import asyncio
+
+from aiogram import Dispatcher, F
+from aiogram.filters import Command
+
+from app.handlers.docker_commands import get_containers, container_actions, do_container_action
+from app.handlers.user_command import execute_command
+from app.settings import bot
+
+
+async def start():
+ dp = Dispatcher()
+
+ dp.message.register(execute_command, Command(commands="command"))
+ dp.message.register(get_containers, Command(commands="docker_list"))
+
+ dp.callback_query.register(container_actions, F.data.startswith("container"))
+ dp.callback_query.register(do_container_action, F.data.startswith("action"))
+
+ try:
+ await dp.start_polling(bot)
+ finally:
+ await bot.session.close()
+
+
+if __name__ == "__main__":
+ asyncio.run(start())