irctest/irctest/controllers/anope_services.py

154 lines
3.9 KiB
Python

import functools
from pathlib import Path
import shutil
import subprocess
from typing import Tuple, Type
from irctest.basecontrollers import BaseServicesController, DirectoryBasedController
TEMPLATE_CONFIG = """
serverinfo {{
name = "services.example.org"
description = "Anope IRC Services"
numeric = "00A"
pid = "services.pid"
motd = "conf/empty_file"
}}
uplink {{
host = "{server_hostname}"
port = {server_port}
password = "password"
}}
module {{
name = "{protocol}"
}}
networkinfo {{
networkname = "testnet"
nicklen = 31
userlen = 10
hostlen = 64
chanlen = 32
}}
mail {{
usemail = no
}}
service {{
nick = "NickServ"
user = "services"
host = "services.host"
gecos = "Nickname Registration Service"
}}
module {{
name = "nickserv"
client = "NickServ"
forceemail = no
passlen = 1000 # Some tests need long passwords
maxpasslen = 1000
minpasslen = 1
}}
command {{ service = "NickServ"; name = "HELP"; command = "generic/help"; }}
module {{
name = "ns_register"
registration = "none"
}}
command {{ service = "NickServ"; name = "REGISTER"; command = "nickserv/register"; }}
options {{
casemap = "ascii"
readtimeout = 5s
warningtimeout = 4h
}}
module {{ name = "{module_prefix}sasl" }}
module {{ name = "enc_bcrypt" }}
module {{ name = "ns_cert" }}
"""
@functools.lru_cache()
def installed_version() -> Tuple[int, ...]:
output = subprocess.run(
["anope", "--version"], stdout=subprocess.PIPE, universal_newlines=True
).stdout
(anope, version, *trailing) = output.split()[0].split("-")
assert anope == "Anope"
return tuple(map(int, version.split(".")))
class AnopeController(BaseServicesController, DirectoryBasedController):
"""Collaborator for server controllers that rely on Anope"""
software_name = "Anope"
software_version = None
def run(self, protocol: str, server_hostname: str, server_port: int) -> None:
self.create_config()
assert protocol in (
"bahamut",
"inspircd3",
"charybdis",
"hybrid",
"plexus",
"unreal4",
"ngircd",
)
assert self.directory
services_path = shutil.which("anope")
assert services_path
# Rewrite Anope 2.0 module names for 2.1
if not self.software_version:
self.software_version = installed_version()
if self.software_version >= (2, 1, 0):
if protocol == "charybdis":
protocol = "solanum"
elif protocol == "inspircd3":
protocol = "inspircd"
elif protocol == "unreal4":
protocol = "unrealircd"
with self.open_file("conf/services.conf") as fd:
fd.write(
TEMPLATE_CONFIG.format(
protocol=protocol,
server_hostname=server_hostname,
server_port=server_port,
module_prefix="" if self.software_version >= (2, 1, 2) else "m_",
)
)
with self.open_file("conf/empty_file") as fd:
pass
# Config and code need to be in the same directory, *obviously*
(self.directory / "lib").symlink_to(Path(services_path).parent.parent / "lib")
(self.directory / "modules").symlink_to(
Path(services_path).parent.parent / "modules"
)
self.proc = subprocess.Popen(
[
"anope",
"--config=services.conf", # can't be an absolute path in 2.0
"--nofork", # don't fork
"--nopid", # don't write a pid
],
cwd=self.directory,
# stdout=subprocess.DEVNULL,
# stderr=subprocess.DEVNULL,
)
def get_irctest_controller_class() -> Type[AnopeController]:
return AnopeController