Add upgrade confirm and reboot password
This commit is contained in:
@@ -27,6 +27,9 @@ arcane:
|
|||||||
api_key: "arc_..."
|
api_key: "arc_..."
|
||||||
env_id: 0
|
env_id: 0
|
||||||
|
|
||||||
|
security:
|
||||||
|
reboot_password: "CHANGE_ME"
|
||||||
|
|
||||||
docker:
|
docker:
|
||||||
# If true, discover containers by name/label
|
# If true, discover containers by name/label
|
||||||
autodiscovery: true
|
autodiscovery: true
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
|
import asyncio
|
||||||
from aiogram import F
|
from aiogram import F
|
||||||
from aiogram.types import Message, CallbackQuery
|
from aiogram.types import Message, CallbackQuery, InlineKeyboardMarkup, InlineKeyboardButton
|
||||||
from app import dp
|
from app import dp, cfg
|
||||||
from auth import is_admin_msg
|
from auth import is_admin_msg
|
||||||
from keyboards import system_kb
|
from keyboards import system_kb
|
||||||
from system_checks import security, disks
|
from system_checks import security, disks
|
||||||
from app import cfg
|
|
||||||
from services.http_checks import get_url_checks, check_url
|
from services.http_checks import get_url_checks, check_url
|
||||||
import asyncio
|
|
||||||
from services.queue import enqueue
|
from services.queue import enqueue
|
||||||
from services.updates import list_updates, apply_updates
|
from services.updates import list_updates, apply_updates
|
||||||
from state import UPDATES_CACHE
|
from services.runner import run_cmd
|
||||||
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton
|
from state import UPDATES_CACHE, REBOOT_PENDING
|
||||||
|
|
||||||
|
|
||||||
@dp.message(F.text == "💽 Disks")
|
@dp.message(F.text == "💽 Disks")
|
||||||
@@ -42,7 +41,7 @@ async def urls(msg: Message):
|
|||||||
results = await asyncio.gather(*tasks)
|
results = await asyncio.gather(*tasks)
|
||||||
|
|
||||||
lines = ["🌐 URLs\n"]
|
lines = ["🌐 URLs\n"]
|
||||||
for (alias, url), (ok, status, ms, err) in zip(checks, results):
|
for (alias, _url), (ok, status, ms, err) in zip(checks, results):
|
||||||
if ok:
|
if ok:
|
||||||
lines.append(f"🟢 {alias}: {status} ({ms}ms)")
|
lines.append(f"🟢 {alias}: {status} ({ms}ms)")
|
||||||
elif status is not None:
|
elif status is not None:
|
||||||
@@ -79,12 +78,27 @@ async def updates_apply(msg: Message):
|
|||||||
if not is_admin_msg(msg):
|
if not is_admin_msg(msg):
|
||||||
return
|
return
|
||||||
|
|
||||||
async def job():
|
kb = InlineKeyboardMarkup(
|
||||||
text = await apply_updates()
|
inline_keyboard=[[
|
||||||
await msg.answer(text, reply_markup=system_kb, parse_mode="Markdown")
|
InlineKeyboardButton(text="✅ Confirm", callback_data="upgrade:confirm"),
|
||||||
|
InlineKeyboardButton(text="✖ Cancel", callback_data="upgrade:cancel"),
|
||||||
|
]]
|
||||||
|
)
|
||||||
|
await msg.answer("⚠️ Confirm package upgrade?", reply_markup=kb)
|
||||||
|
|
||||||
pos = await enqueue("pkg-upgrade", job)
|
|
||||||
await msg.answer(f"🕓 Upgrade queued (#{pos})", reply_markup=system_kb)
|
@dp.message(F.text == "🔄 Reboot")
|
||||||
|
async def reboot_request(msg: Message):
|
||||||
|
if not is_admin_msg(msg):
|
||||||
|
return
|
||||||
|
|
||||||
|
kb = InlineKeyboardMarkup(
|
||||||
|
inline_keyboard=[[
|
||||||
|
InlineKeyboardButton(text="✅ Confirm", callback_data="reboot:confirm"),
|
||||||
|
InlineKeyboardButton(text="✖ Cancel", callback_data="reboot:cancel"),
|
||||||
|
]]
|
||||||
|
)
|
||||||
|
await msg.answer("⚠️ Confirm reboot?", reply_markup=kb)
|
||||||
|
|
||||||
|
|
||||||
def _updates_kb(page: int, total_pages: int) -> InlineKeyboardMarkup:
|
def _updates_kb(page: int, total_pages: int) -> InlineKeyboardMarkup:
|
||||||
@@ -133,3 +147,59 @@ async def updates_page(cb: CallbackQuery):
|
|||||||
return
|
return
|
||||||
await cb.answer()
|
await cb.answer()
|
||||||
await send_updates_page(cb.message, cb.from_user.id, page, edit=True)
|
await send_updates_page(cb.message, cb.from_user.id, page, edit=True)
|
||||||
|
|
||||||
|
|
||||||
|
@dp.callback_query(F.data == "upgrade:confirm")
|
||||||
|
async def upgrade_confirm(cb: CallbackQuery):
|
||||||
|
if cb.from_user.id != cfg["telegram"]["admin_id"]:
|
||||||
|
return
|
||||||
|
await cb.answer()
|
||||||
|
|
||||||
|
async def job():
|
||||||
|
text = await apply_updates()
|
||||||
|
await cb.message.answer(text, reply_markup=system_kb, parse_mode="Markdown")
|
||||||
|
|
||||||
|
pos = await enqueue("pkg-upgrade", job)
|
||||||
|
await cb.message.answer(f"🕓 Upgrade queued (#{pos})", reply_markup=system_kb)
|
||||||
|
|
||||||
|
|
||||||
|
@dp.callback_query(F.data == "upgrade:cancel")
|
||||||
|
async def upgrade_cancel(cb: CallbackQuery):
|
||||||
|
await cb.answer("Cancelled")
|
||||||
|
|
||||||
|
|
||||||
|
@dp.callback_query(F.data == "reboot:confirm")
|
||||||
|
async def reboot_confirm(cb: CallbackQuery):
|
||||||
|
if cb.from_user.id != cfg["telegram"]["admin_id"]:
|
||||||
|
return
|
||||||
|
await cb.answer()
|
||||||
|
REBOOT_PENDING[cb.from_user.id] = {}
|
||||||
|
await cb.message.answer("🔐 Send reboot password", reply_markup=system_kb)
|
||||||
|
|
||||||
|
|
||||||
|
@dp.callback_query(F.data == "reboot:cancel")
|
||||||
|
async def reboot_cancel(cb: CallbackQuery):
|
||||||
|
await cb.answer("Cancelled")
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message(F.text, F.func(lambda msg: msg.from_user and msg.from_user.id in REBOOT_PENDING))
|
||||||
|
async def reboot_password(msg: Message):
|
||||||
|
if not is_admin_msg(msg):
|
||||||
|
return
|
||||||
|
REBOOT_PENDING.pop(msg.from_user.id, None)
|
||||||
|
|
||||||
|
expected = cfg.get("security", {}).get("reboot_password")
|
||||||
|
if not expected:
|
||||||
|
await msg.answer("⚠️ Reboot password not configured", reply_markup=system_kb)
|
||||||
|
return
|
||||||
|
|
||||||
|
if (msg.text or "").strip() != expected:
|
||||||
|
await msg.answer("❌ Wrong password", reply_markup=system_kb)
|
||||||
|
return
|
||||||
|
|
||||||
|
async def job():
|
||||||
|
await msg.answer("🔄 Rebooting…", reply_markup=system_kb)
|
||||||
|
await run_cmd(["sudo", "reboot"], timeout=10)
|
||||||
|
|
||||||
|
pos = await enqueue("reboot", job)
|
||||||
|
await msg.answer(f"🕓 Reboot queued (#{pos})", reply_markup=system_kb)
|
||||||
|
|||||||
1
state.py
1
state.py
@@ -4,3 +4,4 @@ DOCKER_MAP: Dict[str, str] = {}
|
|||||||
LOG_FILTER_PENDING: Dict[int, dict] = {}
|
LOG_FILTER_PENDING: Dict[int, dict] = {}
|
||||||
UPDATES_CACHE: Dict[int, dict] = {}
|
UPDATES_CACHE: Dict[int, dict] = {}
|
||||||
ARCANE_CACHE: Dict[int, dict] = {}
|
ARCANE_CACHE: Dict[int, dict] = {}
|
||||||
|
REBOOT_PENDING: Dict[int, dict] = {}
|
||||||
|
|||||||
Reference in New Issue
Block a user