diff --git a/clanModules/dino.nix b/clanModules/dino.nix new file mode 100644 index 000000000..0c75af7fe --- /dev/null +++ b/clanModules/dino.nix @@ -0,0 +1,3 @@ +{ pkgs, ... }: { + environment.systemPackages = [ pkgs.dino ]; +} diff --git a/clanModules/ejabberd.nix b/clanModules/ejabberd.nix new file mode 100644 index 000000000..d7197a34c --- /dev/null +++ b/clanModules/ejabberd.nix @@ -0,0 +1,199 @@ +{ config +, ... +}: { + services.ejabberd = { + enable = true; + configFile = "/etc/ejabberd.yml"; + }; + + environment.etc."ejabberd.yml" = { + user = "ejabberd"; + mode = "0600"; + text = '' + loglevel: 4 + + default_db: sql + new_sql_schema: true + sql_type: sqlite + sql_database: "/var/lib/ejabberd/db.sqlite" + + hosts: + - ${config.clanCore.machineName}.local + + listen: + - + port: 5222 + ip: "::1" + module: ejabberd_c2s + max_stanza_size: 262144 + shaper: c2s_shaper + access: c2s + starttls_required: false + - + port: 5269 + ip: "::" + module: ejabberd_s2s_in + max_stanza_size: 524288 + + auth_method: [anonymous] + anonymous_protocol: login_anon + acl: + local: + user_regexp: "" + loopback: + ip: + - 127.0.0.0/8 + - ::1/128 + access_rules: + local: + allow: local + c2s: + deny: blocked + allow: all + s2s: + - allow + announce: + allow: admin + configure: + allow: admin + muc_create: + allow: all + pubsub_createnode: + allow: local + trusted_network: + allow: loopback + api_permissions: + "console commands": + from: + - ejabberd_ctl + who: all + what: "*" + "admin access": + who: + access: + allow: + acl: loopback + acl: admin + oauth: + scope: "ejabberd:admin" + access: + allow: + acl: loopback + acl: admin + what: + - "*" + - "!stop" + - "!start" + "public commands": + who: + ip: 127.0.0.1/8 + what: + - status + - connected_users_number + shaper: + normal: 1000 + fast: 50000 + + shaper_rules: + max_user_sessions: 10 + max_user_offline_messages: + 5000: admin + 100: all + c2s_shaper: + none: admin + normal: all + s2s_shaper: fast + modules: + mod_adhoc: {} + mod_admin_extra: {} + mod_announce: + access: announce + mod_avatar: {} + mod_blocking: {} + mod_bosh: {} + mod_caps: {} + mod_carboncopy: {} + mod_client_state: {} + mod_configure: {} + mod_disco: {} + mod_fail2ban: {} + mod_http_api: {} + mod_http_upload: + put_url: https://@HOST@:5443/upload + mod_last: {} + mod_mam: + ## Mnesia is limited to 2GB, better to use an SQL backend + ## For small servers SQLite is a good fit and is very easy + ## to configure. Uncomment this when you have SQL configured: + ## db_type: sql + assume_mam_usage: true + default: always + mod_mqtt: + access_publish: + "homeassistant/#": + - allow: hass_publisher + - deny + "#": + - deny + access_subscribe: + "homeassistant/#": + - allow: hass_subscriber + - deny + "#": + - deny + mod_muc: + host: "muc.@HOST@" + access: + - allow + access_admin: + - allow: admin + access_create: muc_create + access_persistent: muc_create + access_mam: + - allow + default_room_options: + mam: true + mod_muc_admin: {} + mod_offline: + access_max_user_messages: max_user_offline_messages + mod_ping: {} + mod_privacy: {} + mod_private: {} + mod_proxy65: + access: local + max_connections: 5 + mod_pubsub: + access_createnode: pubsub_createnode + plugins: + - flat + - pep + force_node_config: + ## Avoid buggy clients to make their bookmarks public + storage:bookmarks: + access_model: whitelist + mod_push: {} + mod_push_keepalive: {} + mod_register: + ## Only accept registration requests from the "trusted" + ## network (see access_rules section above). + ## Think twice before enabling registration from any + ## address. See the Jabber SPAM Manifesto for details: + ## https://github.com/ge0rg/jabber-spam-fighting-manifesto + ip_access: trusted_network + mod_roster: + versioning: true + mod_s2s_dialback: {} + mod_shared_roster: {} + mod_stream_mgmt: + resend_on_timeout: if_offline + mod_vcard: {} + mod_vcard_xupdate: {} + mod_version: + show_os: false + ''; + }; + + networking.firewall.allowedTCPPorts = [ + 5269 # xmpp-server + ]; +} diff --git a/clanModules/flake-module.nix b/clanModules/flake-module.nix index 62505ef81..d273f1a09 100644 --- a/clanModules/flake-module.nix +++ b/clanModules/flake-module.nix @@ -8,5 +8,8 @@ ]; }) (builtins.readDir ./diskLayouts); + ejabberd = ./ejabberd.nix; + dino = ./dino.nix; + xfce = ./xfce.nix; }; } diff --git a/clanModules/xfce.nix b/clanModules/xfce.nix new file mode 100644 index 000000000..6c919c864 --- /dev/null +++ b/clanModules/xfce.nix @@ -0,0 +1,7 @@ +{ + services.xserver = { + enable = true; + desktopManager.xfce.enable = true; + layout = "us"; + }; +} diff --git a/pkgs/clan-cli/clan_cli/dirs.py b/pkgs/clan-cli/clan_cli/dirs.py index c70529613..89f16bd71 100644 --- a/pkgs/clan-cli/clan_cli/dirs.py +++ b/pkgs/clan-cli/clan_cli/dirs.py @@ -78,7 +78,7 @@ def clan_flakes_dir() -> Path: def specific_flake_dir(flake_name: FlakeName) -> Path: flake_dir = clan_flakes_dir() / flake_name if not flake_dir.exists(): - raise ClanError(f"Flake '{flake_name}' does not exist") + raise ClanError(f"Flake '{flake_name}' does not exist in {flake_dir}") return flake_dir diff --git a/pkgs/clan-cli/clan_cli/vms/create.py b/pkgs/clan-cli/clan_cli/vms/create.py index 31852dc7c..8a075e1e5 100644 --- a/pkgs/clan-cli/clan_cli/vms/create.py +++ b/pkgs/clan-cli/clan_cli/vms/create.py @@ -5,6 +5,7 @@ import os import re import shlex import sys +import tempfile from pathlib import Path from typing import Iterator from uuid import UUID @@ -76,103 +77,105 @@ class BuildVmTask(BaseTask): validate_path(clan_flakes_dir(), flake_dir) flake_dir.mkdir(exist_ok=True) - xchg_dir = flake_dir / "xchg" - xchg_dir.mkdir() - secrets_dir = flake_dir / "secrets" - secrets_dir.mkdir() - disk_img = f"{flake_dir}/disk.img" + with tempfile.TemporaryDirectory() as tmpdir_: + tmpdir = Path(tmpdir_) + xchg_dir = tmpdir / "xchg" + xchg_dir.mkdir(exist_ok=True) + secrets_dir = tmpdir / "secrets" + secrets_dir.mkdir(exist_ok=True) + disk_img = tmpdir / "disk.img" - env = os.environ.copy() - env["CLAN_DIR"] = str(self.vm.flake_url) + env = os.environ.copy() + env["CLAN_DIR"] = str(self.vm.flake_url) - env["PYTHONPATH"] = str( - ":".join(sys.path) - ) # TODO do this in the clanCore module - env["SECRETS_DIR"] = str(secrets_dir) + env["PYTHONPATH"] = str( + ":".join(sys.path) + ) # TODO do this in the clanCore module + env["SECRETS_DIR"] = str(secrets_dir) - res = is_path_or_url(str(self.vm.flake_url)) - if res is None: - raise ClanError( - f"flake_url must be a valid path or URL, got {self.vm.flake_url}" - ) - elif res == "path": # Only generate secrets for local clans - cmd = next(cmds) - if Path(self.vm.flake_url).is_dir(): - cmd.run( - [vm_config["generateSecrets"], clan_name], - env=env, + res = is_path_or_url(str(self.vm.flake_url)) + if res is None: + raise ClanError( + f"flake_url must be a valid path or URL, got {self.vm.flake_url}" ) - else: - self.log.warning("won't generate secrets for non local clan") + elif res == "path": # Only generate secrets for local clans + cmd = next(cmds) + if Path(self.vm.flake_url).is_dir(): + cmd.run( + [vm_config["generateSecrets"], clan_name], + env=env, + ) + else: + self.log.warning("won't generate secrets for non local clan") - cmd = next(cmds) - cmd.run( - [vm_config["uploadSecrets"], clan_name], - env=env, - ) - - cmd = next(cmds) - cmd.run( - nix_shell( - ["qemu"], - [ - "qemu-img", - "create", - "-f", - "raw", - disk_img, - "1024M", - ], + cmd = next(cmds) + cmd.run( + [vm_config["uploadSecrets"], clan_name], + env=env, ) - ) - cmd = next(cmds) - cmd.run( - nix_shell( - ["e2fsprogs"], - [ - "mkfs.ext4", - "-L", - "nixos", - disk_img, - ], + cmd = next(cmds) + cmd.run( + nix_shell( + ["qemu"], + [ + "qemu-img", + "create", + "-f", + "raw", + str(disk_img), + "1024M", + ], + ) ) - ) - cmd = next(cmds) - cmdline = [ - (Path(vm_config["toplevel"]) / "kernel-params").read_text(), - f'init={vm_config["toplevel"]}/init', - f'regInfo={vm_config["regInfo"]}/registration', - "console=ttyS0,115200n8", - "console=tty0", - ] - qemu_command = [ - # fmt: off - "qemu-kvm", - "-name", machine, - "-m", f'{vm_config["memorySize"]}M', - "-smp", str(vm_config["cores"]), - "-device", "virtio-rng-pci", - "-net", "nic,netdev=user.0,model=virtio", "-netdev", "user,id=user.0", - "-virtfs", "local,path=/nix/store,security_model=none,mount_tag=nix-store", - "-virtfs", f"local,path={xchg_dir},security_model=none,mount_tag=shared", - "-virtfs", f"local,path={xchg_dir},security_model=none,mount_tag=xchg", - "-virtfs", f"local,path={secrets_dir},security_model=none,mount_tag=secrets", - "-drive", f'cache=writeback,file={disk_img},format=raw,id=drive1,if=none,index=1,werror=report', - "-device", "virtio-blk-pci,bootindex=1,drive=drive1,serial=root", - "-device", "virtio-keyboard", - "-usb", - "-device", "usb-tablet,bus=usb-bus.0", - "-kernel", f'{vm_config["toplevel"]}/kernel', - "-initrd", vm_config["initrd"], - "-append", " ".join(cmdline), - # fmt: on - ] - if not self.vm.graphics: - qemu_command.append("-nographic") - print("$ " + shlex.join(qemu_command)) - cmd.run(nix_shell(["qemu"], qemu_command)) + cmd = next(cmds) + cmd.run( + nix_shell( + ["e2fsprogs"], + [ + "mkfs.ext4", + "-L", + "nixos", + str(disk_img), + ], + ) + ) + + cmd = next(cmds) + cmdline = [ + (Path(vm_config["toplevel"]) / "kernel-params").read_text(), + f'init={vm_config["toplevel"]}/init', + f'regInfo={vm_config["regInfo"]}/registration', + "console=ttyS0,115200n8", + "console=tty0", + ] + qemu_command = [ + # fmt: off + "qemu-kvm", + "-name", machine, + "-m", f'{vm_config["memorySize"]}M', + "-smp", str(vm_config["cores"]), + "-device", "virtio-rng-pci", + "-net", "nic,netdev=user.0,model=virtio", "-netdev", "user,id=user.0", + "-virtfs", "local,path=/nix/store,security_model=none,mount_tag=nix-store", + "-virtfs", f"local,path={xchg_dir},security_model=none,mount_tag=shared", + "-virtfs", f"local,path={xchg_dir},security_model=none,mount_tag=xchg", + "-virtfs", f"local,path={secrets_dir},security_model=none,mount_tag=secrets", + "-drive", f'cache=writeback,file={disk_img},format=raw,id=drive1,if=none,index=1,werror=report', + "-device", "virtio-blk-pci,bootindex=1,drive=drive1,serial=root", + "-device", "virtio-keyboard", + "-usb", + "-device", "usb-tablet,bus=usb-bus.0", + "-kernel", f'{vm_config["toplevel"]}/kernel', + "-initrd", vm_config["initrd"], + "-append", " ".join(cmdline), + # fmt: on + ] + if not self.vm.graphics: + qemu_command.append("-nographic") + print("$ " + shlex.join(qemu_command)) + cmd.run(nix_shell(["qemu"], qemu_command)) def create_vm(vm: VmConfig) -> BuildVmTask: