aboutsummaryrefslogtreecommitdiffstats
path: root/arthur
diff options
context:
space:
mode:
authorGravatar Joe Banks <[email protected]>2021-07-27 23:18:35 +0100
committerGravatar Joe Banks <[email protected]>2021-07-27 23:18:35 +0100
commit304ae1893888c011935390a60ee6a24607142623 (patch)
tree91978dce41873afb5069108cbbe1353df1b66b2e /arthur
parentMerge pull request #2 from doublevcodes/main (diff)
Migrate to discord.py v2.0
Diffstat (limited to 'arthur')
-rw-r--r--arthur/apis/cloudflare/zones.py8
-rw-r--r--arthur/bot.py4
-rw-r--r--arthur/exts/cloudflare/zones.py9
-rw-r--r--arthur/exts/error_handler/error_handler.py3
-rw-r--r--arthur/exts/kubernetes/deployments.py137
5 files changed, 77 insertions, 84 deletions
diff --git a/arthur/apis/cloudflare/zones.py b/arthur/apis/cloudflare/zones.py
index 7debfd1..81a54f1 100644
--- a/arthur/apis/cloudflare/zones.py
+++ b/arthur/apis/cloudflare/zones.py
@@ -5,9 +5,7 @@ import aiohttp
from arthur.config import CONFIG
-AUTH_HEADER = {
- "Authorization": f"Bearer {CONFIG.cloudflare_token}"
-}
+AUTH_HEADER = {"Authorization": f"Bearer {CONFIG.cloudflare_token}"}
async def list_zones(zone_name: Optional[str] = None) -> dict[str, str]:
@@ -30,9 +28,7 @@ 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
- }
+ request_body = {"purge_everything": True}
async with aiohttp.ClientSession() as session:
async with session.post(endpoint, headers=AUTH_HEADER, json=request_body) as response:
diff --git a/arthur/bot.py b/arthur/bot.py
index cda66b1..249ada7 100644
--- a/arthur/bot.py
+++ b/arthur/bot.py
@@ -4,7 +4,6 @@ from typing import Any
from discord.ext import commands
from discord.ext.commands import Bot
-from discord_components import DiscordComponents
from kubernetes_asyncio import config
from arthur import logger
@@ -40,9 +39,6 @@ class KingArthur(Bot):
async def on_ready(self) -> None:
"""Initialise bot once connected and authorised with Discord."""
- # Initialise components (e.g. buttons, selections)
- DiscordComponents(self)
-
# Authenticate with Kubernetes
if (Path.home() / ".kube/config").exists():
await config.load_kube_config()
diff --git a/arthur/exts/cloudflare/zones.py b/arthur/exts/cloudflare/zones.py
index 564dd2e..457efc5 100644
--- a/arthur/exts/cloudflare/zones.py
+++ b/arthur/exts/cloudflare/zones.py
@@ -21,9 +21,7 @@ class Zones(commands.Cog):
@zones.command(name="purge")
async def purge(
- self,
- ctx: commands.Context,
- zone_name: Optional[str] = "pythondiscord.com"
+ 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)
@@ -38,10 +36,7 @@ class Zones(commands.Cog):
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:"
- )
+ message = generate_error_message(description=description_content, emote=":x:")
await ctx.send(message)
diff --git a/arthur/exts/error_handler/error_handler.py b/arthur/exts/error_handler/error_handler.py
index 2a61f40..673fbc7 100644
--- a/arthur/exts/error_handler/error_handler.py
+++ b/arthur/exts/error_handler/error_handler.py
@@ -49,8 +49,7 @@ class ErrorHandler(Cog):
await ctx.send(
generate_error_message(
description=(
- f"Unknown exception occurred: `{error.__class__.__name__}:"
- f" {error}`"
+ f"Unknown exception occurred: `{error.__class__.__name__}:" f" {error}`"
)
)
)
diff --git a/arthur/exts/kubernetes/deployments.py b/arthur/exts/kubernetes/deployments.py
index c41db32..0322b4d 100644
--- a/arthur/exts/kubernetes/deployments.py
+++ b/arthur/exts/kubernetes/deployments.py
@@ -1,9 +1,8 @@
"""The Deployments cog helps with managing Kubernetes deployments."""
-import asyncio
from textwrap import dedent
+from discord import ButtonStyle, Interaction, ui
from discord.ext import commands
-from discord_components.component import ActionRow, Button, ButtonStyle
from kubernetes_asyncio.client.models import V1Deployment
from kubernetes_asyncio.client.rest import ApiException
from tabulate import tabulate
@@ -13,6 +12,69 @@ from arthur.bot import KingArthur
from arthur.utils import generate_error_message
+class ConfirmDeployment(ui.View):
+ """A confirmation view for redeploying to Kubernetes."""
+
+ def __init__(self, author_id: int, deployment_ns: tuple[str, str]) -> None:
+ super().__init__()
+ self.confirmed = None
+ self.interaction = None
+ self.authorization = author_id
+ self.deployment = deployment_ns[1]
+ self.namespace = deployment_ns[0]
+
+ async def interaction_check(self, interaction: Interaction) -> bool:
+ """Check the interactor is authorised."""
+ if interaction.user.id == self.authorization:
+ return True
+
+ await interaction.response.send_message(
+ generate_error_message(description="You are not authorized to perform this action."),
+ ephemeral=True,
+ )
+
+ return False
+
+ @ui.button(label="Confirm", style=ButtonStyle.green, row=0)
+ async def confirm(self, _button: ui.Button, interaction: Interaction) -> None:
+ """Redeploy the specified service."""
+ try:
+ await deployments.restart_deployment(self.deployment, self.namespace)
+ except ApiException as e:
+ if e.status == 404:
+ return await interaction.response.send_message(
+ content=generate_error_message(
+ description="Could not find deployment, check the namespace.",
+ ),
+ ephemeral=False,
+ )
+
+ await interaction.response.send_message(
+ content=generate_error_message(
+ description=f"Unexpected error occurred, error code {e.status}"
+ ),
+ ephemeral=False,
+ )
+ else:
+ description = (
+ f":white_check_mark: Restarted deployment "
+ f"`{self.deployment}` in namespace `{self.namespace}`."
+ )
+
+ await interaction.response.send_message(content=description, ephemeral=False)
+
+ self.stop()
+
+ @ui.button(label="Cancel", style=ButtonStyle.grey, row=0)
+ async def cancel(self, _button: ui.Button, interaction: Interaction) -> None:
+ """Logic for if the deployment is not approved."""
+ await interaction.response.send_message(
+ content=":x: Redeployment aborted",
+ ephemeral=False,
+ )
+ self.stop()
+
+
def deployment_to_emote(deployment: V1Deployment) -> str:
"""Convert a deployment to an emote based on it's replica status."""
if deployment.status.available_replicas == deployment.spec.replicas:
@@ -83,80 +145,25 @@ class Deployments(commands.Cog):
self, ctx: commands.Context, deployment: str, namespace: str = "default"
) -> None:
"""Restart the specified deployment in the selected namespace (defaults to default)."""
- components = ActionRow(
- Button(
- label="Redeploy",
- style=ButtonStyle.green,
- custom_id=f"{ctx.message.id}-redeploy",
- ),
- Button(
- label="Abort",
- style=ButtonStyle.red,
- custom_id=f"{ctx.message.id}-abort",
- ),
- )
+ confirmation = ConfirmDeployment(ctx.author.id, [namespace, deployment])
msg = await ctx.send(
f":warning: Please confirm you want to restart `deploy/{deployment}` in `{namespace}`",
- components=[components],
+ view=confirmation,
)
- try:
- interaction = await self.bot.wait_for(
- "button_click",
- check=lambda i: i.component.custom_id.startswith(str(ctx.message.id))
- and i.user.id == ctx.author.id,
- timeout=30,
- )
- except asyncio.TimeoutError:
- return await msg.edit(
- generate_error_message(
+ timed_out = await confirmation.wait()
+
+ if timed_out:
+ await msg.edit(
+ content=generate_error_message(
title="What is the airspeed velocity of an unladen swallow?",
description=(
"Whatever the answer may be, it's certainly "
"faster than you could select a confirmation option."
),
- ),
- components=[],
- )
-
- if interaction.component.custom_id == f"{ctx.message.id}-abort":
- await interaction.respond(
- content=":x: Redeployment aborted",
- ephemeral=False,
- )
- else:
- try:
- await deployments.restart_deployment(deployment, namespace)
- except ApiException as e:
- if e.status == 404:
- return await interaction.respond(
- content=generate_error_message(
- description="Could not find deployment, check the namespace.",
- ),
- ephemeral=False,
- )
-
- return await interaction.respond(
- content=generate_error_message(
- description=f"Unexpected error occurred, error code {e.status}"
- ),
- ephemeral=False
- )
- else:
- description = (
- f":white_check_mark: Restarted deployment "
- f"`{deployment}` in namespace `{namespace}`."
- )
- await interaction.respond(
- content=description,
- ephemeral=False
)
-
- for component in components.components:
- component.disabled = True
-
- await msg.edit(components=[components])
+ )
def setup(bot: KingArthur) -> None: