aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--.vscode/settings.json3
-rw-r--r--arthur/apis/cloudflare/zones.py41
-rw-r--r--arthur/config.py3
-rw-r--r--arthur/exts/cloudflare/zones.py51
-rw-r--r--arthur/exts/kubernetes/deployments.py4
6 files changed, 101 insertions, 5 deletions
diff --git a/.gitignore b/.gitignore
index a81c8ee..e70bdfd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -136,3 +136,7 @@ dmypy.json
# Cython debug symbols
cython_debug/
+
+# Editing environment configuration files
+.vscode
+.idea
diff --git a/.vscode/settings.json b/.vscode/settings.json
deleted file mode 100644
index 163c984..0000000
--- a/.vscode/settings.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "python.formatting.provider": "black"
-}
diff --git a/arthur/apis/cloudflare/zones.py b/arthur/apis/cloudflare/zones.py
new file mode 100644
index 0000000..7debfd1
--- /dev/null
+++ b/arthur/apis/cloudflare/zones.py
@@ -0,0 +1,41 @@
+"""APIs for managing Cloudflare zones."""
+from typing import Optional
+
+import aiohttp
+
+from arthur.config import CONFIG
+
+AUTH_HEADER = {
+ "Authorization": f"Bearer {CONFIG.cloudflare_token}"
+}
+
+
+async def list_zones(zone_name: Optional[str] = None) -> dict[str, str]:
+ """List all Cloudflare zones."""
+ endpoint = "https://api.cloudflare.com/client/v4/zones"
+
+ if zone_name is not None:
+ endpoint += f"?name={zone_name}"
+
+ async with aiohttp.ClientSession() as session:
+ async with session.get(endpoint, headers=AUTH_HEADER) as response:
+ info = await response.json()
+
+ zones = info["result"]
+
+ return {zone["name"]: zone["id"] for zone in zones}
+
+
+async def purge_zone(zone_identifier: str) -> dict:
+ """Purge the cache for a Cloudflare zone."""
+ endpoint = f"https://api.cloudflare.com/client/v4/zones/{zone_identifier}/purge_cache"
+
+ request_body = {
+ "purge_everything": True
+ }
+
+ async with aiohttp.ClientSession() as session:
+ async with session.post(endpoint, headers=AUTH_HEADER, json=request_body) as response:
+ info = await response.json()
+
+ return {"success": info["success"], "errors": info["errors"]}
diff --git a/arthur/config.py b/arthur/config.py
index 982aa68..03eab03 100644
--- a/arthur/config.py
+++ b/arthur/config.py
@@ -14,6 +14,9 @@ class Config(BaseSettings):
# Authorised role ID for usage
devops_role: int = 409416496733880320
+ # Token for authorising with the Cloudflare API
+ cloudflare_token: str
+
class Config: # noqa: D106
env_file = ".env"
env_prefix = "KING_ARTHUR_"
diff --git a/arthur/exts/cloudflare/zones.py b/arthur/exts/cloudflare/zones.py
new file mode 100644
index 0000000..564dd2e
--- /dev/null
+++ b/arthur/exts/cloudflare/zones.py
@@ -0,0 +1,51 @@
+"""The zones cog helps with managing Cloudflare zones."""
+from typing import Optional
+
+from discord.ext import commands
+
+from arthur.apis.cloudflare import zones
+from arthur.bot import KingArthur
+from arthur.utils import generate_error_message
+
+
+class Zones(commands.Cog):
+ """Commands for working with Cloudflare zones."""
+
+ def __init__(self, bot: KingArthur) -> None:
+ self.bot = bot
+
+ @commands.group(name="zones", invoke_without_command=True)
+ async def zones(self, ctx: commands.Context) -> None:
+ """Commands for working with Cloudflare zones."""
+ await ctx.send_help(ctx.command)
+
+ @zones.command(name="purge")
+ async def purge(
+ self,
+ ctx: commands.Context,
+ zone_name: Optional[str] = "pythondiscord.com"
+ ) -> None:
+ """Command to clear the Cloudflare cache of the specified zone."""
+ pydis_zones = await zones.list_zones(zone_name)
+ required_id = pydis_zones[zone_name]
+ purge_attempt_response = await zones.purge_zone(required_id)
+
+ if purge_attempt_response["success"]:
+ message = ":white_check_mark:"
+ message += f" **Cache cleared!** The Cloudflare cache for `{zone_name}` was cleared."
+ else:
+ description_content = f"The cache for `{zone_name}` couldn't be cleared.\n"
+ if errors := purge_attempt_response["errors"]:
+ for error in errors:
+ description_content += f"`{error['code']}`: {error['message']}\n"
+ message = generate_error_message(
+ description=description_content,
+ emote=":x:"
+ )
+
+ await ctx.send(message)
+
+
+def setup(bot: KingArthur) -> None:
+ """Add the extension to the bot."""
+ bot.add_cog(Zones(bot))
diff --git a/arthur/exts/kubernetes/deployments.py b/arthur/exts/kubernetes/deployments.py
index dccf676..c41db32 100644
--- a/arthur/exts/kubernetes/deployments.py
+++ b/arthur/exts/kubernetes/deployments.py
@@ -134,7 +134,7 @@ class Deployments(commands.Cog):
content=generate_error_message(
description="Could not find deployment, check the namespace.",
),
- ephemeral=False
+ ephemeral=False,
)
return await interaction.respond(
@@ -150,7 +150,7 @@ class Deployments(commands.Cog):
)
await interaction.respond(
content=description,
- ephemeral=False,
+ ephemeral=False
)
for component in components.components: