diff options
author | 2021-07-27 23:31:29 +0100 | |
---|---|---|
committer | 2021-07-27 23:31:29 +0100 | |
commit | 46aff6c262c3f8ec8ff54db6b32f31b5ec97ef7e (patch) | |
tree | 1c4775a8bee693f56e6ef07eab3b2aa332814a87 | |
parent | remove quotes from black profile (diff) | |
parent | Migrate to discord.py v2.0 (diff) |
Merge branch 'main' into patch-1
-rw-r--r-- | arthur/apis/cloudflare/zones.py | 8 | ||||
-rw-r--r-- | arthur/bot.py | 4 | ||||
-rw-r--r-- | arthur/exts/cloudflare/zones.py | 9 | ||||
-rw-r--r-- | arthur/exts/error_handler/error_handler.py | 3 | ||||
-rw-r--r-- | arthur/exts/kubernetes/deployments.py | 137 | ||||
-rw-r--r-- | poetry.lock | 76 | ||||
-rw-r--r-- | pyproject.toml | 3 |
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" |