1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
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))
|