aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arthur/apis/kubernetes/jobs.py32
-rw-r--r--arthur/bot.py1
-rw-r--r--arthur/exts/kubernetes/jobs.py81
3 files changed, 114 insertions, 0 deletions
diff --git a/arthur/apis/kubernetes/jobs.py b/arthur/apis/kubernetes/jobs.py
new file mode 100644
index 0000000..c079da0
--- /dev/null
+++ b/arthur/apis/kubernetes/jobs.py
@@ -0,0 +1,32 @@
+"""APIs for interacting with Kubernetes Jobs & Cronjobs."""
+from typing import Any, Optional
+
+from kubernetes_asyncio import client
+from kubernetes_asyncio.client.api_client import ApiClient
+from kubernetes_asyncio.client.models import V1beta1CronJob, V1beta1CronJobList, V1Job
+
+
+async def list_cronjobs(namespace: Optional[str] = None) -> V1beta1CronJobList:
+ """Query the Kubernetes API for a list of cronjobss in the provided namespace."""
+ async with ApiClient() as api:
+ api = client.BatchV1beta1Api(api)
+ if namespace:
+ return await api.list_namespaced_cron_job(namespace)
+ else:
+ return await api.list_cron_job_for_all_namespaces()
+
+
+async def get_cronjob(namespace: str, cronjob_name: str) -> V1beta1CronJob:
+ """Fetch a cronjob given the name and namespace."""
+ async with ApiClient() as api:
+ api = client.BatchV1beta1Api(api)
+ return await api.read_namespaced_cron_job(cronjob_name, namespace)
+
+
+async def create_job(namespace: str, job_name: str, cron_spec: dict[str, Any]) -> V1Job:
+ """Create a job in the specified namespace with the given specification and name."""
+ async with ApiClient() as api:
+ api = client.BatchV1Api(api)
+ return await api.create_namespaced_job(
+ namespace, V1Job(metadata={"name": job_name}, spec=cron_spec)
+ )
diff --git a/arthur/bot.py b/arthur/bot.py
index 05da078..5ba93a5 100644
--- a/arthur/bot.py
+++ b/arthur/bot.py
@@ -75,6 +75,7 @@ class KingArthur(Bot):
logger.info("Loaded <red>jishaku</red>")
async def is_owner(self, user: Union[User, Member]) -> bool:
+ """Check if the invoker is a bot owner."""
if not user.guild_id:
return False
diff --git a/arthur/exts/kubernetes/jobs.py b/arthur/exts/kubernetes/jobs.py
new file mode 100644
index 0000000..6f7a1fe
--- /dev/null
+++ b/arthur/exts/kubernetes/jobs.py
@@ -0,0 +1,81 @@
+"""The zones cog helps with managing Cloudflare zones."""
+import discord
+from discord.ext import commands
+from kubernetes_asyncio.client.models import V1beta1CronJobList
+
+from arthur.apis.kubernetes import jobs
+from arthur.bot import KingArthur
+from arthur.config import CONFIG
+
+# from arthur.utils import generate_error_message
+
+
+class CronJobView(discord.ui.View):
+ """This view allows users to select and trigger a CronJob."""
+
+ def __init__(self, cron_jobs: V1beta1CronJobList) -> None:
+ super().__init__()
+
+ self.cron_jobs = cron_jobs
+
+ for cron_job in self.cron_jobs.items:
+ cj = cron_job.metadata.name
+ ns = cron_job.metadata.namespace
+ self.children[0].add_option(
+ label=cron_job.metadata.name, value=f"{ns}/{cj}", description=ns, emoji="🛠️"
+ )
+
+ def disable_select(self) -> None:
+ """Disable the select button."""
+ self.children[0].disabled = True
+
+ async def interaction_check(self, interaction: discord.Interaction) -> bool:
+ """Ensure the user has the DevOps role."""
+ return CONFIG.devops_role in [r.id for r in interaction.user.roles]
+
+ @discord.ui.select(
+ placeholder="Select a CronJob to trigger...",
+ )
+ async def select_job(
+ self, dropdown: discord.ui.Select, interaction: discord.Interaction
+ ) -> None:
+ """Drop down menu contains the list of cronjobsb."""
+ cronjob_namespace, cronjob_name = dropdown.values[0].split("/")
+
+ cronjob = await jobs.get_cronjob(cronjob_namespace, cronjob_name)
+
+ new_job = await jobs.create_job(
+ cronjob_namespace,
+ f"{cronjob_name}-{interaction.message.id}",
+ cronjob.spec.job_template.spec,
+ )
+
+ self.disable_select()
+
+ await interaction.message.edit(view=self)
+ await interaction.response.send_message(f"🌬️ Spawned job `{new_job.metadata.name}`")
+
+
+class Jobs(commands.Cog):
+ """Commands for working with Kubernetes Jobs & CronJobs."""
+
+ def __init__(self, bot: KingArthur) -> None:
+ self.bot = bot
+
+ @commands.group(name="cronjob", aliases=["cronjobs", "cj"], invoke_without_command=True)
+ async def cronjob(self, ctx: commands.Context) -> None:
+ """Commands for working with Kubernetes CronJobs."""
+ await ctx.send_help(ctx.command)
+
+ @cronjob.command(name="trigger")
+ async def trigger(self, ctx: commands.Context) -> None:
+ """Command to trigger a Kubernetes cronjob now."""
+ cronjobs = await jobs.list_cronjobs()
+
+ view = CronJobView(cronjobs)
+ await ctx.send(":tools: Pick a CronJob to trigger", view=view)
+
+
+def setup(bot: KingArthur) -> None:
+ """Add the extension to the bot."""
+ bot.add_cog(Jobs(bot))