chore: Abstract machines and modules
All checks were successful
Check workflows / check_workflows (push) Successful in 21s
Run pre-commit on all files / check (push) Successful in 24s
Check meta / check_dns (pull_request) Successful in 19s
Check meta / check_meta (pull_request) Successful in 18s
Check workflows / check_workflows (pull_request) Successful in 19s
Build all the nodes / bridge01 (pull_request) Successful in 1m13s
Build all the nodes / geo01 (pull_request) Successful in 1m14s
Build all the nodes / compute01 (pull_request) Successful in 1m44s
Build all the nodes / geo02 (pull_request) Successful in 1m12s
Build all the nodes / rescue01 (pull_request) Successful in 1m30s
Build all the nodes / storage01 (pull_request) Successful in 1m29s
Build all the nodes / vault01 (pull_request) Successful in 1m26s
Build all the nodes / web02 (pull_request) Successful in 1m19s
Run pre-commit on all files / check (pull_request) Successful in 24s
Build all the nodes / web01 (pull_request) Successful in 1m56s
Build all the nodes / web03 (pull_request) Successful in 1m25s

This adds subdirectories for the different types of systems, for the
modules and the machines
This commit is contained in:
Tom Hubrecht 2024-12-08 13:22:07 +01:00
parent c3f4e7ade6
commit ecbad0a638
Signed by: thubrecht
SSH key fingerprint: SHA256:r+nK/SIcWlJ0zFZJGHtlAoRwq1Rm+WcKAm5ADYMoQPc
264 changed files with 49 additions and 38 deletions

View file

@ -1 +0,0 @@
use nix

View file

@ -1,75 +0,0 @@
# Copyright :
# - Ryan Lahfa <ryan.lahfa@dgnum.eu> 2024
#
# Ce logiciel est un programme informatique servant à déployer des
# configurations de serveurs via NixOS.
#
# Ce logiciel est régi par la licence CeCILL soumise au droit français et
# respectant les principes de diffusion des logiciels libres. Vous pouvez
# utiliser, modifier et/ou redistribuer ce programme sous les conditions
# de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
# sur le site "http://www.cecill.info".
#
# En contrepartie de l'accessibilité au code source et des droits de copie,
# de modification et de redistribution accordés par cette licence, il n'est
# offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons,
# seule une responsabilité restreinte pèse sur l'auteur du programme, le
# titulaire des droits patrimoniaux et les concédants successifs.
#
# A cet égard l'attention de l'utilisateur est attirée sur les risques
# associés au chargement, à l'utilisation, à la modification et/ou au
# développement et à la reproduction du logiciel par l'utilisateur étant
# donné sa spécificité de logiciel libre, qui peut le rendre complexe à
# manipuler et qui le réserve donc à des développeurs et des professionnels
# avertis possédant des connaissances informatiques approfondies. Les
# utilisateurs sont donc invités à charger et tester l'adéquation du
# logiciel à leurs besoins dans des conditions permettant d'assurer la
# sécurité de leurs systèmes et ou de leurs données et, plus généralement,
# à l'utiliser et l'exploiter dans les mêmes conditions de sécurité.
#
# Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
# pris connaissance de la licence CeCILL, et que vous en avez accepté les
# termes.
{
config,
pkgs,
lib,
...
}:
let
cfg = config.dgn-chatops;
inherit (lib) mkEnableOption mkIf;
python3 = pkgs.python311;
python3Pkgs = python3.pkgs;
ircrobots = python3Pkgs.callPackage ./ircrobots.nix { };
tortoise-orm = python3Pkgs.callPackage ./tortoise-orm.nix { };
ps = python3Pkgs.makePythonPath [
ircrobots
tortoise-orm
python3Pkgs.aiohttp
];
in
{
options.dgn-chatops = {
enable = mkEnableOption "the ChatOps layer";
};
# Our ChatOps bot.
config = mkIf cfg.enable {
systemd.services.irc-takumi = {
description = "DGNum IRC automation bot, Takumi";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
environment = {
PYTHONPATH = ps;
};
serviceConfig = {
RuntimeDirectory = "takumi";
StateDirectory = "takumi";
DynamicUser = true;
ExecStart = "${lib.getExe python3} ${./takumi.py}";
};
};
};
}

View file

