diff options
Diffstat (limited to 'arthur')
| -rw-r--r-- | arthur/exts/grafana/team_sync.py | 89 | 
1 files changed, 89 insertions, 0 deletions
diff --git a/arthur/exts/grafana/team_sync.py b/arthur/exts/grafana/team_sync.py new file mode 100644 index 0000000..501f891 --- /dev/null +++ b/arthur/exts/grafana/team_sync.py @@ -0,0 +1,89 @@ +import aiohttp +import discord +from discord.ext import commands, tasks + +from arthur import logger +from arthur.apis import github, grafana +from arthur.bot import KingArthur + + +class GrafanaTeamSync(commands.Cog): +    """ +    Update Grafana team membership to match Github team membership. + +    Grafana team name must match Github team slug exactly. +    Use `gh api orgs/{org-name}/teams` to get a list of teams in an org +    """ + +    def __init__(self, bot: KingArthur) -> None: +        self.bot = bot +        self.sync_github_grafana_teams.start() + +    async def _sync_teams(self, team: dict[str, str]) -> tuple[int, int]: +        """ +        Ensure members in github are present in grafana teams. + +        Return the number of members missing from teh grafana team, and the number of members added. +        """ +        github_team_members = { +            member["login"] +            for member in await github.list_team_members(team["name"], self.bot.http_session) +        } +        grafana_team_members = { +            member["login"] +            for member in await grafana.list_team_members(team["id"], self.bot.http_session) +            if member.get("auth_module") == "oauth_github" +        } + +        missing_members = github_team_members - grafana_team_members +        grafana_users = await grafana.get_all_users(self.bot.http_session) +        added_members = set() +        for grafana_user in grafana_users: +            if grafana_user["login"] not in missing_members: +                continue +            await grafana.add_user_to_team( +                grafana_user["userId"], +                team["id"], +                self.bot.http_session, +            ) +            added_members.add(grafana_user["login"]) +        return len(missing_members), len(added_members) + +    @tasks.loop(hours=12) +    async def sync_github_grafana_teams(self, channel: discord.TextChannel | None = None) -> None: +        """Update Grafana team membership to match Github team membership.""" +        grafana_teams = await grafana.list_teams(self.bot.http_session) +        for team in grafana_teams: +            logger.debug(f"Processing {team['name']}") +            try: +                missing, added = await self._sync_teams(team) +            except aiohttp.ClientResponseError as e: +                logger.error(e) +                if channel: +                    await channel.send(e) +                continue + +            if channel and missing: +                await channel.send( +                    f"Found {missing} users not in the {team['name']} grafana team, added {added} of them." +                ) + +    @sync_github_grafana_teams.error +    async def on_task_error(self, error: Exception) -> None: +        """Ensure task errors are output.""" +        logger.error(error) + +    @commands.group(name="grafana", aliases=("graf",), invoke_without_command=True) +    async def grafana_group(self, ctx: commands.Context) -> None: +        """Commands for working with grafana API.""" +        await ctx.send_help(ctx.command) + +    @grafana_group.command(name="sync") +    async def sync_teams(self, ctx: commands.Context) -> None: +        """Sync Grafana & Github teams now.""" +        await self.sync_github_grafana_teams(ctx.channel) + + +async def setup(bot: KingArthur) -> None: +    """Add cog to bot.""" +    await bot.add_cog(GrafanaTeamSync(bot))  |