diff options
| author | 2021-07-27 23:18:35 +0100 | |
|---|---|---|
| committer | 2021-07-27 23:18:35 +0100 | |
| commit | 304ae1893888c011935390a60ee6a24607142623 (patch) | |
| tree | 91978dce41873afb5069108cbbe1353df1b66b2e | |
| parent | Merge pull request #2 from doublevcodes/main (diff) | |
Migrate to discord.py v2.0
| -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"  |