@ -1,56 +0,0 @@
{
lib,
buildPythonPackage,
fetchFromGitea,
pythonOlder,
anyio,
asyncio-rlock,
asyncio-throttle,
ircstates,
async-stagger,
async-timeout,
python,
}:
buildPythonPackage rec {
pname = "ircrobots";
version = "0.7.0";
format = "setuptools";
disabled = pythonOlder "3.7";
src = fetchFromGitea {
domain = "git.dgnum.eu";
owner = "DGNum";
repo = pname;
# No tag yet :(.
rev = "63aa84b40450bd534fc232eee10e8088028c9f6d";
hash = "sha256-gXiPy6wjPEtc9v0cG0lb2QVXDlU5Q8ncxJO0lBm2RSE=";
};
postPatch = ''
# too specific pins https://github.com/jesopo/ircrobots/issues/3
sed -iE 's/anyio.*/anyio/' requirements.txt
'';
propagatedBuildInputs = [
anyio
asyncio-rlock
asyncio-throttle
ircstates
async-stagger
async-timeout
];
checkPhase = ''
${python.interpreter} -m unittest test
'';
pythonImportsCheck = [ "ircrobots" ];
meta = with lib; {
description = "Asynchronous bare-bones IRC bot framework for python3";
license = licenses.mit;
homepage = "https://github.com/jesopo/ircrobots";
maintainers = with maintainers; [ hexa ];
};
}

View file

@ -1,31 +0,0 @@
{
lib,
buildPythonPackage,
fetchFromGitHub,
poetry-core,
}:
buildPythonPackage rec {
pname = "pypika-tortoise";
version = "0.1.6";
pyproject = true;
src = fetchFromGitHub {
owner = "tortoise";
repo = "pypika-tortoise";
rev = "v${version}";
hash = "sha256-xx5FUMHh6413fsvwrEA+Q0tBmJWy00h5O6YijvrJyCE=";
};
build-system = [ poetry-core ];
pythonImportsCheck = [ "pypika" ];
meta = {
description = "";
homepage = "https://github.com/tortoise/pypika-tortoise";
changelog = "https://github.com/tortoise/pypika-tortoise/blob/${src.rev}/CHANGELOG.md";
license = lib.licenses.asl20;
maintainers = with lib.maintainers; [ raitobezarius ];
};
}

View file

@ -1,20 +0,0 @@
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "takumi"
version = "1.1.0"
authors = [
{ name = "Ryan Lahfa", email = "ryan@dgnum.eu" },
]
description = "Fully automatic day-to-day operations at DGNum"
requires-python = ">=3.11"
classifiers = [
"Programming Language :: Python :: 3",
"Operating System :: OS Independent",
]
[project.urls]
Homepage = "https://git.dgnum.eu/DGNum/infrastructure"
Issues = "https://git.dgnum.eu/DGNum/infrastructure/issues"

View file

@ -1,29 +0,0 @@
{
pkgs ? import <nixpkgs> { },
python3 ? pkgs.python3,
}:
let
takumi = python3.pkgs.buildPythonPackage rec {
pname = "takumi";
version = "1.1.0";
pyproject = true;
src = ./.;
build-system = [ python3.pkgs.hatchling ];
dependencies = [
(python3.pkgs.callPackage ./ircrobots.nix { })
(python3.pkgs.callPackage ./tortoise-orm.nix { })
python3.pkgs.aiohttp
];
postInstall = ''
mkdir -p $out/bin
cp -v takumi.py $out/bin/takumi.py
chmod +x $out/bin/takumi.py
wrapProgram $out/bin/takumi.py --prefix PYTHONPATH : "$PYTHONPATH"
'';
};
in
pkgs.mkShell { packages = [ takumi ]; }

View file

