aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Joe Banks <[email protected]>2021-07-27 23:31:29 +0100
committerGravatar GitHub <[email protected]>2021-07-27 23:31:29 +0100
commit46aff6c262c3f8ec8ff54db6b32f31b5ec97ef7e (patch)
tree1c4775a8bee693f56e6ef07eab3b2aa332814a87
parentremove quotes from black profile (diff)
parentMigrate to discord.py v2.0 (diff)
Merge branch 'main' into patch-1
-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
-rw-r--r--poetry.lock76
-rw-r--r--pyproject.toml3
7 files changed, 115 insertions, 125 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:
diff --git a/poetry.lock b/poetry.lock
index ceb2021..818e696 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -64,7 +64,7 @@ stevedore = ">=1.20.0"
[[package]]
name = "black"
-version = "21.6b0"
+version = "21.7b0"
description = "The uncompromising code formatter."
category = "dev"
optional = false
@@ -76,7 +76,7 @@ click = ">=7.1.2"
mypy-extensions = ">=0.4.3"
pathspec = ">=0.8.1,<1"
regex = ">=2020.1.8"
-toml = ">=0.10.1"
+tomli = ">=0.2.6,<2.0.0"
[package.extras]
colorama = ["colorama (>=0.4.3)"]
@@ -120,32 +120,24 @@ optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]]
-name = "discord-components"
-version = "1.1.2"
-description = "An unofficial library for discord components."
-category = "main"
-optional = false
-python-versions = ">=3.6"
-
-[package.dependencies]
-aiohttp = "*"
-"discord.py" = "*"
-
-[[package]]
name = "discord.py"
-version = "1.7.3"
+version = "2.0.0a0"
description = "A Python wrapper for the Discord API"
category = "main"
optional = false
-python-versions = ">=3.5.3"
+python-versions = ">=3.8.0"
[package.dependencies]
aiohttp = ">=3.6.0,<3.8.0"
[package.extras]
-docs = ["sphinx (==3.0.3)", "sphinxcontrib-trio (==1.1.2)", "sphinxcontrib-websupport"]
+docs = ["sphinx (==4.0.2)", "sphinxcontrib-trio (==1.1.2)", "sphinxcontrib-websupport"]
+speed = ["orjson (>=3.5.4)"]
voice = ["PyNaCl (>=1.3.0,<1.5)"]
+[package.source]
+type = "url"
+url = "https://github.com/Rapptz/discord.py/archive/master.zip"
[[package]]
name = "flake8"
version = "3.9.2"
@@ -236,7 +228,7 @@ smmap = ">=3.0.1,<5"
[[package]]
name = "gitpython"
-version = "3.1.18"
+version = "3.1.19"
description = "Python Git Library"
category = "dev"
optional = false
@@ -244,6 +236,7 @@ python-versions = ">=3.6"
[package.dependencies]
gitdb = ">=4.0.1,<5"
+typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.10\""}
[[package]]
name = "idna"
@@ -332,11 +325,11 @@ python-versions = "*"
[[package]]
name = "pathspec"
-version = "0.8.1"
+version = "0.9.0"
description = "Utility library for gitignore style pattern matching of file paths."
category = "dev"
optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
[[package]]
name = "pbr"
@@ -416,11 +409,11 @@ six = ">=1.5"
[[package]]
name = "python-dotenv"
-version = "0.18.0"
+version = "0.19.0"
description = "Read key-value pairs from a .env file and set them as environment variables"
category = "main"
optional = false
-python-versions = "*"
+python-versions = ">=3.5"
[package.extras]
cli = ["click (>=5.0)"]
@@ -526,6 +519,14 @@ optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]]
+name = "tomli"
+version = "1.1.0"
+description = "A lil' TOML parser"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[[package]]
name = "typing-extensions"
version = "3.10.0.0"
description = "Backported and Experimental Type Hints for Python 3.5+"
@@ -580,7 +581,7 @@ multidict = ">=4.0"
[metadata]
lock-version = "1.1"
python-versions = "^3.9"
-content-hash = "aa7e8d19f1fec00f12705f1148929edd306658d9caba57f07b5b4638e549ad22"
+content-hash = "0d475ddd5f16fbb32d7351985e92f291fc30e8774f22f9b9c78f1cf01ccf9162"
[metadata.files]
aiohttp = [
@@ -639,8 +640,8 @@ bandit = [
{file = "bandit-1.7.0.tar.gz", hash = "sha256:8a4c7415254d75df8ff3c3b15cfe9042ecee628a1e40b44c15a98890fbfc2608"},
]
black = [
- {file = "black-21.6b0-py3-none-any.whl", hash = "sha256:dfb8c5a069012b2ab1e972e7b908f5fb42b6bbabcba0a788b86dc05067c7d9c7"},
- {file = "black-21.6b0.tar.gz", hash = "sha256:dc132348a88d103016726fe360cb9ede02cecf99b76e3660ce6c596be132ce04"},
+ {file = "black-21.7b0-py3-none-any.whl", hash = "sha256:1c7aa6ada8ee864db745b22790a32f94b2795c253a75d6d9b5e439ff10d23116"},
+ {file = "black-21.7b0.tar.gz", hash = "sha256:c8373c6491de9362e39271630b65b964607bc5c79c83783547d76c839b3aa219"},
]
certifi = [
{file = "certifi-2021.5.30-py2.py3-none-any.whl", hash = "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"},
@@ -658,14 +659,7 @@ colorama = [
{file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
{file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
]
-discord-components = [
- {file = "discord_components-1.1.2-py3-none-any.whl", hash = "sha256:2fbe8dc21d67419bbb069e41d70698c81860e381b055fe2beb4b849a643270b7"},
- {file = "discord_components-1.1.2.tar.gz", hash = "sha256:d3be12457244a8f6a924bc6d34a135415813f7b9ee4592256fef86403bf99e00"},
-]
-"discord.py" = [
- {file = "discord.py-1.7.3-py3-none-any.whl", hash = "sha256:c6f64db136de0e18e090f6752ea68bdd4ab0a61b82dfe7acecefa22d6477bb0c"},
- {file = "discord.py-1.7.3.tar.gz", hash = "sha256:462cd0fe307aef8b29cbfa8dd613e548ae4b2cb581d46da9ac0d46fb6ea19408"},
-]
+"discord.py" = []
flake8 = [
{file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"},
{file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"},
@@ -694,8 +688,8 @@ gitdb = [
{file = "gitdb-4.0.7.tar.gz", hash = "sha256:96bf5c08b157a666fec41129e6d327235284cca4c81e92109260f353ba138005"},
]
gitpython = [
- {file = "GitPython-3.1.18-py3-none-any.whl", hash = "sha256:fce760879cd2aebd2991b3542876dc5c4a909b30c9d69dfc488e504a8db37ee8"},
- {file = "GitPython-3.1.18.tar.gz", hash = "sha256:b838a895977b45ab6f0cc926a9045c8d1c44e2b653c1fcc39fe91f42c6e8f05b"},
+ {file = "GitPython-3.1.19-py3-none-any.whl", hash = "sha256:17690588e36bd0cee21921ce621fad1e8be45a37afa486ff846fb8efcf53c34c"},
+ {file = "GitPython-3.1.19.tar.gz", hash = "sha256:18f4039b96b5567bc4745eb851737ce456a2d499cecd71e84f5c0950e92d0e53"},
]
idna = [
{file = "idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a"},
@@ -764,8 +758,8 @@ mypy-extensions = [
{file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
]
pathspec = [
- {file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"},
- {file = "pathspec-0.8.1.tar.gz", hash = "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd"},
+ {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"},
+ {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"},
]
pbr = [
{file = "pbr-5.6.0-py2.py3-none-any.whl", hash = "sha256:c68c661ac5cc81058ac94247278eeda6d2e6aecb3e227b0387c30d277e7ef8d4"},
@@ -842,8 +836,8 @@ python-dateutil = [
{file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
]
python-dotenv = [
- {file = "python-dotenv-0.18.0.tar.gz", hash = "sha256:effaac3c1e58d89b3ccb4d04a40dc7ad6e0275fda25fd75ae9d323e2465e202d"},
- {file = "python_dotenv-0.18.0-py2.py3-none-any.whl", hash = "sha256:dd8fe852847f4fbfadabf6183ddd4c824a9651f02d51714fa075c95561959c7d"},
+ {file = "python-dotenv-0.19.0.tar.gz", hash = "sha256:f521bc2ac9a8e03c736f62911605c5d83970021e3fa95b37d769e2bbbe9b6172"},
+ {file = "python_dotenv-0.19.0-py2.py3-none-any.whl", hash = "sha256:aae25dc1ebe97c420f50b81fb0e5c949659af713f31fdb63c749ca68748f34b1"},
]
pyyaml = [
{file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"},
@@ -951,6 +945,10 @@ toml = [
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
]
+tomli = [
+ {file = "tomli-1.1.0-py3-none-any.whl", hash = "sha256:f4a182048010e89cbec0ae4686b21f550a7f2903f665e34a6de58ec15424f919"},
+ {file = "tomli-1.1.0.tar.gz", hash = "sha256:33d7984738f8bb699c9b0a816eb646a8178a69eaa792d258486776a5d21b8ca5"},
+]
typing-extensions = [
{file = "typing_extensions-3.10.0.0-py2-none-any.whl", hash = "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497"},
{file = "typing_extensions-3.10.0.0-py3-none-any.whl", hash = "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"},
diff --git a/pyproject.toml b/pyproject.toml
index c17cccb..1405e14 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -7,12 +7,11 @@ license = "MIT"
[tool.poetry.dependencies]
python = "^3.9"
-"discord.py" = "^1.7.3"
-discord-components = "^1.1.2"
pydantic = {extras = ["dotenv"], version = "^1.8.2"}
loguru = "^0.5.3"
kubernetes_asyncio = "^12.1.1"
tabulate = {extras = ["widechars"], version = "^0.8.9"}
+"discord.py" = {url = "https://github.com/Rapptz/discord.py/archive/master.zip"}
[tool.poetry.dev-dependencies]
black = "^21.6b0"