async def _exec_nix_store_transfer_db( src: ChildProcess, src_nix_store: Command, src_fd: FileDescriptor, closure: t.Sequence[t.Union[str, os.PathLike]], dest: ChildProcess, dest_nix_store: Command, dest_fd: FileDescriptor, ) -> None: "Exec nix-store to copy the Nix database for a closure between two stores" await dest.task.inherit_fd(dest_fd).dup2(dest.stdin) await dest_fd.close() dest_child = await dest.exec(dest_nix_store.args("--load-db").env({'NIX_REMOTE': ''})) await src.task.inherit_fd(src_fd).dup2(src.stdout) await src_fd.close() src_child = await src.exec(src_nix_store.args("--dump-db", *closure)) await src_child.check() await dest_child.check()
async def _exec_nix_store_import_export( src: ChildProcess, src_nix_store: Command, src_fd: FileDescriptor, closure: t.Sequence[t.Union[str, os.PathLike]], dest: ChildProcess, dest_nix_store: Command, dest_fd: FileDescriptor, ) -> None: "Exec nix-store to copy a closure of paths between two stores" await dest.task.inherit_fd(dest_fd).dup2(dest.stdin) await dest_fd.close() dest_child = await dest.exec(dest_nix_store.args("--import").env({'NIX_REMOTE': ''})) await src.task.inherit_fd(src_fd).dup2(src.stdout) await src_fd.close() src_child = await src.exec(src_nix_store.args("--export", *closure)) await src_child.check() await dest_child.check()
async def start_recursor(nursery, parent: Thread, path: Path, ipv4_sockets: t.List[t.Tuple[handle.FileDescriptor, handle.FileDescriptor]], ipv6_sockets: t.List[t.Tuple[handle.FileDescriptor, handle.FileDescriptor]], root_hints: dns.zone.Zone=None) -> Powerdns: pdns_recursor = Command(Path("/home/sbaugh/.local/src/pdns/pdns/recursordist/pdns_recursor"), ['pdns_recursor'], {}) thread = await parent.fork() ipv4s = {str(i+1): (udp.move(thread.task), tcp.move(thread.task)) for i, (udp, tcp) in enumerate(ipv4_sockets)} ipv6s = {"::"+str(i+1): (udp.move(thread.task), tcp.move(thread.task)) for i, (udp, tcp) in enumerate(ipv6_sockets)} addresses = {**ipv4s, **ipv6s} await thread.unshare_files(going_to_exec=True) config = { "config-dir": os.fsdecode(path), "socket-dir": os.fsdecode(path), # more logging "loglevel": "9", "log-common-errors": "yes", "quiet": "no", "trace": "yes", "dont-query": "", "logging-facility": "0", # relevant stuff "local-address": ",".join(addresses), "allow-from": "127.0.0.0/8", "local-address-udp-fds": ",".join([f"{i}={await fd.as_argument()}" for i, (fd, _) in addresses.items()]), "local-address-tcp-fds": ",".join([f"{i}={await fd.as_argument()}" for i, (_, fd) in addresses.items()]), } if root_hints is not None: config["hint-file"] = os.fsdecode(await thread.spit(path/'root.hints', root_hints.to_text())) child = await thread.exec(pdns_recursor.args(*[f"--{name}={value}" for name, value in config.items()])) nursery.start_soon(child.check) return Powerdns()
async def exec_nix_store_transfer_db( src: ChildThread, src_nix_store: Command, src_fd: FileDescriptor, closure: t.List[Path], dest: ChildThread, dest_nix_store: Command, dest_fd: FileDescriptor, ) -> None: "Exec nix-store to copy the Nix database for a closure between two stores" await dest.unshare_files_and_replace({ dest.stdin: dest_fd, }) await dest_fd.close() dest_child = await dest.exec( dest_nix_store.args("--load-db").env({'NIX_REMOTE': ''})) await src.unshare_files_and_replace({ src.stdout: src_fd, }) await src_fd.close() src_child = await src.exec(src_nix_store.args("--dump-db", *closure)) await src_child.check() await dest_child.check()
async def exec_nix_store_import_export( src: ChildThread, src_nix_store: Command, src_fd: FileDescriptor, closure: t.List[Path], dest: ChildThread, dest_nix_store: Command, dest_fd: FileDescriptor, ) -> None: "Exec nix-store to copy a closure of paths between two stores" await dest.unshare_files_and_replace({ dest.stdin: dest_fd, }) await dest_fd.close() dest_child = await dest.exec( dest_nix_store.args("--import").env({'NIX_REMOTE': ''})) await src.unshare_files_and_replace({ src.stdout: src_fd, }) await src_fd.close() src_child = await src.exec(src_nix_store.args("--export", *closure)) await src_child.check() await dest_child.check()
async def start_powerdns(nursery, parent: Thread, path: Path, zone: dns.zone.Zone, # tuple is (udpfd, listening tcpfd) ipv4_sockets: t.List[t.Tuple[handle.FileDescriptor, handle.FileDescriptor]], ipv6_sockets: t.List[t.Tuple[handle.FileDescriptor, handle.FileDescriptor]], ) -> Powerdns: pdns_server = Command(Path("/home/sbaugh/.local/src/pdns/pdns/pdns_server"), ['pdns_server'], {}) # pdns_server = await parent.environ.which("pdns_server") thread = await parent.fork() # we pretend to pass addresses like 0.0.0.1 etc # we add one so we don't pass 0.0.0.0 and make powerdns think it's bound to everything ipv4s = {str(i+1): (udp.move(thread.task), tcp.move(thread.task)) for i, (udp, tcp) in enumerate(ipv4_sockets)} ipv6s = {str(i+1): (udp.move(thread.task), tcp.move(thread.task)) for i, (udp, tcp) in enumerate(ipv6_sockets)} await thread.unshare_files(going_to_exec=True) config = { "config-dir": os.fsdecode(path), # TODO control-console seems to be a feature where it will listen on stdin or something? # we should use that instead of this socketdir "socket-dir": os.fsdecode(path), # more logging "loglevel": "9", "log-dns-queries": "yes", # backend "launch": "bind", "bind-config": os.fsdecode(await thread.spit(path/"named.conf", 'zone "%s" { file "%s"; };' % ( zone.origin.to_text(), os.fsdecode(await thread.spit(path/"zone", zone.to_text()))))), "enable-lua-records": "yes", # relevant stuff "local-address": ",".join(ipv4s), "local-address-udp-fds": ",".join([f"{i}={await fd.as_argument()}" for i, (fd, _) in ipv4s.items()]), "local-address-tcp-fds": ",".join([f"{i}={await fd.as_argument()}" for i, (_, fd) in ipv4s.items()]), "local-ipv6": ",".join(ipv6s), "local-ipv6-udp-fds": ",".join([f"{i}={await fd.as_argument()}" for i, (fd, _) in ipv6s.items()]), "local-ipv6-tcp-fds": ",".join([f"{i}={await fd.as_argument()}" for i, (_, fd) in ipv6s.items()]), } print(config['local-address-udp-fds']) child = await thread.exec(pdns_server.args(*[f"--{name}={value}" for name, value in config.items()])) nursery.start_soon(child.check) return Powerdns()
class TestMail(TrioTestCase): async def asyncSetUp(self) -> None: self.process = local.process self.tmpdir = await self.process.mkdtemp("test_mail") self.path = self.tmpdir.path await update_symlink( self.process, await self.process.ram.ptr(self.tmpdir.parent / "test_mail.current"), self.path) smtp_sock = await self.process.task.socket(AF.INET, SOCK.STREAM) await smtp_sock.bind(await self.process.ram.ptr( SockaddrIn(3000, "127.0.0.1"))) await smtp_sock.listen(10) self.smtpd = await start_smtpd( self.nursery, self.process, await self.process.mkdir(self.path / "smtpd"), smtp_sock) self.maildir = await Maildir.make(self.process, self.path / "mail") self.dovecot = await start_dovecot( self.nursery, self.process, await self.process.mkdir(self.path / "dovecot"), self.smtpd.lmtp_listener, self.maildir) smtpctl = await self.process.environ.which("smtpctl") self.sendmail = Command(smtpctl.executable_path, [b'sendmail'], {'SMTPD_CONFIG_FILE': self.smtpd.config_file}) self.inty = await Inotify.make(self.process) async def asyncTearDown(self) -> None: await self.tmpdir.cleanup() async def send_email(self, from_: str, to: str, subject: str, msg: str) -> None: process = await self.process.fork() await process.unshare_files() fd = await process.task.memfd_create(await process.ram.ptr(Path('message'))) msg = f'From: {from_}\nSubject: {subject}\nTo: {to}\n\n' + msg await process.spit(fd, msg) await fd.lseek(0, SEEK.SET) await process.stdin.replace_with(fd) child = await process.exec(self.sendmail.args('-t')) await child.check() async def test_sendmail(self) -> None: watch = await self.inty.add(self.maildir.new(), IN.MOVED_TO) # TODO sigh, opensmtpd isn't validating the From field... from_ = 'from@localhost' to = 'sbaugh@localhost' subject = 'Subjective' msg = 'Hello me!\n' await self.send_email(from_, to, subject, msg) event = await watch.wait_until_event(IN.MOVED_TO) if event.name is None: raise Exception("event has no name??") mailfd = await self.process.task.open( await self.process.ram.ptr(self.maildir.new() / event.name), O.RDONLY) data = await self.process.read_to_eof(mailfd) message = email.message_from_bytes(data) self.assertEqual(from_, message['From']) self.assertEqual(to, message['To']) self.assertEqual(subject, message['Subject']) self.assertEqual(msg, message.get_payload()) # So I need to set up proper DNS stuff. # Which... I can do by running my own DNS server :) # aha, okay, so I could have a DNS server which, # automatically forwards the requests to the NS server in the record async def test_mail_tester(self) -> None: from_ = '*****@*****.**' to = '*****@*****.**' subject = 'Subjective' msg = 'Hello me!\n' await self.send_email(from_, to, subject, msg) await trio.sleep(9999)