@ -1,121 +0,0 @@
#!/usr/bin/env python3
import asyncio
from irctokens.line import build, Line
from ircrobots.bot import Bot as BaseBot
from ircrobots.server import Server as BaseServer
from ircrobots.params import ConnectionParams
import aiohttp
BRIDGE_NICKNAME = "hermes"
SERVERS = [
("dgnum", "irc.dgnum.eu")
]
TEAMS = {
"fai": ("tomate", "elias", "JeMaGius", "Luj", "catvayor", "Raito"),
"marketing": ("cst1", "elias"),
"bureau": ("Raito", "JeMaGius", "Luj", "gdd")
}
# times format is 0700-29092024
TRIGGER = '!'
async def create_meet(title: str, times: list[str], timezone: str = "UTC") -> str:
async with aiohttp.ClientSession() as session:
payload = {
'name': title,
'times': times,
'timezone': timezone
}
async with session.post('https://api.meet.dgnum.eu/event', json=payload) as response:
response.raise_for_status()
id = (await response.json()).get('id')
if not id:
raise RuntimeError('No ID attributed to a meet')
return f'https://meet.dgnum.eu/{id}'
def expand_times(times: list[str]) -> list[str]:
expanded = []
# TODO: verify the date exist in the calendar
# TODO: verify that we don't write any duplicates.
for time in times:
if '-' not in time:
for i in range(7, 20):
expanded.append(f'{i:02}00-{time}')
else:
expanded.append(time)
return expanded
def bridge_stripped(possible_command: str, origin_nick: str) -> str | None:
if origin_nick.lower() == BRIDGE_NICKNAME:
stripped_user = possible_command.split(':')[1].lstrip()
return stripped_user if stripped_user.startswith(TRIGGER) else None
else:
return possible_command if possible_command.startswith(TRIGGER) else None
class Server(BaseServer):
def extract_valid_command(self, line: Line) -> str | None:
me = self.nickname_lower
if line.command == "PRIVMSG" and \
self.has_channel(line.params[0]) and \
line.hostmask is not None and \
self.casefold(line.hostmask.nickname) != me and \
self.has_user(line.hostmask.nickname):
return bridge_stripped(line.params[1], line.hostmask.nickname)
async def line_read(self, line: Line):
print(f"{self.name} < {line.format()}")
if line.command == "001":
print(f"connected to {self.isupport.network}")
await self.send(build("JOIN", ["#dgnum-bridge-test"]))
# In case `!probe_meet <title> <team> <time_1> <time_2> … <time_N> [<timezone>]`
if (command := self.extract_valid_command(line)) is not None:
text = command.lstrip(TRIGGER)
if text.startswith('probe_meet') or text.startswith('pm'):
args = text.split(' ')
if len(args) < 4:
await self.send(build("PRIVMSG", [line.params[0], "usage is !probe_meet <title> <team> <time_1> [<time_2> <time_3> … <time_N>] ; time is in [00-hour-]DDMMYYYY format."]))
return
title, team = args[1], args[2]
print(f"creating meet '{title}' for team '{team}'")
try:
times = expand_times(args[3:])
link = await create_meet(title, times)
if team not in TEAMS:
await self.send(build("PRIVMSG", [line.params[0], f"team {team} does not exist"]))
return
targets = TEAMS[team]
ping_mentions = ', '.join(targets)
await self.send(build("PRIVMSG", [line.params[0], f'{ping_mentions} {link}']))
except ValueError as e:
print(e)
await self.send(build("PRIVMSG", [line.params[0], "time format is [00-hour-]DDMMYYYY, hour is optional, by default it's 07:00 to 19:00 in Europe/Paris timezone"]))
except aiohttp.ClientError as e:
print(e)
await self.send(build("PRIVMSG", [line.params[0], "failed to create the meet on meet.dgnum.eu, API error, check the logs"]))
async def line_send(self, line: Line):
print(f"{self.name} > {line.format()}")
class Bot(BaseBot):
def create_server(self, name: str):
return Server(self, name)
async def main():
bot = Bot()
for name, host in SERVERS:
# For IPv4-only connections.
params = ConnectionParams("Takumi", host, 6698)
await bot.add_server(name, params)
await bot.run()
if __name__ == "__main__":
asyncio.run(main())

View file

@ -1,71 +0,0 @@
{
lib,
buildPythonPackage,
fetchFromGitHub,
poetry-core,
aiosqlite,
iso8601,
callPackage,
pytz,
ciso8601,
orjson,
uvloop,
aiomysql,
asyncmy,
asyncpg,
psycopg,
pydantic,
pythonRelaxDepsHook,
}:
buildPythonPackage rec {
pname = "tortoise-orm";
version = "0.21.6";
pyproject = true;
src = fetchFromGitHub {
owner = "tortoise";
repo = "tortoise-orm";
rev = version;
hash = "sha256-Gu7MSJbPjaGUN6tmHwkmx7Bdy/+V1wZjmTCQrTDDPkw=";
};
buildInputs = [ pythonRelaxDepsHook ];
pythonRelaxDeps = [
"aiosqlite"
"iso8601"
];
build-system = [ poetry-core ];
dependencies = [
aiosqlite
iso8601
pydantic
(callPackage ./pypika-tortoise.nix { })
pytz
];
optional-dependencies = {
accel = [
ciso8601
orjson
uvloop
];
aiomysql = [ aiomysql ];
asyncmy = [ asyncmy ];
asyncpg = [ asyncpg ];
psycopg = [ psycopg ];
};
pythonImportsCheck = [ "tortoise" ];
meta = {
description = "";
homepage = "https://github.com/tortoise/tortoise-orm";
changelog = "https://github.com/tortoise/tortoise-orm/blob/${src.rev}/CHANGELOG.rst";
license = lib.licenses.asl20;
maintainers = with lib.maintainers; [ raitobezarius ];
};
}