Compare commits
38 Commits
e4f6cf2595
...
zineshop
| Author | SHA1 | Date | |
|---|---|---|---|
|
ce6b83f52f
|
|||
|
5a87c7f0dc
|
|||
|
38b2fd0bcc
|
|||
|
ae31ad99bb
|
|||
|
fd51fc97fc
|
|||
|
c6b6720c42
|
|||
|
01fb1bdaa8
|
|||
|
783ec0da20
|
|||
|
c02f4cdfb3
|
|||
|
de054fbb2e
|
|||
|
ee709ee36e
|
|||
|
686ef89e76
|
|||
|
e294fecf7e
|
|||
|
568cce0d48
|
|||
|
46e9bae193
|
|||
| 4949719307 | |||
|
e8c188debf
|
|||
|
1f559d93ba
|
|||
|
a03b7506c5
|
|||
|
3b2a7cedc5
|
|||
|
a48e271853
|
|||
|
d202a3d0cb
|
|||
| ef33833910 | |||
| d73031e7f1 | |||
| be0bb0b08b | |||
| 026494c877 | |||
| 3021716640 | |||
| 70ec63f213 | |||
| 91d86c49a1 | |||
| 96dee29595 | |||
| d5e94b50cb | |||
| 286e03c853 | |||
| 766b738a6a | |||
| de600fe7c7 | |||
| 5731fc795e | |||
| 1083949c87 | |||
| 413202e940 | |||
| ec20c80251 |
@@ -1,47 +1,19 @@
|
|||||||
# Create host with disko-install
|
# Create host with nixos-anywhere
|
||||||
How to use disko-install is described here: https://github.com/nix-community/disko/blob/master/docs/disko-install.md
|
We use a nixos-anywhere wrapper script to deploy new hosts.
|
||||||
---
|
The wrapper script takes care of copying persistent host keys before calling nixos-anywhere.
|
||||||
Here are the exact steps to get bakunin running:
|
|
||||||
First create machines/hostname/configuration.nix
|
To accomplish that boot the host from a nixos image and setup a root password.
|
||||||
Add hosts nixosConfiguration in machines/configurations.nix
|
|
||||||
Boot nixos installer on the Machine.
|
|
||||||
``` bash
|
``` bash
|
||||||
# establish network connection
|
sudo su
|
||||||
wpa_passphrase "network" "password" > wpa.conf
|
passwd
|
||||||
wpa_supplicant -B -i wlp3s0 -c wpa.conf
|
```
|
||||||
ping 8.8.8.8
|
|
||||||
# if that works continue
|
|
||||||
|
|
||||||
# generate a base hardware config
|
After that get the hosts ip using `ip a` and start deployment from your own machine:
|
||||||
nixos-generate-config --root /tmp/config --no-filesystems
|
|
||||||
|
|
||||||
# get the infra repo
|
``` bash
|
||||||
nix-shell -p git
|
# from infrastrucutre repository root dir:
|
||||||
git clone https://git.dynamicdiscord.de/kalipso/infrastructure
|
nix develop .#
|
||||||
cd infrastructure
|
remote-install hostname 10.0.42.23
|
||||||
|
|
||||||
# add the new generated hardware config (and import in hosts configuration.nix)
|
|
||||||
cp /tmp/config/etc/nixos/hardware-configuration.nix machines/bakunin/
|
|
||||||
|
|
||||||
# check which harddrive we want to install the system on
|
|
||||||
lsblk #choose harddrive, in this case /dev/sda
|
|
||||||
|
|
||||||
# run nixos-install on that harddrive
|
|
||||||
sudo nix --extra-experimental-features flakes --extra-experimental-features nix-command run 'github:nix-community/disko/latest#disko-install' -- --flake .#bakunin --disk main /dev/sda
|
|
||||||
|
|
||||||
# this failed with out of memory
|
|
||||||
# running again showed: no disk left on device
|
|
||||||
# it seems the usb stick i used for flashing is way to small
|
|
||||||
# it is only
|
|
||||||
# with a bigger one (more than 8 gig i guess) it should work
|
|
||||||
# instead the disko-install tool i try the old method - first partitioning using disko and then installing the system
|
|
||||||
# for that i needed to adjust ./machines/modules/disko/btrfs-laptop.nix and set the disk to "/dev/sda"
|
|
||||||
|
|
||||||
sudo nix --extra-experimental-features "flakes nix-command" run 'github:nix-community/disko/latest' -- --mode format --flake .#bakunin
|
|
||||||
|
|
||||||
# failed with no space left on device.
|
|
||||||
# problem is lots of data is written to the local /nix/store which is mounted on tmpfs in ram
|
|
||||||
# it seems that a workaround could be modifying the bootable stick to contain a swap partition to extend tmpfs storage
|
|
||||||
```
|
```
|
||||||
|
|
||||||
# Testing Disko
|
# Testing Disko
|
||||||
@@ -49,18 +21,3 @@ Testing disko partitioning is working quite well. Just run the following and che
|
|||||||
```bash
|
```bash
|
||||||
nix run -L .\#nixosConfigurations.fanny.config.system.build.vmWithDisko
|
nix run -L .\#nixosConfigurations.fanny.config.system.build.vmWithDisko
|
||||||
```
|
```
|
||||||
|
|
||||||
Only problem is that encryption is not working, so it needs to be commented out. For testing host fanny the following parts in ```./machines/modules/disko/fanny.nix``` need to be commented out(for both pools!):
|
|
||||||
```nix
|
|
||||||
datasets = {
|
|
||||||
encrypted = {
|
|
||||||
options = {
|
|
||||||
encryption = "aes-256-gcm"; #THIS ONE
|
|
||||||
keyformat = "passphrase"; #THIS ONE
|
|
||||||
keylocation = "file:///tmp/root.key"; #THIS ONE
|
|
||||||
};
|
|
||||||
# use this to read the key during boot
|
|
||||||
postCreateHook = '' #THIS ONE
|
|
||||||
zfs set keylocation="prompt" "zroot/$name"; #THIS ONE
|
|
||||||
''; #THIS ONE
|
|
||||||
```
|
|
||||||
|
|||||||
65
flake.lock
generated
65
flake.lock
generated
@@ -235,7 +235,8 @@
|
|||||||
"nixpkgs-unstable": "nixpkgs-unstable",
|
"nixpkgs-unstable": "nixpkgs-unstable",
|
||||||
"sops-nix": "sops-nix",
|
"sops-nix": "sops-nix",
|
||||||
"tasklist": "tasklist",
|
"tasklist": "tasklist",
|
||||||
"utils": "utils_3"
|
"utils": "utils_3",
|
||||||
|
"zineshop": "zineshop"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sops-nix": {
|
"sops-nix": {
|
||||||
@@ -334,6 +335,21 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"systems_5": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"tasklist": {
|
"tasklist": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
@@ -341,11 +357,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1737548421,
|
"lastModified": 1743458889,
|
||||||
"narHash": "sha256-gmlqJdC+v86vXc2yMhiza1mvsqh3vMfrEsiw+tV5MXg=",
|
"narHash": "sha256-eVTtsCPio3Wj/g/gvKTsyjh90vrNsmgjzXK9jMfcboM=",
|
||||||
"ref": "refs/heads/master",
|
"ref": "refs/heads/master",
|
||||||
"rev": "c5fff78c83959841ac724980a13597dcfa6dc26d",
|
"rev": "b61466549e2687628516aa1f9ba73f251935773a",
|
||||||
"revCount": 29,
|
"revCount": 30,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://git.dynamicdiscord.de/kalipso/tasklist"
|
"url": "https://git.dynamicdiscord.de/kalipso/tasklist"
|
||||||
},
|
},
|
||||||
@@ -407,6 +423,45 @@
|
|||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"utils_4": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems_5"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731533236,
|
||||||
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"zineshop": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"utils": "utils_4"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1744626173,
|
||||||
|
"narHash": "sha256-DSuLVFGvmMUoStIs5ar4CLE8eD2dlFPUmPC7CODauts=",
|
||||||
|
"ref": "refs/heads/master",
|
||||||
|
"rev": "19ce41aca7d92bc8e02f97e7bdbca7ac7ba64090",
|
||||||
|
"revCount": 103,
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.dynamicdiscord.de/kalipso/zineshop"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.dynamicdiscord.de/kalipso/zineshop"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": "root",
|
"root": "root",
|
||||||
|
|||||||
@@ -22,6 +22,11 @@
|
|||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
zineshop = {
|
||||||
|
url = "git+https://git.dynamicdiscord.de/kalipso/zineshop";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
|
||||||
ep3-bs = {
|
ep3-bs = {
|
||||||
url = "git+https://git.dynamicdiscord.de/kalipso/ep3-bs.nix";
|
url = "git+https://git.dynamicdiscord.de/kalipso/ep3-bs.nix";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
|||||||
@@ -73,6 +73,17 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
services.nginx.virtualHosts."shop.malobeo.org" = {
|
||||||
|
forceSSL = true;
|
||||||
|
enableACME= true;
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://10.0.0.10";
|
||||||
|
extraConfig = ''
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
services.nginx.virtualHosts."status.malobeo.org" = {
|
services.nginx.virtualHosts."status.malobeo.org" = {
|
||||||
forceSSL = true;
|
forceSSL = true;
|
||||||
enableACME= true;
|
enableACME= true;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ in
|
|||||||
{
|
{
|
||||||
sops.defaultSopsFile = ./secrets.yaml;
|
sops.defaultSopsFile = ./secrets.yaml;
|
||||||
sops.secrets.wg_private = {};
|
sops.secrets.wg_private = {};
|
||||||
|
sops.secrets.shop_auth = {};
|
||||||
|
|
||||||
imports =
|
imports =
|
||||||
[ # Include the results of the hardware scan.
|
[ # Include the results of the hardware scan.
|
||||||
@@ -18,6 +19,7 @@ in
|
|||||||
inputs.self.nixosModules.malobeo.microvm
|
inputs.self.nixosModules.malobeo.microvm
|
||||||
inputs.self.nixosModules.malobeo.metrics
|
inputs.self.nixosModules.malobeo.metrics
|
||||||
inputs.self.nixosModules.malobeo.users
|
inputs.self.nixosModules.malobeo.users
|
||||||
|
inputs.self.nixosModules.malobeo.backup
|
||||||
];
|
];
|
||||||
|
|
||||||
virtualisation.vmVariantWithDisko = {
|
virtualisation.vmVariantWithDisko = {
|
||||||
@@ -42,6 +44,11 @@ in
|
|||||||
cacheurl = "https://cache.dynamicdiscord.de";
|
cacheurl = "https://cache.dynamicdiscord.de";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
malobeo.backup = {
|
||||||
|
enable = true;
|
||||||
|
snapshots = [ "storage/encrypted" "zroot/encrypted/var" ];
|
||||||
|
};
|
||||||
|
|
||||||
nix = {
|
nix = {
|
||||||
settings.experimental-features = [ "nix-command" "flakes" ];
|
settings.experimental-features = [ "nix-command" "flakes" ];
|
||||||
#always update microvms
|
#always update microvms
|
||||||
@@ -53,6 +60,7 @@ in
|
|||||||
malobeo.users = {
|
malobeo.users = {
|
||||||
malobeo = true;
|
malobeo = true;
|
||||||
admin = true;
|
admin = true;
|
||||||
|
backup = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
malobeo.disks = {
|
malobeo.disks = {
|
||||||
@@ -86,7 +94,13 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
services.malobeo.microvm.enableHostBridge = true;
|
services.malobeo.microvm.enableHostBridge = true;
|
||||||
services.malobeo.microvm.deployHosts = [ "overwatch" "infradocs" "nextcloud" "durruti" ];
|
services.malobeo.microvm.deployHosts = [
|
||||||
|
"overwatch"
|
||||||
|
"infradocs"
|
||||||
|
"nextcloud"
|
||||||
|
"durruti"
|
||||||
|
"zineshop"
|
||||||
|
];
|
||||||
|
|
||||||
networking = {
|
networking = {
|
||||||
nat = {
|
nat = {
|
||||||
@@ -137,6 +151,18 @@ in
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
virtualHosts."shop.malobeo.org" = {
|
||||||
|
# created with: nix-shell --packages apacheHttpd --run 'htpasswd -B -c foo.txt malobeo'
|
||||||
|
# then content of foo.txt put into sops
|
||||||
|
basicAuthFile = config.sops.secrets.shop_auth.path;
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://10.0.0.15:8080";
|
||||||
|
extraConfig = ''
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
services.tor = {
|
services.tor = {
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
wg_private: ENC[AES256_GCM,data:kFuLzZz9lmtUccQUIYiXvJRf7WBg5iCq1xxCiI76J3TaIBELqgbEmUtPR4g=,iv:0S0uzX4OVxQCKDOl1zB6nDo8152oE7ymBWdVkPkKlro=,tag:gg1n1BsnjNPikMBNB60F5Q==,type:str]
|
wg_private: ENC[AES256_GCM,data:kFuLzZz9lmtUccQUIYiXvJRf7WBg5iCq1xxCiI76J3TaIBELqgbEmUtPR4g=,iv:0S0uzX4OVxQCKDOl1zB6nDo8152oE7ymBWdVkPkKlro=,tag:gg1n1BsnjNPikMBNB60F5Q==,type:str]
|
||||||
|
shop_cleartext: ENC[AES256_GCM,data:sifpX/R6JCcNKgwN2M4Dbflgnfs5CqB8ez5fULPohuFS6k36BLemWzEk,iv:1lRYausj7V/53sfSO9UnJ2OC/Si94JXgIo81Ld74BE8=,tag:5osQU/67bvFeUGA90BSiIA==,type:str]
|
||||||
|
shop_auth: ENC[AES256_GCM,data:0NDIRjmGwlSFls12sCb5OlgyGTCHpPQIjycEJGhYlZsWKhEYXV2u3g1RHMkF8Ny913jarjf0BgwSq5pBD9rgPL9t8X8=,iv:3jgCv/Gg93Mhdm4eYzwF9QrK14QL2bcC4wwSajCA88o=,tag:h8dhMK46hABv9gYW4johkA==,type:str]
|
||||||
sops:
|
sops:
|
||||||
kms: []
|
kms: []
|
||||||
gcp_kms: []
|
gcp_kms: []
|
||||||
@@ -23,8 +25,8 @@ sops:
|
|||||||
QVZyNWVOMTh3ejBha21Qb2xCRkFERGMKH9nMQUoS5bGcLUx2T1dOmKd9jshttTrP
|
QVZyNWVOMTh3ejBha21Qb2xCRkFERGMKH9nMQUoS5bGcLUx2T1dOmKd9jshttTrP
|
||||||
SKFx7MXcjFRLKS2Ij12V8ftjL3Uod6be5zoMibkxK19KmXY/514Jww==
|
SKFx7MXcjFRLKS2Ij12V8ftjL3Uod6be5zoMibkxK19KmXY/514Jww==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
lastmodified: "2025-01-14T12:41:07Z"
|
lastmodified: "2025-04-14T10:34:55Z"
|
||||||
mac: ENC[AES256_GCM,data:RJ4Fa8MmX8u8S3zrD/SaywTC3d2IfHQPBDy3C9u4GuXJ/ruEChAB1kN8rqMPvkmET8UUgHIEp7RpbzMtg/FOmKYKYTTx5t//3/VozvAEZurhG/4mnN3r6uaZ0R9+wSjym8IyOKsJ7p4XrfE5tRdzNyU4EqfkEiyf+jO751uSnYI=,iv:eiTdmbcrpUvyDPFmGawxJs/ehmD7KqulaoB+nfpC6ko=,tag:+TKr53cFS3wbLXNgcbZfJQ==,type:str]
|
mac: ENC[AES256_GCM,data:vcDXtTi0bpqhHnL6XanJo+6a8f5LAE628HazDVaNO34Ll3eRyhi95eYGXQDDkVk2WUn9NJ5oCMPltnU82bpLtskzTfQDuXHaPZJq5gtOuMH/bAKrY0dfShrdyx71LkA4AFlcI1P5hchpbyY1FK3iqe4D0miBv+Q8lCMgQMVrfxI=,iv:1lMzH899K0CnEtm16nyq8FL/aCkSYJVoj7HSKCyUnPg=,tag:mEbkmFNg5VZtSKqq80NrCw==,type:str]
|
||||||
pgp:
|
pgp:
|
||||||
- created_at: "2025-02-11T18:32:49Z"
|
- created_at: "2025-02-11T18:32:49Z"
|
||||||
enc: |-
|
enc: |-
|
||||||
@@ -65,4 +67,4 @@ sops:
|
|||||||
-----END PGP MESSAGE-----
|
-----END PGP MESSAGE-----
|
||||||
fp: aef8d6c7e4761fc297cda833df13aebb1011b5d4
|
fp: aef8d6c7e4761fc297cda833df13aebb1011b5d4
|
||||||
unencrypted_suffix: _unencrypted
|
unencrypted_suffix: _unencrypted
|
||||||
version: 3.9.2
|
version: 3.9.4
|
||||||
|
|||||||
@@ -67,6 +67,14 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
zineshop = {
|
||||||
|
type = "microvm";
|
||||||
|
network = {
|
||||||
|
address = "10.0.0.15";
|
||||||
|
mac = "D0:E5:CA:F0:D7:F1";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
testvm = {
|
testvm = {
|
||||||
type = "host";
|
type = "host";
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{ config, pkgs, ... }:
|
{ config, pkgs, inputs, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
imports =
|
imports =
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
../modules/sshd.nix
|
../modules/sshd.nix
|
||||||
../modules/minimal_tools.nix
|
../modules/minimal_tools.nix
|
||||||
../modules/autoupdate.nix
|
../modules/autoupdate.nix
|
||||||
|
inputs.self.nixosModules.malobeo.printing
|
||||||
];
|
];
|
||||||
|
|
||||||
malobeo.autoUpdate = {
|
malobeo.autoUpdate = {
|
||||||
@@ -50,6 +51,8 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
services.printing.enable = true;
|
services.printing.enable = true;
|
||||||
|
services.malobeo.printing.enable = true;
|
||||||
|
|
||||||
services.printing.drivers = [
|
services.printing.drivers = [
|
||||||
(pkgs.writeTextDir "share/cups/model/brother5350.ppd" (builtins.readFile ../modules/BR5350_2_GPL.ppd))
|
(pkgs.writeTextDir "share/cups/model/brother5350.ppd" (builtins.readFile ../modules/BR5350_2_GPL.ppd))
|
||||||
pkgs.gutenprint
|
pkgs.gutenprint
|
||||||
|
|||||||
4777
machines/modules/KOC658UX.ppd
Normal file
4777
machines/modules/KOC658UX.ppd
Normal file
File diff suppressed because it is too large
Load Diff
@@ -195,8 +195,7 @@ rec {
|
|||||||
|
|
||||||
vmNestedMicroVMOverwrites = host: sopsDummy: {
|
vmNestedMicroVMOverwrites = host: sopsDummy: {
|
||||||
|
|
||||||
services.malobeo.microvm.deployHosts = pkgs.lib.mkForce [];
|
microvm.vms = pkgs.lib.mkForce (
|
||||||
microvm.vms =
|
|
||||||
let
|
let
|
||||||
# Map the values to each hostname to then generate an Attrset using listToAttrs
|
# Map the values to each hostname to then generate an Attrset using listToAttrs
|
||||||
mapperFunc = name: { inherit name; value = {
|
mapperFunc = name: { inherit name; value = {
|
||||||
@@ -216,7 +215,7 @@ rec {
|
|||||||
};
|
};
|
||||||
}; };
|
}; };
|
||||||
in
|
in
|
||||||
builtins.listToAttrs (map mapperFunc self.nixosConfigurations.${host}.config.services.malobeo.microvm.deployHosts);
|
builtins.listToAttrs (map mapperFunc self.nixosConfigurations.${host}.config.services.malobeo.microvm.deployHosts));
|
||||||
};
|
};
|
||||||
|
|
||||||
buildVM = host: networking: sopsDummy: disableDisko: varPath: writableStore: fwdPort: (self.nixosConfigurations.${host}.extendModules {
|
buildVM = host: networking: sopsDummy: disableDisko: varPath: writableStore: fwdPort: (self.nixosConfigurations.${host}.extendModules {
|
||||||
|
|||||||
102
machines/modules/malobeo/backup.nix
Normal file
102
machines/modules/malobeo/backup.nix
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
cfg = config.malobeo.backup;
|
||||||
|
hostToCommand = (hostname: datasetNames:
|
||||||
|
(map (dataset: {
|
||||||
|
name = "${hostname}_${dataset.sourceDataset}";
|
||||||
|
value = {
|
||||||
|
inherit hostname;
|
||||||
|
inherit (dataset) sourceDataset targetDataset;
|
||||||
|
};
|
||||||
|
} ) datasetNames));
|
||||||
|
peers = import ./peers.nix;
|
||||||
|
|
||||||
|
enableSnapshots = cfg.snapshots != null;
|
||||||
|
enableBackups = cfg.hosts != null;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.malobeo.backup = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = "Enable sanoid/syncoid based backup functionality";
|
||||||
|
};
|
||||||
|
|
||||||
|
snapshots = mkOption {
|
||||||
|
type = types.nullOr (types.listOf types.str);
|
||||||
|
default = null;
|
||||||
|
description = "Automatic snapshots will be created for the given datasets";
|
||||||
|
};
|
||||||
|
|
||||||
|
hosts = mkOption {
|
||||||
|
default = null;
|
||||||
|
type = types.nullOr (types.attrsOf (types.listOf (types.submodule {
|
||||||
|
options = {
|
||||||
|
sourceDataset = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "The source that needs to be backed up";
|
||||||
|
};
|
||||||
|
targetDataset = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "The target dataset where the backup should be stored";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})));
|
||||||
|
description = ''
|
||||||
|
Hostname with list of datasets to backup. This option should be defined on hosts that will store backups.
|
||||||
|
|
||||||
|
It is necessary to add the machines that get backed up to known hosts.
|
||||||
|
This can be done for example systemwide using
|
||||||
|
programs.ssh.knownHosts."10.100.0.101" = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHqp2/YiiIhai7wyScGZJ20gtrzY+lp4N/8unyRs4qhc";
|
||||||
|
Or set it for the syncoid user directly.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
sshKey = mkOption {
|
||||||
|
default = null;
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
description = "Set path to ssh key used for pull backups. Otherwise default key is used";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf (cfg.enable) {
|
||||||
|
services.sanoid = mkIf (enableSnapshots) {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
templates."default" = {
|
||||||
|
hourly = 24;
|
||||||
|
daily = 30; #keep 30 daily snapshots
|
||||||
|
monthly = 6; #keep 6 monthly backups
|
||||||
|
yearly = 0;
|
||||||
|
|
||||||
|
autosnap = true; #take snapshots automatically
|
||||||
|
autoprune = true; #delete old snapshots
|
||||||
|
};
|
||||||
|
|
||||||
|
datasets = builtins.listToAttrs (map (name: { inherit name; value = {
|
||||||
|
useTemplate = [ "default" ];
|
||||||
|
recursive = true;
|
||||||
|
}; }) cfg.snapshots);
|
||||||
|
};
|
||||||
|
|
||||||
|
services.syncoid = mkIf (enableBackups) {
|
||||||
|
enable = true;
|
||||||
|
sshKey = cfg.sshKey;
|
||||||
|
|
||||||
|
commonArgs = [
|
||||||
|
"--no-sync-snap"
|
||||||
|
];
|
||||||
|
|
||||||
|
interval = "*-*-* 04:15:00";
|
||||||
|
|
||||||
|
commands = builtins.mapAttrs (name: value: {
|
||||||
|
source = "backup@${peers.${value.hostname}.address}:${value.sourceDataset}";
|
||||||
|
target = "${value.targetDataset}";
|
||||||
|
sendOptions = "w";
|
||||||
|
recvOptions = "\"\"";
|
||||||
|
recursive = true;
|
||||||
|
})(builtins.listToAttrs (builtins.concatLists (builtins.attrValues (builtins.mapAttrs hostToCommand cfg.hosts))));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -102,6 +102,22 @@ in
|
|||||||
/run/current-system/sw/bin/microvm -Ru ${name}
|
/run/current-system/sw/bin/microvm -Ru ${name}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
"microvm-init-dirs@${name}" = {
|
||||||
|
description = "Initialize microvm directories";
|
||||||
|
after = [ "zfs-mount.service" ];
|
||||||
|
wantedBy = [ "microvm@${name}.service" ];
|
||||||
|
unitConfig.ConditionPathExists = "!/var/lib/microvms/${name}/.is_initialized";
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
};
|
||||||
|
script = ''
|
||||||
|
mkdir -p /var/lib/microvms/${name}/var
|
||||||
|
mkdir -p /var/lib/microvms/${name}/etc
|
||||||
|
mkdir -p /var/lib/microvms/data/${name}
|
||||||
|
touch /var/lib/microvms/${name}/.is_initialized
|
||||||
|
'';
|
||||||
|
};
|
||||||
}) {} (cfg.deployHosts);
|
}) {} (cfg.deployHosts);
|
||||||
|
|
||||||
systemd.timers = builtins.foldl' (timers: name: timers // {
|
systemd.timers = builtins.foldl' (timers: name: timers // {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"vpn" = {
|
"vpn" = {
|
||||||
role = "server";
|
role = "server";
|
||||||
publicIp = "5.9.153.217";
|
publicIp = "5.9.153.217";
|
||||||
address = [ "10.100.0.1/24" ];
|
address = "10.100.0.1";
|
||||||
allowedIPs = [ "10.100.0.0/24" ];
|
allowedIPs = [ "10.100.0.0/24" ];
|
||||||
listenPort = 51821;
|
listenPort = 51821;
|
||||||
publicKey = "hF9H10Y8Ar7zvZXFoNM8LSoaYFgPCXv30c54SSEucX4=";
|
publicKey = "hF9H10Y8Ar7zvZXFoNM8LSoaYFgPCXv30c54SSEucX4=";
|
||||||
@@ -11,36 +11,43 @@
|
|||||||
|
|
||||||
"celine" = {
|
"celine" = {
|
||||||
role = "client";
|
role = "client";
|
||||||
address = [ "10.100.0.2/24" ];
|
address = "10.100.0.2";
|
||||||
allowedIPs = [ "10.100.0.2/32" ];
|
allowedIPs = [ "10.100.0.2/32" ];
|
||||||
publicKey = "Jgx82tSOmZJS4sm1o8Eci9ahaQdQir2PLq9dBqsWZw4=";
|
publicKey = "Jgx82tSOmZJS4sm1o8Eci9ahaQdQir2PLq9dBqsWZw4=";
|
||||||
};
|
};
|
||||||
|
|
||||||
"desktop" = {
|
"desktop" = {
|
||||||
role = "client";
|
role = "client";
|
||||||
address = [ "10.100.0.3/24" ];
|
address = "10.100.0.3";
|
||||||
allowedIPs = [ "10.100.0.3/32" ];
|
allowedIPs = [ "10.100.0.3/32" ];
|
||||||
publicKey = "FtY2lcdWcw+nvtydOOUDyaeh/xkaqHA8y9GXzqU0Am0=";
|
publicKey = "FtY2lcdWcw+nvtydOOUDyaeh/xkaqHA8y9GXzqU0Am0=";
|
||||||
};
|
};
|
||||||
|
|
||||||
"atlan-pc" = {
|
"atlan-pc" = {
|
||||||
role = "client";
|
role = "client";
|
||||||
address = [ "10.100.0.5/24" ];
|
address = "10.100.0.5";
|
||||||
allowedIPs = [ "10.100.0.5/32" ];
|
allowedIPs = [ "10.100.0.5/32" ];
|
||||||
publicKey = "TrJ4UAF//zXdaLwZudI78L+rTC36zEDodTDOWNS4Y1Y=";
|
publicKey = "TrJ4UAF//zXdaLwZudI78L+rTC36zEDodTDOWNS4Y1Y=";
|
||||||
};
|
};
|
||||||
|
|
||||||
"hetzner" = {
|
"hetzner" = {
|
||||||
role = "client";
|
role = "client";
|
||||||
address = [ "10.100.0.6/24" ];
|
address = "10.100.0.6";
|
||||||
allowedIPs = [ "10.100.0.6/32" ];
|
allowedIPs = [ "10.100.0.6/32" ];
|
||||||
publicKey = "csRzgwtnzmSLeLkSwTwEOrdKq55UOxZacR5D3GopCTQ=";
|
publicKey = "csRzgwtnzmSLeLkSwTwEOrdKq55UOxZacR5D3GopCTQ=";
|
||||||
};
|
};
|
||||||
|
|
||||||
"fanny" = {
|
"fanny" = {
|
||||||
role = "client";
|
role = "client";
|
||||||
address = [ "10.100.0.101/24" ];
|
address = "10.100.0.101";
|
||||||
allowedIPs = [ "10.100.0.101/32" ];
|
allowedIPs = [ "10.100.0.101/32" ];
|
||||||
publicKey = "3U59F6T1s/1LaZBIa6wB0qsVuO6pRR9jfYZJIH2piAU=";
|
publicKey = "3U59F6T1s/1LaZBIa6wB0qsVuO6pRR9jfYZJIH2piAU=";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
"backup0" = {
|
||||||
|
role = "client";
|
||||||
|
address = "10.100.0.20";
|
||||||
|
allowedIPs = [ "10.100.0.20/32" ];
|
||||||
|
publicKey = "Pp55Jg//jREzHdbbIqTXc9N7rnLZIFw904qh6NLrACE=";
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
51
machines/modules/malobeo/printing.nix
Normal file
51
machines/modules/malobeo/printing.nix
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
cfg = config.services.malobeo.printing;
|
||||||
|
driverFile = pkgs.writeTextDir "share/cups/model/konicaminoltac258.ppd" (builtins.readFile ../KOC658UX.ppd);
|
||||||
|
|
||||||
|
defaultPpdOptions = {
|
||||||
|
PageSize = "A4";
|
||||||
|
SelectColor = "Grayscale";
|
||||||
|
Finisher = "FS534";
|
||||||
|
SaddleUnit = "SD511";
|
||||||
|
Model = "C258";
|
||||||
|
InputSlot = "Tray1";
|
||||||
|
};
|
||||||
|
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.services.malobeo.printing = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = "Setup malobeo printers";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf (cfg.enable) {
|
||||||
|
services.printing.enable = true;
|
||||||
|
services.printing.drivers = [
|
||||||
|
driverFile
|
||||||
|
];
|
||||||
|
|
||||||
|
hardware.printers.ensurePrinters = [ {
|
||||||
|
name = "KonicaDefault";
|
||||||
|
model = "konicaminoltac258.ppd";
|
||||||
|
location = "Zine Workshop";
|
||||||
|
deviceUri = "ipp://192.168.1.42/ipp";
|
||||||
|
ppdOptions = defaultPpdOptions;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "KonicaBooklet";
|
||||||
|
model = "konicaminoltac258.ppd";
|
||||||
|
location = "Zine Workshop";
|
||||||
|
deviceUri = "ipp://192.168.1.42/ipp";
|
||||||
|
ppdOptions = defaultPpdOptions // {
|
||||||
|
Fold = "Stitch";
|
||||||
|
Staple = "None";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -9,12 +9,17 @@ in
|
|||||||
malobeo = lib.mkOption {
|
malobeo = lib.mkOption {
|
||||||
type = lib.types.bool;
|
type = lib.types.bool;
|
||||||
default = true;
|
default = true;
|
||||||
description = "enable malobeo user, defaults to on";
|
description = "enable malobeo user, defaults to on, ";
|
||||||
};
|
};
|
||||||
admin = lib.mkOption {
|
admin = lib.mkOption {
|
||||||
type = lib.types.bool;
|
type = lib.types.bool;
|
||||||
default = true;
|
default = true;
|
||||||
description = "enable admin user, defaults to on to prevent lockouts";
|
description = "enable admin user, defaults to on to prevent lockouts, passwordless sudo access";
|
||||||
|
};
|
||||||
|
backup = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = false;
|
||||||
|
description = "enable backup user, ";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
config = lib.mkMerge [
|
config = lib.mkMerge [
|
||||||
@@ -50,6 +55,30 @@ in
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
})
|
})
|
||||||
|
(lib.mkIf cfg.backup {
|
||||||
|
users.users.backup = {
|
||||||
|
isNormalUser = true;
|
||||||
|
hashedPassword = null;
|
||||||
|
openssh.authorizedKeys.keys = sshKeys.backup;
|
||||||
|
description = "backup user for pull style backups, can only use zfs commands";
|
||||||
|
};
|
||||||
|
environment.systemPackages = with pkgs; [];
|
||||||
|
security.sudo.extraRules = [
|
||||||
|
{
|
||||||
|
users = [ "backup" ];
|
||||||
|
commands = [
|
||||||
|
{
|
||||||
|
command = "/run/current-system/sw/bin/zfs";
|
||||||
|
options = [ "NOPASSWD" ];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
command = "/run/current-system/sw/bin/zpool";
|
||||||
|
options = [ "NOPASSWD" ];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
})
|
||||||
{
|
{
|
||||||
users.mutableUsers = false;
|
users.mutableUsers = false;
|
||||||
services.openssh.hostKeys = [
|
services.openssh.hostKeys = [
|
||||||
@@ -69,4 +98,4 @@ in
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ in
|
|||||||
interfaces = {
|
interfaces = {
|
||||||
malovpn = {
|
malovpn = {
|
||||||
mtu = 1340; #seems to be necessary to proxypass nginx traffic through vpn
|
mtu = 1340; #seems to be necessary to proxypass nginx traffic through vpn
|
||||||
address = myPeer.address;
|
address = [ "${myPeer.address}/24" ];
|
||||||
autostart = cfg.autostart;
|
autostart = cfg.autostart;
|
||||||
listenPort = mkIf (myPeer.role == "server") myPeer.listenPort;
|
listenPort = mkIf (myPeer.role == "server") myPeer.listenPort;
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ with lib;
|
|||||||
};
|
};
|
||||||
extraAppsEnable = true;
|
extraAppsEnable = true;
|
||||||
extraApps = {
|
extraApps = {
|
||||||
inherit (config.services.nextcloud.package.packages.apps) contacts calendar deck polls;
|
inherit (config.services.nextcloud.package.packages.apps) contacts calendar deck polls registration;
|
||||||
collectives = pkgs.fetchNextcloudApp {
|
collectives = pkgs.fetchNextcloudApp {
|
||||||
sha256 = "sha256-cj/8FhzxOACJaUEu0eG9r7iAQmnOG62yFHeyUICalFY=";
|
sha256 = "sha256-cj/8FhzxOACJaUEu0eG9r7iAQmnOG62yFHeyUICalFY=";
|
||||||
url = "https://github.com/nextcloud/collectives/releases/download/v2.15.2/collectives-2.15.2.tar.gz";
|
url = "https://github.com/nextcloud/collectives/releases/download/v2.15.2/collectives-2.15.2.tar.gz";
|
||||||
@@ -56,6 +56,7 @@ with lib;
|
|||||||
};
|
};
|
||||||
settings = {
|
settings = {
|
||||||
trusted_domains = ["10.0.0.13"];
|
trusted_domains = ["10.0.0.13"];
|
||||||
|
trusted_proxies = [ "10.0.0.1" ];
|
||||||
"maintenance_window_start" = "1";
|
"maintenance_window_start" = "1";
|
||||||
"default_phone_region" = "DE";
|
"default_phone_region" = "DE";
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -107,6 +107,12 @@ with lib;
|
|||||||
targets = [ "10.0.0.13:9002" ];
|
targets = [ "10.0.0.13:9002" ];
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
job_name = "zineshop";
|
||||||
|
static_configs = [{
|
||||||
|
targets = [ "10.0.0.15:9002" ];
|
||||||
|
}];
|
||||||
|
}
|
||||||
{
|
{
|
||||||
job_name = "fanny";
|
job_name = "fanny";
|
||||||
static_configs = [{
|
static_configs = [{
|
||||||
|
|||||||
@@ -5,4 +5,8 @@
|
|||||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINQg6a2EGmq+i9lfwU+SRMQ8MGN3is3VS6janzl9qOHo quaseb67@hzdr.de"
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINQg6a2EGmq+i9lfwU+SRMQ8MGN3is3VS6janzl9qOHo quaseb67@hzdr.de"
|
||||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICKaEcGaSKU0xC5qCwzj2oCLLG4PYjWHZ7/CXHw4urVk atlan@nixos"
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICKaEcGaSKU0xC5qCwzj2oCLLG4PYjWHZ7/CXHw4urVk atlan@nixos"
|
||||||
];
|
];
|
||||||
|
backup = [
|
||||||
|
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDIGryhnXdmbGObONG88K+c9zeduMrwtoLHwzMDZg3UXB+Cnq2FXWOrlLZxA+95VUgHpyGZiykJmzeWrKhldDlDeGGd8QCCLeuliiOgXADTYjWaVfhd+6arPZrK2VtqqsguvH40gW1xfoGAOmAT4WFnxWxIaEip0V2u6NOoKTiH9I3bz2Qe4lfJvPXig+XwCXcukXd6XUkDFYDpiw8XNV3X7pqTus5d2RYR97bAhIYZZQ6h50ZpTY8N0lFh4RY5yfx8BhxJW3tfoi9uZvVuPx7dGPsZsSniENFPMNz3UwHGitTJMr4088cJrAGgd5lyFuLouiHiM2JMGA0wx9wWTbWJEwTLaTVQK9gSJf857ndV2zCh9vKlfko4w9bQgqxKg4U/mY8dXX1E7D51nD2ci8Ed+ZG+NEneFLyZhLsD82GkBY+YovA+4xm/pcx+hBhlyqGNxI8v+Jh+JhEyD/ZLgJfq3ZMbGIGsTiDwZ2flLLxImHHEoDoT6PHU6hDhPDJu560="
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJKl5FWPskhlnzJs1+mMYrVTMNnRG92uFKUgGlteTPhL"
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,15 @@ with lib;
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
virtualHosts."shop.malobeo.org" = {
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://10.100.0.101";
|
||||||
|
extraConfig = ''
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
system.stateVersion = "22.11"; # Did you read the comment?
|
system.stateVersion = "22.11"; # Did you read the comment?
|
||||||
|
|||||||
34
machines/zineshop/configuration.nix
Normal file
34
machines/zineshop/configuration.nix
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{ self, config, lib, pkgs, inputs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
{
|
||||||
|
networking = {
|
||||||
|
hostName = mkDefault "zineshop";
|
||||||
|
useDHCP = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
imports = [
|
||||||
|
inputs.malobeo.nixosModules.malobeo.metrics
|
||||||
|
inputs.malobeo.nixosModules.malobeo.printing
|
||||||
|
inputs.zineshop.nixosModules.zineshop
|
||||||
|
../modules/malobeo_user.nix
|
||||||
|
../modules/sshd.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
malobeo.metrics = {
|
||||||
|
enable = true;
|
||||||
|
enablePromtail = true;
|
||||||
|
logNginx = true;
|
||||||
|
lokiHost = "10.0.0.14";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.printing.enable = true;
|
||||||
|
services.malobeo.printing.enable = true;
|
||||||
|
|
||||||
|
services.zineshop.enable = true;
|
||||||
|
networking.firewall.allowedTCPPorts = [ 8080 ];
|
||||||
|
|
||||||
|
system.stateVersion = "22.11"; # Did you read the comment?
|
||||||
|
}
|
||||||
|
|
||||||
@@ -116,6 +116,8 @@ in (utils.lib.eachSystem (builtins.filter filter_system utils.lib.defaultSystems
|
|||||||
metrics.imports = [ ./machines/modules/malobeo/metrics.nix ];
|
metrics.imports = [ ./machines/modules/malobeo/metrics.nix ];
|
||||||
disko.imports = [ ./machines/modules/disko ];
|
disko.imports = [ ./machines/modules/disko ];
|
||||||
users.imports = [ ./machines/modules/malobeo/users.nix ];
|
users.imports = [ ./machines/modules/malobeo/users.nix ];
|
||||||
|
backup.imports = [ ./machines/modules/malobeo/backup.nix ];
|
||||||
|
printing.imports = [ ./machines/modules/malobeo/printing.nix ];
|
||||||
};
|
};
|
||||||
|
|
||||||
hydraJobs = nixpkgs.lib.mapAttrs (_: nixpkgs.lib.hydraJob) (
|
hydraJobs = nixpkgs.lib.mapAttrs (_: nixpkgs.lib.hydraJob) (
|
||||||
|
|||||||
Reference in New Issue
Block a user