lol

Merge pull request #144174 from mkg20001/lxdimage

authored by

Maciej Krüger and committed by
GitHub
b4e153c4 75a5831e

+456
+1
nixos/modules/module-list.nix
··· 772 772 ./services/networking/libreswan.nix 773 773 ./services/networking/lldpd.nix 774 774 ./services/networking/logmein-hamachi.nix 775 + ./services/networking/lxd-image-server.nix 775 776 ./services/networking/mailpile.nix 776 777 ./services/networking/magic-wormhole-mailbox-server.nix 777 778 ./services/networking/matterbridge.nix
+138
nixos/modules/services/networking/lxd-image-server.nix
··· 1 + { config, pkgs, lib, ... }: 2 + 3 + with lib; 4 + 5 + let 6 + cfg = config.services.lxd-image-server; 7 + format = pkgs.formats.toml {}; 8 + 9 + location = "/var/www/simplestreams"; 10 + in 11 + { 12 + options = { 13 + services.lxd-image-server = { 14 + enable = mkEnableOption "lxd-image-server"; 15 + 16 + group = mkOption { 17 + type = types.str; 18 + description = "Group assigned to the user and the webroot directory."; 19 + default = "nginx"; 20 + example = "www-data"; 21 + }; 22 + 23 + settings = mkOption { 24 + type = format.type; 25 + description = '' 26 + Configuration for lxd-image-server. 27 + 28 + Example see <link xlink:href="https://github.com/Avature/lxd-image-server/blob/master/config.toml"/>. 29 + ''; 30 + default = {}; 31 + }; 32 + 33 + nginx = { 34 + enable = mkEnableOption "nginx"; 35 + domain = mkOption { 36 + type = types.str; 37 + description = "Domain to use for nginx virtual host."; 38 + example = "images.example.org"; 39 + }; 40 + }; 41 + }; 42 + }; 43 + 44 + config = mkMerge [ 45 + (mkIf (cfg.enable) { 46 + users.users.lxd-image-server = { 47 + isSystemUser = true; 48 + group = cfg.group; 49 + }; 50 + users.groups.${cfg.group} = {}; 51 + 52 + environment.etc."lxd-image-server/config.toml".source = format.generate "config.toml" cfg.settings; 53 + 54 + services.logrotate.paths.lxd-image-server = { 55 + path = "/var/log/lxd-image-server/lxd-image-server.log"; 56 + frequency = "daily"; 57 + keep = 21; 58 + user = "lxd-image-server"; 59 + group = cfg.group; 60 + extraConfig = '' 61 + missingok 62 + compress 63 + delaycompress 64 + copytruncate 65 + notifempty 66 + ''; 67 + }; 68 + 69 + systemd.tmpfiles.rules = [ 70 + "d /var/www/simplestreams 0755 lxd-image-server ${cfg.group}" 71 + ]; 72 + 73 + systemd.services.lxd-image-server = { 74 + wantedBy = [ "multi-user.target" ]; 75 + after = [ "network.target" ]; 76 + 77 + description = "LXD Image Server"; 78 + 79 + script = '' 80 + ${pkgs.lxd-image-server}/bin/lxd-image-server init 81 + ${pkgs.lxd-image-server}/bin/lxd-image-server watch 82 + ''; 83 + 84 + serviceConfig = { 85 + User = "lxd-image-server"; 86 + Group = cfg.group; 87 + DynamicUser = true; 88 + LogsDirectory = "lxd-image-server"; 89 + RuntimeDirectory = "lxd-image-server"; 90 + ExecReload = "${pkgs.lxd-image-server}/bin/lxd-image-server reload"; 91 + ReadWritePaths = [ location ]; 92 + }; 93 + }; 94 + }) 95 + # this is seperate so it can be enabled on mirrored hosts 96 + (mkIf (cfg.nginx.enable) { 97 + # https://github.com/Avature/lxd-image-server/blob/master/resources/nginx/includes/lxd-image-server.pkg.conf 98 + services.nginx.virtualHosts = { 99 + "${cfg.nginx.domain}" = { 100 + forceSSL = true; 101 + enableACME = mkDefault true; 102 + 103 + root = location; 104 + 105 + locations = { 106 + "/streams/v1/" = { 107 + index = "index.json"; 108 + }; 109 + 110 + # Serve json files with content type header application/json 111 + "~ \.json$" = { 112 + extraConfig = '' 113 + add_header Content-Type application/json; 114 + ''; 115 + }; 116 + 117 + "~ \.tar.xz$" = { 118 + extraConfig = '' 119 + add_header Content-Type application/octet-stream; 120 + ''; 121 + }; 122 + 123 + "~ \.tar.gz$" = { 124 + extraConfig = '' 125 + add_header Content-Type application/octet-stream; 126 + ''; 127 + }; 128 + 129 + # Deny access to document root and the images folder 130 + "~ ^/(images/)?$" = { 131 + return = "403"; 132 + }; 133 + }; 134 + }; 135 + }; 136 + }) 137 + ]; 138 + }
+1
nixos/tests/all-tests.nix
··· 238 238 lxd = handleTest ./lxd.nix {}; 239 239 lxd-image = handleTest ./lxd-image.nix {}; 240 240 lxd-nftables = handleTest ./lxd-nftables.nix {}; 241 + lxd-image-server = handleTest ./lxd-image-server.nix {}; 241 242 #logstash = handleTest ./logstash.nix {}; 242 243 lorri = handleTest ./lorri/default.nix {}; 243 244 magic-wormhole-mailbox-server = handleTest ./magic-wormhole-mailbox-server.nix {};
+127
nixos/tests/lxd-image-server.nix
··· 1 + import ./make-test-python.nix ({ pkgs, ...} : 2 + 3 + let 4 + # Since we don't have access to the internet during the tests, we have to 5 + # pre-fetch lxd containers beforehand. 6 + # 7 + # I've chosen to import Alpine Linux, because its image is turbo-tiny and, 8 + # generally, sufficient for our tests. 9 + alpine-meta = pkgs.fetchurl { 10 + url = "https://tarballs.nixos.org/alpine/3.12/lxd.tar.xz"; 11 + hash = "sha256-1tcKaO9lOkvqfmG/7FMbfAEToAuFy2YMewS8ysBKuLA="; 12 + }; 13 + 14 + alpine-rootfs = pkgs.fetchurl { 15 + url = "https://tarballs.nixos.org/alpine/3.12/rootfs.tar.xz"; 16 + hash = "sha256-Tba9sSoaiMtQLY45u7p5DMqXTSDgs/763L/SQp0bkCA="; 17 + }; 18 + 19 + lxd-config = pkgs.writeText "config.yaml" '' 20 + storage_pools: 21 + - name: default 22 + driver: dir 23 + config: 24 + source: /var/lxd-pool 25 + 26 + networks: 27 + - name: lxdbr0 28 + type: bridge 29 + config: 30 + ipv4.address: auto 31 + ipv6.address: none 32 + 33 + profiles: 34 + - name: default 35 + devices: 36 + eth0: 37 + name: eth0 38 + network: lxdbr0 39 + type: nic 40 + root: 41 + path: / 42 + pool: default 43 + type: disk 44 + ''; 45 + 46 + 47 + in { 48 + name = "lxd-image-server"; 49 + 50 + meta = with pkgs.lib.maintainers; { 51 + maintainers = [ mkg20001 ]; 52 + }; 53 + 54 + machine = { lib, ... }: { 55 + virtualisation = { 56 + cores = 2; 57 + 58 + memorySize = 2048; 59 + diskSize = 4096; 60 + 61 + lxc.lxcfs.enable = true; 62 + lxd.enable = true; 63 + }; 64 + 65 + security.pki.certificates = [ 66 + (builtins.readFile ./common/acme/server/ca.cert.pem) 67 + ]; 68 + 69 + services.nginx = { 70 + enable = true; 71 + }; 72 + 73 + services.lxd-image-server = { 74 + enable = true; 75 + nginx = { 76 + enable = true; 77 + domain = "acme.test"; 78 + }; 79 + }; 80 + 81 + services.nginx.virtualHosts."acme.test" = { 82 + enableACME = false; 83 + sslCertificate = ./common/acme/server/acme.test.cert.pem; 84 + sslCertificateKey = ./common/acme/server/acme.test.key.pem; 85 + }; 86 + 87 + networking.hosts = { 88 + "::1" = [ "acme.test" ]; 89 + }; 90 + }; 91 + 92 + testScript = '' 93 + machine.wait_for_unit("sockets.target") 94 + machine.wait_for_unit("lxd.service") 95 + machine.wait_for_file("/var/lib/lxd/unix.socket") 96 + 97 + # It takes additional second for lxd to settle 98 + machine.sleep(1) 99 + 100 + # lxd expects the pool's directory to already exist 101 + machine.succeed("mkdir /var/lxd-pool") 102 + 103 + 104 + machine.succeed( 105 + "cat ${lxd-config} | lxd init --preseed" 106 + ) 107 + 108 + machine.succeed( 109 + "lxc image import ${alpine-meta} ${alpine-rootfs} --alias alpine" 110 + ) 111 + 112 + loc = "/var/www/simplestreams/images/iats/alpine/amd64/default/v1" 113 + 114 + with subtest("push image to server"): 115 + machine.succeed("lxc launch alpine test") 116 + machine.succeed("lxc stop test") 117 + machine.succeed("lxc publish --public test --alias=testimg") 118 + machine.succeed("lxc image export testimg") 119 + machine.succeed("ls >&2") 120 + machine.succeed("mkdir -p " + loc) 121 + machine.succeed("mv *.tar.gz " + loc) 122 + 123 + with subtest("pull image from server"): 124 + machine.succeed("lxc remote add img https://acme.test --protocol=simplestreams") 125 + machine.succeed("lxc image list img: >&2") 126 + ''; 127 + })
+30
pkgs/development/python-modules/confight/default.nix
··· 1 + { lib 2 + , buildPythonPackage 3 + , fetchPypi 4 + , toml 5 + }: 6 + 7 + buildPythonPackage rec { 8 + pname = "confight"; 9 + version = "1.3.1"; 10 + 11 + src = fetchPypi { 12 + inherit pname version; 13 + sha256 = "sha256-fJr7f9Y/zEpCedWYd04AMuhkOFqZLJOw4sDiz8SDQ/Y="; 14 + }; 15 + 16 + propagatedBuildInputs = [ 17 + toml 18 + ]; 19 + 20 + pythonImportsCheck = [ "confight" ]; 21 + 22 + doCheck = false; 23 + 24 + meta = with lib; { 25 + description = "Python context manager for managing pid files"; 26 + homepage = "https://github.com/avature/confight"; 27 + license = with licenses; [ mit ]; 28 + maintainers = with maintainers; [ mkg20001 ]; 29 + }; 30 + }
+32
pkgs/development/python-modules/inotify/default.nix
··· 1 + { lib 2 + , buildPythonPackage 3 + , fetchFromGitHub 4 + , nose 5 + }: 6 + 7 + buildPythonPackage rec { 8 + pname = "inotify"; 9 + version = "unstable-2020-08-27"; 10 + 11 + src = fetchFromGitHub { 12 + owner = "dsoprea"; 13 + repo = "PyInotify"; 14 + rev = "f77596ae965e47124f38d7bd6587365924dcd8f7"; 15 + sha256 = "X0gu4s1R/Kg+tmf6s8SdZBab2HisJl4FxfdwKktubVc="; 16 + fetchSubmodules = false; 17 + }; 18 + 19 + checkInputs = [ 20 + nose 21 + ]; 22 + 23 + # dunno what's wrong but the module works regardless 24 + doCheck = false; 25 + 26 + meta = with lib; { 27 + homepage = "https://github.com/dsoprea/PyInotify"; 28 + description = "Monitor filesystems events on Linux platforms with inotify"; 29 + license = licenses.gpl2; 30 + platforms = platforms.linux; 31 + }; 32 + }
+47
pkgs/tools/virtualization/lxd-image-server/default.nix
··· 1 + { lib 2 + , openssl 3 + , rsync 4 + , python3 5 + , fetchFromGitHub 6 + }: 7 + 8 + python3.pkgs.buildPythonApplication rec { 9 + pname = "lxd-image-server"; 10 + version = "0.0.4"; 11 + 12 + src = fetchFromGitHub { 13 + owner = "Avature"; 14 + repo = "lxd-image-server"; 15 + rev = version; 16 + sha256 = "yx8aUmMfSzyWaM6M7+WcL6ouuWwOpqLzODWSdNgwCwo="; 17 + }; 18 + 19 + patches = [ 20 + ./state.patch 21 + ./run.patch 22 + ]; 23 + 24 + propagatedBuildInputs = with python3.pkgs; [ 25 + setuptools 26 + attrs 27 + click 28 + inotify 29 + cryptography 30 + confight 31 + python-pidfile 32 + ]; 33 + 34 + makeWrapperArgs = [ 35 + ''--prefix PATH ':' "${lib.makeBinPath [ openssl rsync ]}"'' 36 + ]; 37 + 38 + doCheck = false; 39 + 40 + meta = with lib; { 41 + description = "Creates and manages a simplestreams lxd image server on top of nginx"; 42 + homepage = "https://github.com/Avature/lxd-image-server"; 43 + license = licenses.apsl20; 44 + platforms = platforms.unix; 45 + maintainers = with maintainers; [ mkg20001 ]; 46 + }; 47 + }
+25
pkgs/tools/virtualization/lxd-image-server/run.patch
··· 1 + From df2ce9fb48a3790407646a388e0d220a75496c52 Mon Sep 17 00:00:00 2001 2 + From: =?UTF-8?q?Maciej=20Kr=C3=BCger?= <mkg20001@gmail.com> 3 + Date: Wed, 3 Nov 2021 14:23:38 +0100 4 + Subject: [PATCH] /var/run -> /run 5 + 6 + --- 7 + lxd_image_server/tools/config.py | 2 +- 8 + 1 file changed, 1 insertion(+), 1 deletion(-) 9 + 10 + diff --git a/lxd_image_server/tools/config.py b/lxd_image_server/tools/config.py 11 + index 60e8973..23d392a 100644 12 + --- a/lxd_image_server/tools/config.py 13 + +++ b/lxd_image_server/tools/config.py 14 + @@ -9,7 +9,7 @@ import confight 15 + class Config(): 16 + 17 + _lock = Lock() 18 + - pidfile = Path('/var/run/lxd-image-server/pidfile') 19 + + pidfile = Path('/run/lxd-image-server/pidfile') 20 + data = {} 21 + 22 + @classmethod 23 + -- 24 + 2.33.0 25 +
+49
pkgs/tools/virtualization/lxd-image-server/state.patch
··· 1 + From 17a1e09eaf8957174425d05200be9ee3e77229f9 Mon Sep 17 00:00:00 2001 2 + From: =?UTF-8?q?Maciej=20Kr=C3=BCger?= <mkg20001@gmail.com> 3 + Date: Thu, 21 Oct 2021 00:39:08 +0200 4 + Subject: [PATCH] Remove system-state changing code 5 + 6 + This is already done by the module on nixOS 7 + --- 8 + lxd_image_server/cli.py | 15 +-------------- 9 + 1 file changed, 1 insertion(+), 14 deletions(-) 10 + 11 + diff --git a/lxd_image_server/cli.py b/lxd_image_server/cli.py 12 + index d276e6d..f759bf2 100644 13 + --- a/lxd_image_server/cli.py 14 + +++ b/lxd_image_server/cli.py 15 + @@ -140,30 +140,17 @@ def reload_config(): 16 + @cli.command() 17 + @click.option('--root_dir', default='/var/www/simplestreams', 18 + show_default=True) 19 + -@click.option('--ssl_dir', default='/etc/nginx/ssl', show_default=True, 20 + - callback=lambda ctx, param, val: Path(val)) 21 + @click.pass_context 22 + -def init(ctx, root_dir, ssl_dir): 23 + +def init(ctx, root_dir): 24 + if not Path(root_dir).exists(): 25 + logger.error('Root directory does not exists') 26 + else: 27 + - if not ssl_dir.exists(): 28 + - os.makedirs(str(ssl_dir)) 29 + - 30 + - if not (ssl_dir / 'nginx.key').exists(): 31 + - generate_cert(str(ssl_dir)) 32 + - 33 + img_dir = str(Path(root_dir, 'images')) 34 + streams_dir = str(Path(root_dir, 'streams/v1')) 35 + if not Path(img_dir).exists(): 36 + os.makedirs(img_dir) 37 + if not Path(streams_dir).exists(): 38 + os.makedirs(streams_dir) 39 + - conf_path = Path('/etc/nginx/sites-enabled/simplestreams.conf') 40 + - if not conf_path.exists(): 41 + - conf_path.symlink_to( 42 + - '/etc/nginx/sites-available/simplestreams.conf') 43 + - os.system('nginx -s reload') 44 + 45 + if not Path(root_dir, 'streams', 'v1', 'images.json').exists(): 46 + ctx.invoke(update, img_dir=Path(root_dir, 'images'), 47 + -- 48 + 2.33.0 49 +
+2
pkgs/top-level/all-packages.nix
··· 7352 7352 lxcfs = callPackage ../os-specific/linux/lxcfs { }; 7353 7353 lxd = callPackage ../tools/admin/lxd { }; 7354 7354 7355 + lxd-image-server = callPackage ../tools/virtualization/lxd-image-server { }; 7356 + 7355 7357 lzfse = callPackage ../tools/compression/lzfse { }; 7356 7358 7357 7359 lzham = callPackage ../tools/compression/lzham { };
+4
pkgs/top-level/python-packages.nix
··· 1705 1705 1706 1706 confuse = callPackage ../development/python-modules/confuse { }; 1707 1707 1708 + confight = callPackage ../development/python-modules/confight { }; 1709 + 1708 1710 connexion = callPackage ../development/python-modules/connexion { }; 1709 1711 1710 1712 consonance = callPackage ../development/python-modules/consonance { }; ··· 3769 3771 injector = callPackage ../development/python-modules/injector { }; 3770 3772 3771 3773 inkex = callPackage ../development/python-modules/inkex { }; 3774 + 3775 + inotify = callPackage ../development/python-modules/inotify { }; 3772 3776 3773 3777 inotify-simple = callPackage ../development/python-modules/inotify-simple { }; 3774 3778