Upload files to "/"
This commit is contained in:
211
main.py
Normal file
211
main.py
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
import discord
|
||||||
|
import docker
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
from discord.ext import commands, tasks
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
BOT_TOKEN = os.getenv("BOT_TOKEN")
|
||||||
|
DOCKER_HOST = os.getenv("DOCKER_HOST")
|
||||||
|
GUILD_ID = int(os.getenv("GUILD_ID")) # Your server ID
|
||||||
|
CATEGORY_NAME = os.getenv("CATEGORY_NAME") # Category name for the channels
|
||||||
|
|
||||||
|
intents = discord.Intents.default()
|
||||||
|
intents.message_content = True
|
||||||
|
bot = commands.Bot(command_prefix="!", intents=intents)
|
||||||
|
|
||||||
|
# Stores groups: { "groupname": { "channel_id": 123, "containers": ["nginx", "mysql"], "message_id": 456 } }
|
||||||
|
GROUPS_FILE = "groups.json"
|
||||||
|
|
||||||
|
def load_groups():
|
||||||
|
if os.path.exists(GROUPS_FILE):
|
||||||
|
with open(GROUPS_FILE, "r") as f:
|
||||||
|
return json.load(f)
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def save_groups(groups):
|
||||||
|
with open(GROUPS_FILE, "w") as f:
|
||||||
|
json.dump(groups, f, indent=2)
|
||||||
|
|
||||||
|
def status_symbol(status):
|
||||||
|
symbols = {
|
||||||
|
"running": "🟢",
|
||||||
|
"exited": "🔴",
|
||||||
|
"paused": "🟡",
|
||||||
|
"created": "⚪",
|
||||||
|
}
|
||||||
|
return symbols.get(status, "❓")
|
||||||
|
|
||||||
|
# --- Commands ---
|
||||||
|
|
||||||
|
@bot.command()
|
||||||
|
async def container_list(ctx):
|
||||||
|
"""Shows all available containers on the host"""
|
||||||
|
try:
|
||||||
|
client = docker.DockerClient(base_url=DOCKER_HOST, timeout=5)
|
||||||
|
container_list = client.containers.list(all=True)
|
||||||
|
|
||||||
|
message = "**🐳 Available Containers:**\n```\n"
|
||||||
|
for c in container_list:
|
||||||
|
message += f"{status_symbol(c.status)} {c.name}\n"
|
||||||
|
message += "```\nUse `!group_create <name> <container1> <container2> ...` to create a group."
|
||||||
|
|
||||||
|
await ctx.send(message)
|
||||||
|
except Exception as e:
|
||||||
|
await ctx.send(f"❌ Error: {e}")
|
||||||
|
|
||||||
|
@bot.command()
|
||||||
|
async def group_create(ctx, group_name: str, *container_names):
|
||||||
|
"""Creates a group and a channel for it
|
||||||
|
Example: !group_create webservices nginx apache"""
|
||||||
|
if not container_names:
|
||||||
|
await ctx.send("❌ Please specify at least one container!\nExample: `!group_create webservices nginx apache`")
|
||||||
|
return
|
||||||
|
|
||||||
|
guild = bot.get_guild(GUILD_ID)
|
||||||
|
groups = load_groups()
|
||||||
|
|
||||||
|
# Create category if it doesn't exist
|
||||||
|
category = discord.utils.get(guild.categories, name=CATEGORY_NAME)
|
||||||
|
if not category:
|
||||||
|
category = await guild.create_category(CATEGORY_NAME)
|
||||||
|
|
||||||
|
# Create channel
|
||||||
|
channel_name = f"🐳{group_name.lower()}"
|
||||||
|
channel = discord.utils.get(category.channels, name=channel_name)
|
||||||
|
if not channel:
|
||||||
|
# Only bot is allowed to write
|
||||||
|
overwrites = {
|
||||||
|
guild.default_role: discord.PermissionOverwrite(send_messages=False),
|
||||||
|
guild.me: discord.PermissionOverwrite(send_messages=True)
|
||||||
|
}
|
||||||
|
channel = await category.create_text_channel(channel_name, overwrites=overwrites)
|
||||||
|
|
||||||
|
# Save group
|
||||||
|
groups[group_name] = {
|
||||||
|
"channel_id": channel.id,
|
||||||
|
"containers": list(container_names),
|
||||||
|
"message_id": None
|
||||||
|
}
|
||||||
|
save_groups(groups)
|
||||||
|
|
||||||
|
await ctx.send(f"✅ Group **{group_name}** created with channel {channel.mention}\nContainers: `{', '.join(container_names)}`")
|
||||||
|
|
||||||
|
@bot.command()
|
||||||
|
async def group_remove(ctx, group_name: str):
|
||||||
|
"""Deletes a group and its channel"""
|
||||||
|
groups = load_groups()
|
||||||
|
|
||||||
|
if group_name not in groups:
|
||||||
|
await ctx.send(f"❌ Group `{group_name}` not found.")
|
||||||
|
return
|
||||||
|
|
||||||
|
guild = bot.get_guild(GUILD_ID)
|
||||||
|
channel = guild.get_channel(groups[group_name]["channel_id"])
|
||||||
|
if channel:
|
||||||
|
await channel.delete()
|
||||||
|
|
||||||
|
del groups[group_name]
|
||||||
|
save_groups(groups)
|
||||||
|
await ctx.send(f"✅ Group **{group_name}** deleted.")
|
||||||
|
|
||||||
|
@bot.command()
|
||||||
|
async def group_list(ctx):
|
||||||
|
"""Shows all groups"""
|
||||||
|
groups = load_groups()
|
||||||
|
if not groups:
|
||||||
|
await ctx.send("No groups found. Use `!group_create` to create one.")
|
||||||
|
return
|
||||||
|
|
||||||
|
message = "**📋 Groups:**\n"
|
||||||
|
for name, data in groups.items():
|
||||||
|
message += f"\n**{name}:** `{', '.join(data['containers'])}`"
|
||||||
|
await ctx.send(message)
|
||||||
|
|
||||||
|
@bot.command()
|
||||||
|
async def info(ctx):
|
||||||
|
"""Shows all available commands and their usage"""
|
||||||
|
message = (
|
||||||
|
"**🤖 Docker Monitor Bot - Commands**\n\n"
|
||||||
|
"**📋 Container**\n"
|
||||||
|
"`!container_list`\n"
|
||||||
|
"→ Shows all available containers on the host\n\n"
|
||||||
|
"**📁 Groups**\n"
|
||||||
|
"`!group_create <name> <container1> <container2> ...`\n"
|
||||||
|
"→ Creates a group with a dedicated channel for the given containers\n"
|
||||||
|
"→ Example: `!group_create webservices nginx apache`\n\n"
|
||||||
|
"`!group_remove <name>`\n"
|
||||||
|
"→ Deletes a group and its channel\n"
|
||||||
|
"→ Example: `!group_remove webservices`\n\n"
|
||||||
|
"`!group_list`\n"
|
||||||
|
"→ Shows all existing groups and their containers\n\n"
|
||||||
|
"**ℹ️ Other**\n"
|
||||||
|
"`!info`\n"
|
||||||
|
"→ Shows this help message\n\n"
|
||||||
|
"**🔄 Monitoring**\n"
|
||||||
|
"Container statuses are automatically updated every **30 seconds** in their group channels.\n"
|
||||||
|
"🟢 running 🔴 exited 🟡 paused ⚪ created ❓ unknown"
|
||||||
|
)
|
||||||
|
await ctx.send(message)
|
||||||
|
|
||||||
|
# --- Monitoring ---
|
||||||
|
|
||||||
|
@tasks.loop(seconds=30)
|
||||||
|
async def monitor_containers():
|
||||||
|
groups = load_groups()
|
||||||
|
if not groups:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
docker_client = docker.DockerClient(base_url=DOCKER_HOST, timeout=5)
|
||||||
|
all_containers = {c.name: c.status for c in docker_client.containers.list(all=True)}
|
||||||
|
except Exception:
|
||||||
|
return
|
||||||
|
|
||||||
|
guild = bot.get_guild(GUILD_ID)
|
||||||
|
|
||||||
|
for group_name, data in groups.items():
|
||||||
|
channel = guild.get_channel(data["channel_id"])
|
||||||
|
if not channel:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Build status text
|
||||||
|
text = f"**🐳 {group_name.upper()}**\n```\n"
|
||||||
|
for container_name in data["containers"]:
|
||||||
|
if container_name in all_containers:
|
||||||
|
status = all_containers[container_name]
|
||||||
|
text += f"{status_symbol(status)} {container_name:<25} {status}\n"
|
||||||
|
else:
|
||||||
|
text += f"❓ {container_name:<25} not found\n"
|
||||||
|
text += "```"
|
||||||
|
|
||||||
|
try:
|
||||||
|
if data["message_id"]:
|
||||||
|
# Edit existing message
|
||||||
|
message = await channel.fetch_message(data["message_id"])
|
||||||
|
await message.edit(content=text)
|
||||||
|
else:
|
||||||
|
# Send first message
|
||||||
|
message = await channel.send(text)
|
||||||
|
data["message_id"] = message.id
|
||||||
|
save_groups(groups)
|
||||||
|
except discord.NotFound:
|
||||||
|
# Message was deleted, resend
|
||||||
|
message = await channel.send(text)
|
||||||
|
data["message_id"] = message.id
|
||||||
|
save_groups(groups)
|
||||||
|
|
||||||
|
@bot.event
|
||||||
|
async def on_command_error(ctx, error):
|
||||||
|
if isinstance(error, commands.CommandNotFound):
|
||||||
|
return # Ignore unknown commands silently
|
||||||
|
raise error # All other errors still show in logs
|
||||||
|
|
||||||
|
@bot.event
|
||||||
|
async def on_ready():
|
||||||
|
print(f"Bot is online as {bot.user}")
|
||||||
|
monitor_containers.start()
|
||||||
|
|
||||||
|
bot.run(BOT_TOKEN)
|
||||||
Reference in New Issue
Block a user