mirror of
https://github.com/RichieCahill/dotfiles.git
synced 2026-04-21 14:49:10 -04:00
Compare commits
15 Commits
feature/ad
...
feature/bu
| Author | SHA1 | Date | |
|---|---|---|---|
| 2b2d9135c5 | |||
| 81c0ce0928 | |||
| a16daf0e5e | |||
| 55e45d5e84 | |||
| dbd8d5eee3 | |||
| c89bc227f1 | |||
| 6ec355f567 | |||
| 78e51d7c12 | |||
| 96fc29e23a | |||
| 251089990e | |||
| 7364707277 | |||
| 6cefc275a8 | |||
| 74bb89f863 | |||
| ee581e6904 | |||
| c2182c7feb |
2
.github/workflows/build_systems.yml
vendored
2
.github/workflows/build_systems.yml
vendored
@@ -25,4 +25,4 @@ jobs:
|
|||||||
- name: Build default package
|
- name: Build default package
|
||||||
run: "nixos-rebuild build --flake ./#${{ matrix.system }}"
|
run: "nixos-rebuild build --flake ./#${{ matrix.system }}"
|
||||||
- name: copy to nix-cache
|
- name: copy to nix-cache
|
||||||
run: nix copy --accept-flake-config --to unix:///host-nix/var/nix/daemon-socket/socket .#nixosConfigurations.${{ matrix.system }}.config.system.build.toplevel
|
run: nix copy --to ssh://jeeves .#nixosConfigurations.${{ matrix.system }}.config.system.build.toplevel
|
||||||
|
|||||||
13
.vscode/settings.json
vendored
13
.vscode/settings.json
vendored
@@ -81,6 +81,7 @@
|
|||||||
"FASTFOX",
|
"FASTFOX",
|
||||||
"ffmpegthumbnailer",
|
"ffmpegthumbnailer",
|
||||||
"filebot",
|
"filebot",
|
||||||
|
"filebrowser",
|
||||||
"fileroller",
|
"fileroller",
|
||||||
"findbar",
|
"findbar",
|
||||||
"Fira",
|
"Fira",
|
||||||
@@ -97,7 +98,6 @@
|
|||||||
"getch",
|
"getch",
|
||||||
"getmaxyx",
|
"getmaxyx",
|
||||||
"ghdeploy",
|
"ghdeploy",
|
||||||
"gitea",
|
|
||||||
"globalprivacycontrol",
|
"globalprivacycontrol",
|
||||||
"gparted",
|
"gparted",
|
||||||
"gtts",
|
"gtts",
|
||||||
@@ -116,9 +116,7 @@
|
|||||||
"httpchk",
|
"httpchk",
|
||||||
"hurlenko",
|
"hurlenko",
|
||||||
"hwloc",
|
"hwloc",
|
||||||
"ical",
|
|
||||||
"ignorelist",
|
"ignorelist",
|
||||||
"improv",
|
|
||||||
"INITDB",
|
"INITDB",
|
||||||
"iocharset",
|
"iocharset",
|
||||||
"ioit",
|
"ioit",
|
||||||
@@ -128,8 +126,6 @@
|
|||||||
"jnoortheen",
|
"jnoortheen",
|
||||||
"jsbc",
|
"jsbc",
|
||||||
"kagi",
|
"kagi",
|
||||||
"keyformat",
|
|
||||||
"keylocation",
|
|
||||||
"kuma",
|
"kuma",
|
||||||
"lazer",
|
"lazer",
|
||||||
"levelname",
|
"levelname",
|
||||||
@@ -229,9 +225,12 @@
|
|||||||
"pylint",
|
"pylint",
|
||||||
"pymetno",
|
"pymetno",
|
||||||
"pymodbus",
|
"pymodbus",
|
||||||
"pyopenweathermap",
|
|
||||||
"pyownet",
|
"pyownet",
|
||||||
"pytest",
|
"pytest",
|
||||||
|
"qbit",
|
||||||
|
"qbittorrent",
|
||||||
|
"qbittorrentvpn",
|
||||||
|
"qbitvpn",
|
||||||
"quicksuggest",
|
"quicksuggest",
|
||||||
"radarr",
|
"radarr",
|
||||||
"readahead",
|
"readahead",
|
||||||
@@ -289,11 +288,9 @@
|
|||||||
"twimg",
|
"twimg",
|
||||||
"typer",
|
"typer",
|
||||||
"uaccess",
|
"uaccess",
|
||||||
"ubiquiti",
|
|
||||||
"ublock",
|
"ublock",
|
||||||
"uiprotect",
|
"uiprotect",
|
||||||
"uitour",
|
"uitour",
|
||||||
"unifi",
|
|
||||||
"unrar",
|
"unrar",
|
||||||
"unsubmitted",
|
"unsubmitted",
|
||||||
"uptimekuma",
|
"uptimekuma",
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
## Dev environment tips
|
|
||||||
|
|
||||||
- use treefmt to format all files
|
|
||||||
- make python code ruff compliant
|
|
||||||
- use pytest to test python code
|
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
./nh.nix
|
./nh.nix
|
||||||
./nix.nix
|
./nix.nix
|
||||||
./programs.nix
|
./programs.nix
|
||||||
|
./safe_reboot.nix
|
||||||
./ssh.nix
|
./ssh.nix
|
||||||
./snapshot_manager.nix
|
./snapshot_manager.nix
|
||||||
];
|
];
|
||||||
@@ -23,7 +24,7 @@
|
|||||||
boot = {
|
boot = {
|
||||||
tmp.useTmpfs = true;
|
tmp.useTmpfs = true;
|
||||||
kernelPackages = lib.mkDefault pkgs.linuxPackages_6_12;
|
kernelPackages = lib.mkDefault pkgs.linuxPackages_6_12;
|
||||||
zfs.package = lib.mkDefault pkgs.zfs_2_4;
|
zfs.package = lib.mkDefault pkgs.zfs_2_3;
|
||||||
};
|
};
|
||||||
|
|
||||||
hardware.enableRedistributableFirmware = true;
|
hardware.enableRedistributableFirmware = true;
|
||||||
@@ -49,6 +50,11 @@
|
|||||||
PYTHONPATH = "${inputs.self}/";
|
PYTHONPATH = "${inputs.self}/";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
safe_reboot = {
|
||||||
|
enable = lib.mkDefault true;
|
||||||
|
datasetPrefix = "root_pool/";
|
||||||
|
};
|
||||||
|
|
||||||
zfs = {
|
zfs = {
|
||||||
trim.enable = lib.mkDefault true;
|
trim.enable = lib.mkDefault true;
|
||||||
autoScrub.enable = lib.mkDefault true;
|
autoScrub.enable = lib.mkDefault true;
|
||||||
|
|||||||
56
common/global/safe_reboot.nix
Normal file
56
common/global/safe_reboot.nix
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
inputs,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
cfg = config.services.safe_reboot;
|
||||||
|
python_command =
|
||||||
|
lib.escapeShellArgs (
|
||||||
|
[
|
||||||
|
"${pkgs.my_python}/bin/python"
|
||||||
|
"-m"
|
||||||
|
"python.tools.safe_reboot"
|
||||||
|
]
|
||||||
|
++ lib.optionals (cfg.drivePath != null) [ cfg.drivePath ]
|
||||||
|
++ [
|
||||||
|
"--dataset-prefix"
|
||||||
|
cfg.datasetPrefix
|
||||||
|
"--check-only"
|
||||||
|
]
|
||||||
|
);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.services.safe_reboot = {
|
||||||
|
enable = lib.mkEnableOption "Safe reboot dataset/drive validation";
|
||||||
|
datasetPrefix = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "root_pool/";
|
||||||
|
description = "Dataset prefix that must have exec enabled before rebooting.";
|
||||||
|
};
|
||||||
|
drivePath = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.str;
|
||||||
|
default = null;
|
||||||
|
description = "Drive path that must exist before rebooting. Set to null to skip.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
systemd.services.safe-reboot-check = {
|
||||||
|
description = "Safe reboot validation";
|
||||||
|
before = [ "systemd-reboot.service" ];
|
||||||
|
wantedBy = [ "reboot.target" ];
|
||||||
|
partOf = [ "reboot.target" ];
|
||||||
|
path = [ pkgs.zfs ];
|
||||||
|
environment = {
|
||||||
|
PYTHONPATH = "${inputs.self}/";
|
||||||
|
};
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
ExecStart = python_command;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
boot = {
|
boot = {
|
||||||
kernelPackages = pkgs.linuxPackages_6_18;
|
kernelPackages = pkgs.linuxPackages_6_17;
|
||||||
zfs.package = pkgs.zfs_2_4;
|
zfs.package = pkgs.zfs_unstable;
|
||||||
};
|
};
|
||||||
|
|
||||||
hardware.bluetooth = {
|
hardware.bluetooth = {
|
||||||
|
|||||||
129
esphome/batteries.yml
Normal file
129
esphome/batteries.yml
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
esphome:
|
||||||
|
name: batteries
|
||||||
|
friendly_name: batteries
|
||||||
|
|
||||||
|
esp32:
|
||||||
|
board: esp32dev
|
||||||
|
framework:
|
||||||
|
type: arduino
|
||||||
|
|
||||||
|
logger:
|
||||||
|
|
||||||
|
api:
|
||||||
|
encryption:
|
||||||
|
key: !secret api_key
|
||||||
|
|
||||||
|
external_components:
|
||||||
|
- source: github://syssi/esphome-jk-bms@main
|
||||||
|
|
||||||
|
ota:
|
||||||
|
- platform: esphome
|
||||||
|
password: !secret ota_password
|
||||||
|
|
||||||
|
wifi:
|
||||||
|
ssid: !secret wifi_ssid
|
||||||
|
password: !secret wifi_password
|
||||||
|
|
||||||
|
captive_portal:
|
||||||
|
|
||||||
|
esp32_ble_tracker:
|
||||||
|
scan_parameters:
|
||||||
|
interval: 1100ms
|
||||||
|
window: 1100ms
|
||||||
|
active: true
|
||||||
|
|
||||||
|
ble_client:
|
||||||
|
- mac_address: "C8:47:80:29:0F:DB"
|
||||||
|
id: jk_ble0
|
||||||
|
- mac_address: "C8:47:80:37:9D:DD"
|
||||||
|
id: jk_ble1
|
||||||
|
|
||||||
|
jk_bms_ble:
|
||||||
|
- ble_client_id: jk_ble0
|
||||||
|
protocol_version: JK02_32S
|
||||||
|
throttle: 1s
|
||||||
|
id: jk_bms0
|
||||||
|
|
||||||
|
- ble_client_id: jk_ble1
|
||||||
|
protocol_version: JK02_32S
|
||||||
|
throttle: 1s
|
||||||
|
id: jk_bms1
|
||||||
|
|
||||||
|
sensor:
|
||||||
|
# BMS1 sensors
|
||||||
|
- platform: jk_bms_ble
|
||||||
|
jk_bms_ble_id: jk_bms0
|
||||||
|
total_voltage:
|
||||||
|
name: "JK0 Total Voltage"
|
||||||
|
current:
|
||||||
|
name: "JK0 Current"
|
||||||
|
state_of_charge:
|
||||||
|
name: "JK0 SoC"
|
||||||
|
power:
|
||||||
|
name: "JK0 Power"
|
||||||
|
temperature_sensor_1:
|
||||||
|
name: "JK0 Temp 1"
|
||||||
|
temperature_sensor_2:
|
||||||
|
name: "JK0 Temp 2"
|
||||||
|
balancing:
|
||||||
|
name: "JK0 balancing"
|
||||||
|
charging_cycles:
|
||||||
|
name: "JK0 charging cycles"
|
||||||
|
total_runtime:
|
||||||
|
name: "JK0 total runtime"
|
||||||
|
balancing_current:
|
||||||
|
name: "JK0 balancing current"
|
||||||
|
|
||||||
|
# BMS2 sensors
|
||||||
|
- platform: jk_bms_ble
|
||||||
|
jk_bms_ble_id: jk_bms1
|
||||||
|
total_voltage:
|
||||||
|
name: "JK1 Total Voltage"
|
||||||
|
current:
|
||||||
|
name: "JK1 Current"
|
||||||
|
state_of_charge:
|
||||||
|
name: "JK1 SoC"
|
||||||
|
power:
|
||||||
|
name: "Jk1 Power"
|
||||||
|
temperature_sensor_1:
|
||||||
|
name: "JK1 Temp 1"
|
||||||
|
temperature_sensor_2:
|
||||||
|
name: "Jk1 Temp 2"
|
||||||
|
balancing:
|
||||||
|
name: "JK1 balancing"
|
||||||
|
charging_cycles:
|
||||||
|
name: "JK1 charging cycles"
|
||||||
|
total_runtime:
|
||||||
|
name: "JK1 total runtime"
|
||||||
|
balancing_current:
|
||||||
|
name: "JK1 balancing current"
|
||||||
|
|
||||||
|
text_sensor:
|
||||||
|
- platform: jk_bms_ble
|
||||||
|
jk_bms_ble_id: jk_bms0
|
||||||
|
errors:
|
||||||
|
name: "JK0 Errors"
|
||||||
|
|
||||||
|
- platform: jk_bms_ble
|
||||||
|
jk_bms_ble_id: jk_bms1
|
||||||
|
errors:
|
||||||
|
name: "JK1 Errors"
|
||||||
|
|
||||||
|
switch:
|
||||||
|
- platform: jk_bms_ble
|
||||||
|
jk_bms_ble_id: jk_bms0
|
||||||
|
charging:
|
||||||
|
name: "JK0 Charging"
|
||||||
|
discharging:
|
||||||
|
name: "JK0 Discharging"
|
||||||
|
balancer:
|
||||||
|
name: "JK0 Balancing"
|
||||||
|
|
||||||
|
- platform: jk_bms_ble
|
||||||
|
jk_bms_ble_id: jk_bms1
|
||||||
|
charging:
|
||||||
|
name: "JK1 Charging"
|
||||||
|
discharging:
|
||||||
|
name: "JK1 Discharging"
|
||||||
|
balancer:
|
||||||
|
name: "JK1 Balancing"
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
esphome:
|
|
||||||
name: batteries
|
|
||||||
friendly_name: batteries
|
|
||||||
|
|
||||||
esp32:
|
|
||||||
board: esp32dev
|
|
||||||
framework:
|
|
||||||
type: arduino
|
|
||||||
|
|
||||||
logger:
|
|
||||||
|
|
||||||
api:
|
|
||||||
encryption:
|
|
||||||
key: !secret api_key
|
|
||||||
|
|
||||||
external_components:
|
|
||||||
- source: github://syssi/esphome-jk-bms@main
|
|
||||||
|
|
||||||
ota:
|
|
||||||
- platform: esphome
|
|
||||||
password: !secret ota_password
|
|
||||||
|
|
||||||
wifi:
|
|
||||||
ssid: !secret wifi_ssid
|
|
||||||
password: !secret wifi_password
|
|
||||||
fast_connect: on
|
|
||||||
|
|
||||||
captive_portal:
|
|
||||||
|
|
||||||
esp32_ble_tracker:
|
|
||||||
scan_parameters:
|
|
||||||
interval: 1100ms
|
|
||||||
window: 1100ms
|
|
||||||
active: true
|
|
||||||
|
|
||||||
ble_client:
|
|
||||||
- mac_address: "C8:47:80:29:0F:DB"
|
|
||||||
id: jk_ble0
|
|
||||||
|
|
||||||
jk_bms_ble:
|
|
||||||
- ble_client_id: jk_ble0
|
|
||||||
protocol_version: JK02_32S
|
|
||||||
throttle: 1s
|
|
||||||
id: jk_bms0
|
|
||||||
|
|
||||||
button:
|
|
||||||
- platform: jk_bms_ble
|
|
||||||
retrieve_settings:
|
|
||||||
name: "JK0 retrieve settings"
|
|
||||||
retrieve_device_info:
|
|
||||||
name: "JK0 retrieve device info"
|
|
||||||
|
|
||||||
sensor:
|
|
||||||
- platform: jk_bms_ble
|
|
||||||
jk_bms_ble_id: jk_bms0
|
|
||||||
total_voltage:
|
|
||||||
name: "JK0 Total Voltage"
|
|
||||||
state_of_charge:
|
|
||||||
name: "JK0 SoC"
|
|
||||||
charging_power:
|
|
||||||
name: "JK0 charging power"
|
|
||||||
discharging_power:
|
|
||||||
name: "JK0 discharging power"
|
|
||||||
temperature_sensor_1:
|
|
||||||
name: "JK0 Temp 1"
|
|
||||||
temperature_sensor_2:
|
|
||||||
name: "JK0 Temp 2"
|
|
||||||
balancing:
|
|
||||||
name: "JK0 balancing"
|
|
||||||
total_runtime:
|
|
||||||
name: "JK0 total runtime"
|
|
||||||
balancing_current:
|
|
||||||
name: "JK0 balancing current"
|
|
||||||
delta_cell_voltage:
|
|
||||||
name: "JK0 cell delta voltage"
|
|
||||||
average_cell_voltage:
|
|
||||||
name: "JK0 cell average voltage"
|
|
||||||
cell_voltage_1:
|
|
||||||
name: "JK0 cell voltage 1"
|
|
||||||
cell_voltage_2:
|
|
||||||
name: "JK0 cell voltage 2"
|
|
||||||
cell_voltage_3:
|
|
||||||
name: "JK0 cell voltage 3"
|
|
||||||
cell_voltage_4:
|
|
||||||
name: "JK0 cell voltage 4"
|
|
||||||
cell_voltage_5:
|
|
||||||
name: "JK0 cell voltage 5"
|
|
||||||
cell_voltage_6:
|
|
||||||
name: "JK0 cell voltage 6"
|
|
||||||
cell_voltage_7:
|
|
||||||
name: "JK0 cell voltage 7"
|
|
||||||
cell_voltage_8:
|
|
||||||
name: "JK0 cell voltage 8"
|
|
||||||
cell_resistance_1:
|
|
||||||
name: "JK0 cell resistance 1"
|
|
||||||
cell_resistance_2:
|
|
||||||
name: "JK0 cell resistance 2"
|
|
||||||
cell_resistance_3:
|
|
||||||
name: "JK0 cell resistance 3"
|
|
||||||
cell_resistance_4:
|
|
||||||
name: "JK0 cell resistance 4"
|
|
||||||
cell_resistance_5:
|
|
||||||
name: "JK0 cell resistance 5"
|
|
||||||
cell_resistance_6:
|
|
||||||
name: "JK0 cell resistance 6"
|
|
||||||
cell_resistance_7:
|
|
||||||
name: "JK0 cell resistance 7"
|
|
||||||
cell_resistance_8:
|
|
||||||
name: "JK0 cell resistance 8"
|
|
||||||
total_charging_cycle_capacity:
|
|
||||||
name: "JK0 total charging cycle capacity"
|
|
||||||
|
|
||||||
text_sensor:
|
|
||||||
- platform: jk_bms_ble
|
|
||||||
jk_bms_ble_id: jk_bms0
|
|
||||||
errors:
|
|
||||||
name: "JK0 Errors"
|
|
||||||
|
|
||||||
switch:
|
|
||||||
- platform: jk_bms_ble
|
|
||||||
jk_bms_ble_id: jk_bms0
|
|
||||||
charging:
|
|
||||||
name: "JK0 Charging"
|
|
||||||
discharging:
|
|
||||||
name: "JK0 Discharging"
|
|
||||||
balancer:
|
|
||||||
name: "JK0 Balancing"
|
|
||||||
|
|
||||||
- platform: ble_client
|
|
||||||
ble_client_id: jk_ble0
|
|
||||||
name: "JK0 enable bluetooth connection"
|
|
||||||
id: ble_client_switch0
|
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
esphome:
|
|
||||||
name: battery1
|
|
||||||
friendly_name: battery1
|
|
||||||
|
|
||||||
esp32:
|
|
||||||
board: esp32dev
|
|
||||||
framework:
|
|
||||||
type: arduino
|
|
||||||
|
|
||||||
logger:
|
|
||||||
|
|
||||||
api:
|
|
||||||
encryption:
|
|
||||||
key: !secret api_key
|
|
||||||
|
|
||||||
external_components:
|
|
||||||
- source: github://syssi/esphome-jk-bms@main
|
|
||||||
|
|
||||||
ota:
|
|
||||||
- platform: esphome
|
|
||||||
password: !secret ota_password
|
|
||||||
|
|
||||||
wifi:
|
|
||||||
ssid: !secret wifi_ssid
|
|
||||||
password: !secret wifi_password
|
|
||||||
fast_connect: on
|
|
||||||
|
|
||||||
captive_portal:
|
|
||||||
|
|
||||||
esp32_ble_tracker:
|
|
||||||
scan_parameters:
|
|
||||||
interval: 1100ms
|
|
||||||
window: 1100ms
|
|
||||||
active: true
|
|
||||||
|
|
||||||
ble_client:
|
|
||||||
- mac_address: "C8:47:80:37:9D:DD"
|
|
||||||
id: jk_ble1
|
|
||||||
|
|
||||||
jk_bms_ble:
|
|
||||||
- ble_client_id: jk_ble1
|
|
||||||
protocol_version: JK02_32S
|
|
||||||
throttle: 1s
|
|
||||||
id: jk_bms1
|
|
||||||
|
|
||||||
button:
|
|
||||||
- platform: jk_bms_ble
|
|
||||||
retrieve_settings:
|
|
||||||
name: "JK1 retrieve settings"
|
|
||||||
retrieve_device_info:
|
|
||||||
name: "JK1 retrieve device info"
|
|
||||||
|
|
||||||
sensor:
|
|
||||||
- platform: jk_bms_ble
|
|
||||||
jk_bms_ble_id: jk_bms1
|
|
||||||
total_voltage:
|
|
||||||
name: "JK1 Total Voltage"
|
|
||||||
state_of_charge:
|
|
||||||
name: "JK1 SoC"
|
|
||||||
charging_power:
|
|
||||||
name: "JK1 charging power"
|
|
||||||
discharging_power:
|
|
||||||
name: "JK1 discharging power"
|
|
||||||
temperature_sensor_1:
|
|
||||||
name: "JK1 Temp 1"
|
|
||||||
temperature_sensor_2:
|
|
||||||
name: "JK1 Temp 2"
|
|
||||||
balancing:
|
|
||||||
name: "JK1 balancing"
|
|
||||||
total_runtime:
|
|
||||||
name: "JK1 total runtime"
|
|
||||||
balancing_current:
|
|
||||||
name: "JK1 balancing current"
|
|
||||||
delta_cell_voltage:
|
|
||||||
name: "JK1 cell delta voltage"
|
|
||||||
average_cell_voltage:
|
|
||||||
name: "JK1 cell average voltage"
|
|
||||||
cell_voltage_1:
|
|
||||||
name: "JK1 cell voltage 1"
|
|
||||||
cell_voltage_2:
|
|
||||||
name: "JK1 cell voltage 2"
|
|
||||||
cell_voltage_3:
|
|
||||||
name: "JK1 cell voltage 3"
|
|
||||||
cell_voltage_4:
|
|
||||||
name: "JK1 cell voltage 4"
|
|
||||||
cell_voltage_5:
|
|
||||||
name: "JK1 cell voltage 5"
|
|
||||||
cell_voltage_6:
|
|
||||||
name: "JK1 cell voltage 6"
|
|
||||||
cell_voltage_7:
|
|
||||||
name: "JK1 cell voltage 7"
|
|
||||||
cell_voltage_8:
|
|
||||||
name: "JK1 cell voltage 8"
|
|
||||||
cell_resistance_1:
|
|
||||||
name: "JK1 cell resistance 1"
|
|
||||||
cell_resistance_2:
|
|
||||||
name: "JK1 cell resistance 2"
|
|
||||||
cell_resistance_3:
|
|
||||||
name: "JK1 cell resistance 3"
|
|
||||||
cell_resistance_4:
|
|
||||||
name: "JK1 cell resistance 4"
|
|
||||||
cell_resistance_5:
|
|
||||||
name: "JK1 cell resistance 5"
|
|
||||||
cell_resistance_6:
|
|
||||||
name: "JK1 cell resistance 6"
|
|
||||||
cell_resistance_7:
|
|
||||||
name: "JK1 cell resistance 7"
|
|
||||||
cell_resistance_8:
|
|
||||||
name: "JK1 cell resistance 8"
|
|
||||||
total_charging_cycle_capacity:
|
|
||||||
name: "JK1 total charging cycle capacity"
|
|
||||||
|
|
||||||
text_sensor:
|
|
||||||
- platform: jk_bms_ble
|
|
||||||
jk_bms_ble_id: jk_bms1
|
|
||||||
errors:
|
|
||||||
name: "JK1 Errors"
|
|
||||||
|
|
||||||
switch:
|
|
||||||
- platform: jk_bms_ble
|
|
||||||
jk_bms_ble_id: jk_bms1
|
|
||||||
charging:
|
|
||||||
name: "JK1 Charging"
|
|
||||||
discharging:
|
|
||||||
name: "JK1 Discharging"
|
|
||||||
balancer:
|
|
||||||
name: "JK1 Balancing"
|
|
||||||
|
|
||||||
- platform: ble_client
|
|
||||||
ble_client_id: jk_ble1
|
|
||||||
name: "JK1 enable bluetooth connection"
|
|
||||||
id: ble_client_switch0
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
esphome:
|
|
||||||
name: "environment"
|
|
||||||
friendly_name: "environment"
|
|
||||||
|
|
||||||
esp32:
|
|
||||||
board: esp32dev
|
|
||||||
framework:
|
|
||||||
type: arduino
|
|
||||||
|
|
||||||
i2c:
|
|
||||||
sda: GPIO21
|
|
||||||
scl: GPIO22
|
|
||||||
scan: True
|
|
||||||
id: bus_a
|
|
||||||
|
|
||||||
sensor:
|
|
||||||
- platform: aht10
|
|
||||||
i2c_id: bus_a
|
|
||||||
address: 0x38
|
|
||||||
variant: AHT20
|
|
||||||
temperature:
|
|
||||||
name: "environment Temperature"
|
|
||||||
id: aht10_temperature
|
|
||||||
humidity:
|
|
||||||
name: "environment Humidity"
|
|
||||||
id: aht10_humidity
|
|
||||||
update_interval: 5s
|
|
||||||
|
|
||||||
web_server:
|
|
||||||
port: 80
|
|
||||||
|
|
||||||
logger:
|
|
||||||
level: DEBUG
|
|
||||||
|
|
||||||
api:
|
|
||||||
encryption:
|
|
||||||
key: !secret api_key
|
|
||||||
|
|
||||||
ota:
|
|
||||||
- platform: esphome
|
|
||||||
password: !secret ota_password
|
|
||||||
|
|
||||||
wifi:
|
|
||||||
ssid: !secret wifi_ssid
|
|
||||||
password: !secret wifi_password
|
|
||||||
fast_connect: on
|
|
||||||
|
|
||||||
captive_portal:
|
|
||||||
36
flake.lock
generated
36
flake.lock
generated
@@ -8,11 +8,11 @@
|
|||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"dir": "pkgs/firefox-addons",
|
"dir": "pkgs/firefox-addons",
|
||||||
"lastModified": 1766762570,
|
"lastModified": 1763697825,
|
||||||
"narHash": "sha256-Nevsj5NYurwp3I6nSMeh3uirwoinVSbCldqOXu4smms=",
|
"narHash": "sha256-AgCCcVPOi1tuzuW5/StlwqBjRWSX62oL97qWuxrq5UA=",
|
||||||
"owner": "rycee",
|
"owner": "rycee",
|
||||||
"repo": "nur-expressions",
|
"repo": "nur-expressions",
|
||||||
"rev": "03d7d310ea91d6e4b47ed70aa86c781fcc5b38e1",
|
"rev": "cefce78793603231be226fa77e7ad58e0e4899b8",
|
||||||
"type": "gitlab"
|
"type": "gitlab"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -29,11 +29,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1766682973,
|
"lastModified": 1763748372,
|
||||||
"narHash": "sha256-GKO35onS711ThCxwWcfuvbIBKXwriahGqs+WZuJ3v9E=",
|
"narHash": "sha256-AUc78Qv3sWir0hvbmfXoZ7Jzq9VVL97l+sP9Jgms+JU=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "91cdb0e2d574c64fae80d221f4bf09d5592e9ec2",
|
"rev": "d10a9b16b2a3ee28433f3d1c603f4e9f1fecb8e1",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -44,11 +44,11 @@
|
|||||||
},
|
},
|
||||||
"nixos-hardware": {
|
"nixos-hardware": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1766568855,
|
"lastModified": 1762847253,
|
||||||
"narHash": "sha256-UXVtN77D7pzKmzOotFTStgZBqpOcf8cO95FcupWp4Zo=",
|
"narHash": "sha256-BWWnUUT01lPwCWUvS0p6Px5UOBFeXJ8jR+ZdLX8IbrU=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixos-hardware",
|
"repo": "nixos-hardware",
|
||||||
"rev": "c5db9569ac9cc70929c268ac461f4003e3e5ca80",
|
"rev": "899dc449bc6428b9ee6b3b8f771ca2b0ef945ab9",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -60,11 +60,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1766651565,
|
"lastModified": 1763421233,
|
||||||
"narHash": "sha256-QEhk0eXgyIqTpJ/ehZKg9IKS7EtlWxF3N7DXy42zPfU=",
|
"narHash": "sha256-Stk9ZYRkGrnnpyJ4eqt9eQtdFWRRIvMxpNRf4sIegnw=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "3e2499d5539c16d0d173ba53552a4ff8547f4539",
|
"rev": "89c2b2330e733d6cdb5eae7b899326930c2c0648",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -76,11 +76,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs-master": {
|
"nixpkgs-master": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1766794443,
|
"lastModified": 1763774007,
|
||||||
"narHash": "sha256-Q8IyTQ3Lu8vX/iqO3U+E4pjLbP1NsqFih6uElf8OYrQ=",
|
"narHash": "sha256-PPeHfKA11P09kBkBD5pS3tIAFjnG5muHQnODQGTY87g=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "088b069b8270ee36d83533c86b9f91d924d185d9",
|
"rev": "8a7cf7e9e18384533d9ecd0bfbcf475ac1dc497e",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -125,11 +125,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1766289575,
|
"lastModified": 1763607916,
|
||||||
"narHash": "sha256-BOKCwOQQIP4p9z8DasT5r+qjri3x7sPCOq+FTjY8Z+o=",
|
"narHash": "sha256-VefBA1JWRXM929mBAFohFUtQJLUnEwZ2vmYUNkFnSjE=",
|
||||||
"owner": "Mic92",
|
"owner": "Mic92",
|
||||||
"repo": "sops-nix",
|
"repo": "sops-nix",
|
||||||
"rev": "9836912e37aef546029e48c8749834735a6b9dad",
|
"rev": "877bb495a6f8faf0d89fc10bd142c4b7ed2bcc0b",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
@@ -3,14 +3,14 @@
|
|||||||
# When applied, the stable nixpkgs set (declared in the flake inputs) will be accessible through 'pkgs.stable'
|
# When applied, the stable nixpkgs set (declared in the flake inputs) will be accessible through 'pkgs.stable'
|
||||||
stable = final: _prev: {
|
stable = final: _prev: {
|
||||||
stable = import inputs.nixpkgs-stable {
|
stable = import inputs.nixpkgs-stable {
|
||||||
system = final.stdenv.hostPlatform.system;
|
system = final.system;
|
||||||
config.allowUnfree = true;
|
config.allowUnfree = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
# When applied, the master nixpkgs set (declared in the flake inputs) will be accessible through 'pkgs.master'
|
# When applied, the master nixpkgs set (declared in the flake inputs) will be accessible through 'pkgs.master'
|
||||||
master = final: _prev: {
|
master = final: _prev: {
|
||||||
master = import inputs.nixpkgs-master {
|
master = import inputs.nixpkgs-master {
|
||||||
system = final.stdenv.hostPlatform.system;
|
system = final.system;
|
||||||
config.allowUnfree = true;
|
config.allowUnfree = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
111
python/tools/safe_reboot.py
Normal file
111
python/tools/safe_reboot.py
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
"""Safe reboot helper."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import TYPE_CHECKING, Annotated
|
||||||
|
|
||||||
|
import typer
|
||||||
|
|
||||||
|
from python.common import bash_wrapper, configure_logger
|
||||||
|
from python.zfs import Dataset, get_datasets
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from collections.abc import Sequence
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def get_root_pool_datasets(dataset_prefix: str) -> list[Dataset]:
|
||||||
|
"""Return datasets that start with the provided prefix."""
|
||||||
|
return [dataset for dataset in get_datasets() if dataset.name.startswith(dataset_prefix)]
|
||||||
|
|
||||||
|
|
||||||
|
def get_non_executable_datasets(datasets: Sequence[Dataset]) -> list[str]:
|
||||||
|
"""Return dataset names that have exec disabled."""
|
||||||
|
return [dataset.name for dataset in datasets if dataset.exec.lower() != "on"]
|
||||||
|
|
||||||
|
|
||||||
|
def drive_present(drive: str) -> bool:
|
||||||
|
"""Check whether the provided drive exists."""
|
||||||
|
drive_path = drive.strip()
|
||||||
|
if not drive_path:
|
||||||
|
error = "Drive path cannot be empty"
|
||||||
|
raise ValueError(error)
|
||||||
|
|
||||||
|
return Path(drive_path).exists()
|
||||||
|
|
||||||
|
|
||||||
|
def reboot_system() -> None:
|
||||||
|
"""Call systemctl reboot."""
|
||||||
|
output, return_code = bash_wrapper("systemctl reboot")
|
||||||
|
if return_code != 0:
|
||||||
|
raise RuntimeError(output.strip() or "Failed to issue reboot command")
|
||||||
|
|
||||||
|
|
||||||
|
def validate_state(drive: str | None, dataset_prefix: str) -> list[str]:
|
||||||
|
"""Validate dataset and drive state."""
|
||||||
|
datasets = get_root_pool_datasets(dataset_prefix)
|
||||||
|
|
||||||
|
errors: list[str] = []
|
||||||
|
if not datasets:
|
||||||
|
errors.append(f"No datasets found with prefix {dataset_prefix}")
|
||||||
|
else:
|
||||||
|
non_exec_datasets = get_non_executable_datasets(datasets)
|
||||||
|
if non_exec_datasets:
|
||||||
|
errors.append(f"Datasets missing exec=on: {', '.join(non_exec_datasets)}")
|
||||||
|
|
||||||
|
if drive:
|
||||||
|
try:
|
||||||
|
if not drive_present(drive):
|
||||||
|
errors.append(f"Drive {drive} is not present")
|
||||||
|
except ValueError as err:
|
||||||
|
errors.append(str(err))
|
||||||
|
|
||||||
|
return errors
|
||||||
|
|
||||||
|
|
||||||
|
def reboot(
|
||||||
|
drive: Annotated[str | None, typer.Argument(help="Drive that must exist before rebooting.")] = None,
|
||||||
|
dataset_prefix: Annotated[
|
||||||
|
str,
|
||||||
|
typer.Option(
|
||||||
|
"--dataset-prefix",
|
||||||
|
"-p",
|
||||||
|
help="Datasets with this prefix are validated.",
|
||||||
|
),
|
||||||
|
] = "root_pool/",
|
||||||
|
dry_run: Annotated[
|
||||||
|
bool,
|
||||||
|
typer.Option(
|
||||||
|
"--check-only",
|
||||||
|
help="Only validate state without issuing the reboot command.",
|
||||||
|
),
|
||||||
|
] = False,
|
||||||
|
) -> None:
|
||||||
|
"""Validate datasets and drive before rebooting."""
|
||||||
|
configure_logger()
|
||||||
|
logger.info("Starting safe reboot checks")
|
||||||
|
|
||||||
|
if errors := validate_state(drive, dataset_prefix):
|
||||||
|
for error in errors:
|
||||||
|
logger.error(error)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if dry_run:
|
||||||
|
logger.info("All checks passed")
|
||||||
|
return
|
||||||
|
|
||||||
|
logger.info("All checks passed, issuing reboot")
|
||||||
|
reboot_system()
|
||||||
|
|
||||||
|
|
||||||
|
def cli() -> None:
|
||||||
|
"""CLI entry point."""
|
||||||
|
typer.run(reboot)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
cli()
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
"Qihoo360-Light-R1-32B"
|
"Qihoo360-Light-R1-32B"
|
||||||
];
|
];
|
||||||
models = "/zfs/models";
|
models = "/zfs/models";
|
||||||
|
acceleration = "cuda";
|
||||||
openFirewall = true;
|
openFirewall = true;
|
||||||
};
|
};
|
||||||
# open-webui = {
|
# open-webui = {
|
||||||
|
|||||||
@@ -60,20 +60,16 @@
|
|||||||
extraPackages =
|
extraPackages =
|
||||||
python3Packages: with python3Packages; [
|
python3Packages: with python3Packages; [
|
||||||
aioesphomeapi # for esphome
|
aioesphomeapi # for esphome
|
||||||
aiounifi # for ubiquiti integration
|
|
||||||
bleak-esphome # for esphome
|
bleak-esphome # for esphome
|
||||||
esphome-dashboard-api # for esphome
|
esphome-dashboard-api # for esphome
|
||||||
forecast-solar # for solar forecast
|
forecast-solar # for solar forecast
|
||||||
gtts # not sure what wants this
|
gtts # not sure what wants this
|
||||||
ical # for todo
|
|
||||||
jellyfin-apiclient-python # for jellyfin
|
jellyfin-apiclient-python # for jellyfin
|
||||||
paho-mqtt # for mqtt
|
paho-mqtt # for mqtt
|
||||||
psycopg2 # for postgresql
|
psycopg2 # for postgresql
|
||||||
py-improv-ble-client # for esphome
|
py-improv-ble-client # for esphome
|
||||||
pymodbus # for modbus
|
pymodbus # for modbus
|
||||||
pyopenweathermap # for weather
|
pyopenweathermap # for weather
|
||||||
uiprotect # for ubiquiti integration
|
|
||||||
unifi-discovery # for ubiquiti integration
|
|
||||||
];
|
];
|
||||||
extraComponents = [ "isal" ];
|
extraComponents = [ "isal" ];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,45 @@
|
|||||||
|
template:
|
||||||
|
- sensor:
|
||||||
|
# Battery 0
|
||||||
|
- name: "JK0 charge power W"
|
||||||
|
unique_id: jk0_charge_power_w
|
||||||
|
unit_of_measurement: W
|
||||||
|
device_class: power
|
||||||
|
state_class: measurement
|
||||||
|
state: >
|
||||||
|
{% set p = states('sensor.batteries_jk0_power')|float(0) %}
|
||||||
|
{{ max(0, p) }}
|
||||||
|
- name: "JK0 discharge power W"
|
||||||
|
unique_id: jk0_discharge_power_w
|
||||||
|
unit_of_measurement: W
|
||||||
|
device_class: power
|
||||||
|
state_class: measurement
|
||||||
|
state: >
|
||||||
|
{% set p = states('sensor.batteries_jk0_power')|float(0) %}
|
||||||
|
{{ max(0, -p) }}
|
||||||
|
|
||||||
|
# Battery 1
|
||||||
|
- name: "JK1 charge power W"
|
||||||
|
unique_id: jk1_charge_power_w
|
||||||
|
unit_of_measurement: W
|
||||||
|
device_class: power
|
||||||
|
state_class: measurement
|
||||||
|
state: >
|
||||||
|
{% set p = states('sensor.batteries_jk1_power')|float(0) %}
|
||||||
|
{{ max(0, p) }}
|
||||||
|
- name: "JK1 discharge power W"
|
||||||
|
unique_id: jk1_discharge_power_w
|
||||||
|
unit_of_measurement: W
|
||||||
|
device_class: power
|
||||||
|
state_class: measurement
|
||||||
|
state: >
|
||||||
|
{% set p = states('sensor.batteries_jk1_power')|float(0) %}
|
||||||
|
{{ max(0, -p) }}
|
||||||
|
|
||||||
sensor:
|
sensor:
|
||||||
# Battery 0
|
# Battery 0
|
||||||
- platform: integration
|
- platform: integration
|
||||||
source: sensor.batteries_jk0_charging_power
|
source: sensor.jk0_charge_power_w
|
||||||
name: "JK0 energy in"
|
name: "JK0 energy in"
|
||||||
unique_id: jk0_energy_in_kwh
|
unique_id: jk0_energy_in_kwh
|
||||||
unit_prefix: k
|
unit_prefix: k
|
||||||
@@ -10,7 +48,7 @@ sensor:
|
|||||||
max_sub_interval:
|
max_sub_interval:
|
||||||
minutes: 5
|
minutes: 5
|
||||||
- platform: integration
|
- platform: integration
|
||||||
source: sensor.batteries_jk0_discharging_power
|
source: sensor.jk0_discharge_power_w
|
||||||
name: "JK0 energy out"
|
name: "JK0 energy out"
|
||||||
unique_id: jk0_energy_out_kwh
|
unique_id: jk0_energy_out_kwh
|
||||||
unit_prefix: k
|
unit_prefix: k
|
||||||
@@ -21,7 +59,7 @@ sensor:
|
|||||||
|
|
||||||
# Battery 1
|
# Battery 1
|
||||||
- platform: integration
|
- platform: integration
|
||||||
source: sensor.battery1_jk1_charging_power
|
source: sensor.jk1_charge_power_w
|
||||||
name: "JK1 energy in"
|
name: "JK1 energy in"
|
||||||
unique_id: jk1_energy_in_kwh
|
unique_id: jk1_energy_in_kwh
|
||||||
unit_prefix: k
|
unit_prefix: k
|
||||||
@@ -30,7 +68,7 @@ sensor:
|
|||||||
max_sub_interval:
|
max_sub_interval:
|
||||||
minutes: 5
|
minutes: 5
|
||||||
- platform: integration
|
- platform: integration
|
||||||
source: sensor.battery1_jk1_discharging_power
|
source: sensor.jk1_discharge_power_w
|
||||||
name: "JK1 energy out"
|
name: "JK1 energy out"
|
||||||
unique_id: jk1_energy_out_kwh
|
unique_id: jk1_energy_out_kwh
|
||||||
unit_prefix: k
|
unit_prefix: k
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ in
|
|||||||
./services
|
./services
|
||||||
./hardware.nix
|
./hardware.nix
|
||||||
./networking.nix
|
./networking.nix
|
||||||
|
./nvidia.nix
|
||||||
./programs.nix
|
./programs.nix
|
||||||
./runners
|
./runners
|
||||||
./syncthing.nix
|
./syncthing.nix
|
||||||
|
|||||||
60
systems/jeeves/docker/great_cloud_of_witnesses.nix
Normal file
60
systems/jeeves/docker/great_cloud_of_witnesses.nix
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
vars = import ../vars.nix;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
|
||||||
|
# environment.systemPackages = with pkgs; [ php.withExtensions ({ all, ... }: [ all.pdo_pgsql ]) ];
|
||||||
|
|
||||||
|
services.httpd = {
|
||||||
|
enable = true;
|
||||||
|
adminAddr = "webmaster@localhost";
|
||||||
|
|
||||||
|
enablePHP = true;
|
||||||
|
phpPackage = pkgs.php.withExtensions (
|
||||||
|
{ enabled, all }:
|
||||||
|
enabled
|
||||||
|
++ [
|
||||||
|
all.pdo
|
||||||
|
all.pdo_pgsql
|
||||||
|
]
|
||||||
|
);
|
||||||
|
extraModules = [ "rewrite" ];
|
||||||
|
virtualHosts.great_cloud_of_witnesses = {
|
||||||
|
hostName = "localhost";
|
||||||
|
listen = [
|
||||||
|
{
|
||||||
|
ip = "*";
|
||||||
|
port = 8092;
|
||||||
|
}
|
||||||
|
|
||||||
|
];
|
||||||
|
documentRoot = "${vars.services}/great_cloud_of_witnesses";
|
||||||
|
extraConfig = ''
|
||||||
|
<Directory "${vars.services}/great_cloud_of_witnesses">
|
||||||
|
AllowOverride All
|
||||||
|
Require all granted
|
||||||
|
</Directory>
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sops.secrets.gcw_password = {
|
||||||
|
sopsFile = ../../../users/secrets.yaml;
|
||||||
|
neededForUsers = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
users = {
|
||||||
|
users.gcw = {
|
||||||
|
isSystemUser = true;
|
||||||
|
hashedPasswordFile = config.sops.secrets.gcw_password.path;
|
||||||
|
group = "gcw";
|
||||||
|
};
|
||||||
|
groups.gcw = { };
|
||||||
|
};
|
||||||
|
}
|
||||||
47
systems/jeeves/docker/qbitvpn.nix
Normal file
47
systems/jeeves/docker/qbitvpn.nix
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
let
|
||||||
|
vars = import ../vars.nix;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
networking.firewall = {
|
||||||
|
allowedTCPPorts = [
|
||||||
|
6882
|
||||||
|
8081
|
||||||
|
8118
|
||||||
|
];
|
||||||
|
allowedUDPPorts = [ 6882 ];
|
||||||
|
};
|
||||||
|
virtualisation.oci-containers.containers.qbitvpn = {
|
||||||
|
image = "binhex/arch-qbittorrentvpn:5.0.3-1-01";
|
||||||
|
devices = [ "/dev/net/tun:/dev/net/tun" ];
|
||||||
|
extraOptions = [ "--cap-add=NET_ADMIN" ];
|
||||||
|
ports = [
|
||||||
|
"6882:6881"
|
||||||
|
"6882:6881/udp"
|
||||||
|
"8081:8081"
|
||||||
|
"8118:8118"
|
||||||
|
];
|
||||||
|
volumes = [
|
||||||
|
"${vars.docker_configs}/qbitvpn:/config"
|
||||||
|
"${vars.qbitvpn}:/data"
|
||||||
|
"${vars.qbitvpn_scratch}:/data/incomplete"
|
||||||
|
"/etc/localtime:/etc/localtime:ro"
|
||||||
|
];
|
||||||
|
environment = {
|
||||||
|
WEBUI_PORT = "8081";
|
||||||
|
PUID = "600";
|
||||||
|
PGID = "100";
|
||||||
|
VPN_ENABLED = "yes";
|
||||||
|
VPN_CLIENT = "openvpn";
|
||||||
|
STRICT_PORT_FORWARD = "yes";
|
||||||
|
ENABLE_PRIVOXY = "yes";
|
||||||
|
LAN_NETWORK = "192.168.90.0/24";
|
||||||
|
NAME_SERVERS = "1.1.1.1,1.0.0.1";
|
||||||
|
UMASK = "000";
|
||||||
|
DEBUG = "false";
|
||||||
|
DELUGE_DAEMON_LOG_LEVEL = "debug";
|
||||||
|
DELUGE_WEB_LOG_LEVEL = "debug";
|
||||||
|
};
|
||||||
|
environmentFiles = [ "${vars.secrets}/docker/qbitvpn" ];
|
||||||
|
autoStart = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -61,7 +61,31 @@ in
|
|||||||
"luks-root-pool-wwn-0x55cd2e4150f01556-part2" =
|
"luks-root-pool-wwn-0x55cd2e4150f01556-part2" =
|
||||||
makeLuksSSD "/dev/disk/by-id/wwn-0x55cd2e4150f01556-part2";
|
makeLuksSSD "/dev/disk/by-id/wwn-0x55cd2e4150f01556-part2";
|
||||||
|
|
||||||
|
# Media pool
|
||||||
|
"luks-media_pool-nvme-INTEL_SSDPEK1A118GA_BTOC14120V2J118B-part1" =
|
||||||
|
makeLuksSSD "/dev/disk/by-id/nvme-INTEL_SSDPEK1A118GA_BTOC14120V2J118B-part1";
|
||||||
|
"luks-media_pool-nvme-INTEL_SSDPEK1A118GA_BTOC14120WAG118B-part1" =
|
||||||
|
makeLuksSSD "/dev/disk/by-id/nvme-INTEL_SSDPEK1A118GA_BTOC14120WAG118B-part1";
|
||||||
|
"luks-media_pool-nvme-INTEL_SSDPE2ME012T4_CVMD5130000G1P2HGN-part1" =
|
||||||
|
makeLuksSSD "/dev/disk/by-id/nvme-INTEL_SSDPE2ME012T4_CVMD5130000G1P2HGN-part1";
|
||||||
|
"luks-media_pool-nvme-INTEL_SSDPE2ME012T4_CVMD5130000U1P2HGN-part1" =
|
||||||
|
makeLuksSSD "/dev/disk/by-id/nvme-INTEL_SSDPE2ME012T4_CVMD5130000U1P2HGN-part1";
|
||||||
|
|
||||||
|
# Scratch pool
|
||||||
|
"luks-scratch-pool-ata-CT480BX500SSD1_2314E6C3C01C-part1" =
|
||||||
|
makeLuksSSD "/dev/disk/by-id/ata-CT480BX500SSD1_2314E6C3C01C-part1";
|
||||||
|
"luks-scratch-pool-ata-CT480BX500SSD1_2314E6C3C01E-part1" =
|
||||||
|
makeLuksSSD "/dev/disk/by-id/ata-CT480BX500SSD1_2314E6C3C01E-part1";
|
||||||
|
|
||||||
# Storage pool
|
# Storage pool
|
||||||
|
"luks-storage_pool-nvme-Samsung_SSD_970_EVO_Plus_2TB_S6S2NS0T834822N-part1" =
|
||||||
|
makeLuksSSD "/dev/disk/by-id/nvme-Samsung_SSD_970_EVO_Plus_2TB_S6S2NS0T834822N-part1";
|
||||||
|
"luks-storage_pool-nvme-Samsung_SSD_970_EVO_Plus_2TB_S6S2NS0T834817F-part1" =
|
||||||
|
makeLuksSSD "/dev/disk/by-id/nvme-Samsung_SSD_970_EVO_Plus_2TB_S6S2NS0T834817F-part1";
|
||||||
|
"luks-storage_pool-nvme-INTEL_MEMPEK1W016GA_PHBT828104DF016D-part1" =
|
||||||
|
makeLuksSSD "/dev/disk/by-id/nvme-INTEL_MEMPEK1W016GA_PHBT828104DF016D-part1";
|
||||||
|
"luks-storage_pool-nvme-INTEL_MEMPEK1W016GA_PHBT828105A8016D-part1" =
|
||||||
|
makeLuksSSD "/dev/disk/by-id/nvme-INTEL_MEMPEK1W016GA_PHBT828105A8016D-part1";
|
||||||
"luks-storage_pool-wwn-0x5000cca23bc438dd-part1" =
|
"luks-storage_pool-wwn-0x5000cca23bc438dd-part1" =
|
||||||
makeLuksDevice "/dev/disk/by-id/wwn-0x5000cca23bc438dd-part1";
|
makeLuksDevice "/dev/disk/by-id/wwn-0x5000cca23bc438dd-part1";
|
||||||
"luks-storage_pool-wwn-0x5000cca23bd035f5-part1" =
|
"luks-storage_pool-wwn-0x5000cca23bd035f5-part1" =
|
||||||
|
|||||||
@@ -2,71 +2,31 @@
|
|||||||
networking = {
|
networking = {
|
||||||
hostName = "jeeves";
|
hostName = "jeeves";
|
||||||
hostId = "0e15ce35";
|
hostId = "0e15ce35";
|
||||||
firewall = {
|
firewall.enable = true;
|
||||||
enable = true;
|
|
||||||
interfaces.br-nix-builder = {
|
|
||||||
allowedTCPPorts = [ ];
|
|
||||||
allowedUDPPorts = [ ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
useNetworkd = true;
|
useNetworkd = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.network = {
|
systemd.network = {
|
||||||
enable = true;
|
enable = true;
|
||||||
wait-online = {
|
|
||||||
enable = false;
|
|
||||||
anyInterface = true;
|
|
||||||
};
|
|
||||||
netdevs = {
|
|
||||||
"20-br-nix-builder" = {
|
|
||||||
netdevConfig = {
|
|
||||||
Kind = "bridge";
|
|
||||||
Name = "br-nix-builder";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
"30-internet-vlan" = {
|
|
||||||
netdevConfig = {
|
|
||||||
Kind = "vlan";
|
|
||||||
Name = "internet-vlan";
|
|
||||||
};
|
|
||||||
vlanConfig.Id = 100;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
networks = {
|
networks = {
|
||||||
"10-1GB_Primary" = {
|
"10-1GB_Primary" = {
|
||||||
matchConfig.Name = "enp97s0f1";
|
matchConfig.Name = "enp98s0f0";
|
||||||
address = [ "192.168.99.14/24" ];
|
address = [ "192.168.99.14/24" ];
|
||||||
routes = [ { Gateway = "192.168.99.1"; } ];
|
routes = [ { Gateway = "192.168.99.1"; } ];
|
||||||
vlan = [ "internet-vlan" ];
|
|
||||||
linkConfig.RequiredForOnline = "routable";
|
linkConfig.RequiredForOnline = "routable";
|
||||||
};
|
};
|
||||||
"50-internet-vlan" = {
|
"10-1GB_Secondary" = {
|
||||||
matchConfig.Name = "internet-vlan";
|
matchConfig.Name = "enp98s0f1";
|
||||||
bridge = [ "br-nix-builder" ];
|
DHCP = "yes";
|
||||||
linkConfig.RequiredForOnline = "no";
|
|
||||||
};
|
};
|
||||||
"60-br-nix-builder" = {
|
"10-10GB_Primary" = {
|
||||||
matchConfig.Name = "br-nix-builder";
|
matchConfig.Name = "enp97s0f0np0";
|
||||||
bridgeConfig = { };
|
DHCP = "yes";
|
||||||
address = [ "192.168.3.10/24" ];
|
linkConfig.RequiredForOnline = "routable";
|
||||||
routingPolicyRules = [
|
};
|
||||||
{
|
"10-10GB_Secondary" = {
|
||||||
From = "192.168.3.0/24";
|
matchConfig.Name = "enp97s0f1np1";
|
||||||
Table = 100;
|
DHCP = "yes";
|
||||||
Priority = 100;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
routes = [
|
|
||||||
{
|
|
||||||
Gateway = "192.168.3.1";
|
|
||||||
Table = 100;
|
|
||||||
GatewayOnLink = false;
|
|
||||||
Metric = 2048;
|
|
||||||
PreferredSource = "192.168.3.10";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
linkConfig.RequiredForOnline = "no";
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
16
systems/jeeves/nvidia.nix
Normal file
16
systems/jeeves/nvidia.nix
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{ config, ... }:
|
||||||
|
{
|
||||||
|
nixpkgs.config.cudaSupport = true;
|
||||||
|
|
||||||
|
services.xserver.videoDrivers = [ "nvidia" ];
|
||||||
|
hardware = {
|
||||||
|
nvidia = {
|
||||||
|
modesetting.enable = true;
|
||||||
|
powerManagement.enable = true;
|
||||||
|
package = config.boot.kernelPackages.nvidiaPackages.beta;
|
||||||
|
nvidiaSettings = true;
|
||||||
|
open = false;
|
||||||
|
};
|
||||||
|
nvidia-container-toolkit.enable = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -16,20 +16,11 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
services.nix_builder.containers = {
|
services.nix_builder.containers = {
|
||||||
nix-builder-00.enable = true;
|
nix-builder-0.enable = true;
|
||||||
nix-builder-01.enable = true;
|
nix-builder-1.enable = true;
|
||||||
nix-builder-02.enable = true;
|
nix-builder-2.enable = true;
|
||||||
nix-builder-03.enable = true;
|
nix-builder-3.enable = true;
|
||||||
nix-builder-04.enable = true;
|
nix-builder-4.enable = true;
|
||||||
nix-builder-05.enable = true;
|
nix-builder-5.enable = true;
|
||||||
nix-builder-06.enable = true;
|
|
||||||
nix-builder-07.enable = true;
|
|
||||||
nix-builder-08.enable = true;
|
|
||||||
nix-builder-09.enable = true;
|
|
||||||
nix-builder-10.enable = true;
|
|
||||||
nix-builder-11.enable = true;
|
|
||||||
nix-builder-12.enable = true;
|
|
||||||
nix-builder-13.enable = true;
|
|
||||||
nix-builder-14.enable = true;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,130 +6,106 @@
|
|||||||
}:
|
}:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
vars = import ../vars.nix;
|
vars = import ../vars.nix;
|
||||||
cfg = config.services.nix_builder;
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.services.nix_builder = {
|
options.services.nix_builder.containers = mkOption {
|
||||||
bridgeName = mkOption {
|
type = types.attrsOf (
|
||||||
type = types.str;
|
types.submodule (
|
||||||
default = "br-nix-builder";
|
{ name, ... }:
|
||||||
description = "Bridge name for the builder containers.";
|
{
|
||||||
};
|
options.enable = mkEnableOption "GitHub runner container";
|
||||||
|
}
|
||||||
containers = mkOption {
|
)
|
||||||
type = types.attrsOf (
|
);
|
||||||
types.submodule (
|
default = { };
|
||||||
{ name, ... }:
|
description = "GitHub runner container configurations";
|
||||||
{
|
|
||||||
options.enable = mkEnableOption "GitHub runner container";
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
default = { };
|
|
||||||
description = "GitHub runner container configurations";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
config = {
|
config.containers = mapAttrs (
|
||||||
containers = mapAttrs (
|
name: cfg:
|
||||||
name: containerCfg:
|
mkIf cfg.enable {
|
||||||
mkIf containerCfg.enable {
|
autoStart = true;
|
||||||
autoStart = true;
|
bindMounts = {
|
||||||
privateNetwork = true;
|
"/storage" = {
|
||||||
hostBridge = cfg.bridgeName;
|
mountPoint = "/zfs/media/github-runners/${name}";
|
||||||
ephemeral = true;
|
isReadOnly = false;
|
||||||
bindMounts = {
|
|
||||||
storage = {
|
|
||||||
hostPath = "/zfs/media/github-runners/${name}";
|
|
||||||
mountPoint = "/zfs/media/github-runners/${name}";
|
|
||||||
isReadOnly = false;
|
|
||||||
};
|
|
||||||
host-nix = {
|
|
||||||
mountPoint = "/host-nix/var/nix/daemon-socket";
|
|
||||||
hostPath = "/nix/var/nix/daemon-socket";
|
|
||||||
isReadOnly = false;
|
|
||||||
};
|
|
||||||
pat = {
|
|
||||||
hostPath = "${vars.secrets}/services/github-runners/runner_pat";
|
|
||||||
mountPoint = "${vars.secrets}/services/github-runners/runner_pat";
|
|
||||||
isReadOnly = true;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
config =
|
"/secrets".mountPoint = "${vars.secrets}/services/github-runners/${name}";
|
||||||
{
|
"ssh-keys".mountPoint = "${vars.secrets}/services/github-runners/id_ed25519_github-runners";
|
||||||
config,
|
};
|
||||||
pkgs,
|
config =
|
||||||
lib,
|
{
|
||||||
...
|
config,
|
||||||
}:
|
pkgs,
|
||||||
{
|
lib,
|
||||||
networking = {
|
...
|
||||||
useDHCP = lib.mkDefault true;
|
}:
|
||||||
interfaces.eth0.useDHCP = true;
|
{
|
||||||
# Ensure containers don't inherit the host's stub resolver (127.0.0.53) which was causing issues
|
nix.settings = {
|
||||||
useHostResolvConf = false;
|
trusted-substituters = [
|
||||||
};
|
"https://cache.nixos.org"
|
||||||
nix.settings = {
|
"https://cache.tmmworkshop.com"
|
||||||
trusted-substituters = [
|
"https://nix-community.cachix.org"
|
||||||
"https://cache.nixos.org"
|
];
|
||||||
"https://cache.tmmworkshop.com"
|
substituters = [
|
||||||
"https://nix-community.cachix.org"
|
"https://cache.nixos.org/?priority=2&want-mass-query=true"
|
||||||
];
|
"https://cache.tmmworkshop.com/?priority=2&want-mass-query=true"
|
||||||
substituters = [
|
"https://nix-community.cachix.org/?priority=10&want-mass-query=true"
|
||||||
"https://cache.nixos.org/?priority=2&want-mass-query=true"
|
];
|
||||||
"https://cache.tmmworkshop.com/?priority=2&want-mass-query=true"
|
trusted-public-keys = [
|
||||||
"https://nix-community.cachix.org/?priority=10&want-mass-query=true"
|
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
|
||||||
];
|
"cache.tmmworkshop.com:jHffkpgbmEdstQPoihJPYW9TQe6jnQbWR2LqkNGV3iA="
|
||||||
trusted-public-keys = [
|
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
|
||||||
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
|
];
|
||||||
"cache.tmmworkshop.com:jHffkpgbmEdstQPoihJPYW9TQe6jnQbWR2LqkNGV3iA="
|
experimental-features = [
|
||||||
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
|
"flakes"
|
||||||
];
|
"nix-command"
|
||||||
experimental-features = [
|
];
|
||||||
"flakes"
|
|
||||||
"nix-command"
|
|
||||||
];
|
|
||||||
sandbox = true;
|
|
||||||
allowed-users = [ "github-runners" ];
|
|
||||||
trusted-users = [
|
|
||||||
"root"
|
|
||||||
"github-runners"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
nixpkgs = {
|
|
||||||
overlays = builtins.attrValues outputs.overlays;
|
|
||||||
config.allowUnfree = true;
|
|
||||||
};
|
|
||||||
services.github-runners.${name} = {
|
|
||||||
enable = true;
|
|
||||||
replace = true;
|
|
||||||
workDir = "/zfs/media/github-runners/${name}";
|
|
||||||
url = "https://github.com/RichieCahill/dotfiles";
|
|
||||||
extraLabels = [ "nixos" ];
|
|
||||||
tokenFile = "${vars.secrets}/services/github-runners/runner_pat";
|
|
||||||
user = "github-runners";
|
|
||||||
group = "github-runners";
|
|
||||||
extraPackages = with pkgs; [
|
|
||||||
nixfmt-rfc-style
|
|
||||||
nixos-rebuild
|
|
||||||
treefmt
|
|
||||||
my_python
|
|
||||||
];
|
|
||||||
};
|
|
||||||
users = {
|
|
||||||
users.github-runners = {
|
|
||||||
shell = pkgs.bash;
|
|
||||||
isSystemUser = true;
|
|
||||||
group = "github-runners";
|
|
||||||
uid = 601;
|
|
||||||
};
|
|
||||||
groups.github-runners.gid = 601;
|
|
||||||
};
|
|
||||||
system.stateVersion = "24.05";
|
|
||||||
};
|
};
|
||||||
}
|
programs.ssh.extraConfig = ''
|
||||||
) cfg.containers;
|
Host jeeves
|
||||||
};
|
Port 629
|
||||||
|
User github-runners
|
||||||
|
HostName jeeves
|
||||||
|
IdentityFile ${vars.secrets}/services/github-runners/id_ed25519_github-runners
|
||||||
|
StrictHostKeyChecking no
|
||||||
|
UserKnownHostsFile /dev/null
|
||||||
|
'';
|
||||||
|
nixpkgs = {
|
||||||
|
overlays = builtins.attrValues outputs.overlays;
|
||||||
|
config.allowUnfree = true;
|
||||||
|
};
|
||||||
|
services.github-runners.${name} = {
|
||||||
|
enable = true;
|
||||||
|
replace = true;
|
||||||
|
workDir = "/zfs/media/github-runners/${name}";
|
||||||
|
url = "https://github.com/RichieCahill/dotfiles";
|
||||||
|
extraLabels = [ "nixos" ];
|
||||||
|
tokenFile = "${vars.secrets}/services/github-runners/${name}";
|
||||||
|
user = "github-runners";
|
||||||
|
group = "github-runners";
|
||||||
|
extraPackages = with pkgs; [
|
||||||
|
nixfmt-rfc-style
|
||||||
|
nixos-rebuild
|
||||||
|
openssh
|
||||||
|
treefmt
|
||||||
|
my_python
|
||||||
|
];
|
||||||
|
};
|
||||||
|
users = {
|
||||||
|
users.github-runners = {
|
||||||
|
shell = pkgs.bash;
|
||||||
|
isSystemUser = true;
|
||||||
|
group = "github-runners";
|
||||||
|
uid = 601;
|
||||||
|
};
|
||||||
|
groups.github-runners.gid = 601;
|
||||||
|
};
|
||||||
|
system.stateVersion = "24.11";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
) config.services.nix_builder.containers;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,30 +12,31 @@ sudo zpool add storage -o ashift=12 special mirror
|
|||||||
sudo zpool add storage -o ashift=12 logs mirror
|
sudo zpool add storage -o ashift=12 logs mirror
|
||||||
|
|
||||||
# scratch
|
# scratch
|
||||||
sudo zpool create scratch -o ashift=12 -O acltype=posixacl -O atime=off -O dnodesize=auto -O xattr=sa -O compression=zstd -O encryption=aes-256-gcm -O keyformat=hex -O keylocation=file:///key -m /zfs/scratch
|
sudo zpool create -o ashift=12 -O acltype=posixacl -O atime=off -O dnodesize=auto -O xattr=sa -O compression=zstd -m /zfs/scratch scratch
|
||||||
|
|
||||||
# media datasets
|
# media datasets
|
||||||
sudo zfs create media/secure -o encryption=aes-256-gcm -o keyformat=hex -o keylocation=file:///root/zfs.key
|
sudo zfs create -o compression=zstd-9 media/docker
|
||||||
sudo zfs create media/secure/docker -o compression=zstd-9
|
sudo zfs create -o compression=zstd-9 -o sync=disabled media/github-runners
|
||||||
sudo zfs create media/secure/github-runners -o compression=zstd-9 -o sync=disabled
|
sudo zfs create -o copies=3 media/notes
|
||||||
sudo zfs create media/secure/home_assistant -o compression=zstd-19
|
sudo zfs create -o compression=zstd-9 media/plex
|
||||||
sudo zfs create media/secure/notes -o copies=2
|
sudo zfs create -o compression=zstd-9 media/services
|
||||||
sudo zfs create media/secure/postgres -o recordsize=16k -o primarycache=metadata
|
sudo zfs create -o compression=zstd-19 media/home_assistant
|
||||||
sudo zfs create media/secure/services -o compression=zstd-9
|
sudo zfs create -o exec=off media/share
|
||||||
sudo zfs create media/secure/share -o mountpoint=/zfs/media/share -o exec=off
|
sudo zfs create -o recordsize=16k -o primarycache=metadata -o mountpoint=/zfs/media/database/postgres media/postgres
|
||||||
|
|
||||||
# scratch datasets
|
# scratch datasets
|
||||||
sudo zfs create scratch/kafka -o mountpoint=/zfs/scratch/kafka -o recordsize=1M
|
sudo zfs create -o recordsize=16k -o sync=disabled scratch/qbitvpn
|
||||||
sudo zfs create scratch/transmission -o mountpoint=/zfs/scratch/transmission -o recordsize=16k -o sync=disabled
|
sudo zfs create -o recordsize=16k -o sync=disabled scratch/transmission
|
||||||
|
sudo zfs create -o recordsize=1M scratch/kafka
|
||||||
|
|
||||||
# storage datasets
|
# storage datasets
|
||||||
sudo zfs create storage/ollama -o recordsize=1M -o compression=zstd-19 -o sync=disabled
|
sudo zfs create -o recordsize=1M -o compression=zstd-19 storage/archive
|
||||||
sudo zfs create storage/secure -o encryption=aes-256-gcm -o keyformat=hex -o keylocation=file:///root/zfs.key
|
sudo zfs create -o compression=zstd-19 storage/main
|
||||||
sudo zfs create storage/secure/archive -o recordsize=1M -o compression=zstd-19
|
sudo zfs create -o recordsize=16K -o compression=zstd-19 -o copies=2 storage/photos
|
||||||
sudo zfs create storage/secure/library -o recordsize=1M -o compression=zstd-19
|
sudo zfs create -o recordsize=1M -o compression=zstd-19 storage/plex
|
||||||
sudo zfs create storage/secure/main -o compression=zstd-19
|
sudo zfs create -o compression=zstd-19 -o copies=3 storage/secrets
|
||||||
sudo zfs create storage/secure/photos -o recordsize=16K -o compression=zstd-19 -o copies=2
|
sudo zfs create -o compression=zstd-19 storage/syncthing
|
||||||
sudo zfs create storage/secure/plex -o recordsize=1M -o compression=zstd-19
|
sudo zfs create -o recordsize=1M -o compression=zstd-9 -o exec=off -o sync=disabled storage/qbitvpn
|
||||||
sudo zfs create storage/secure/secrets -o compression=zstd-19 -o copies=3
|
sudo zfs create -o recordsize=1M -o compression=zstd-9 -o exec=off -o sync=disabled storage/transmission
|
||||||
sudo zfs create storage/secure/syncthing -o compression=zstd-19
|
sudo zfs create -o recordsize=1M -o compression=zstd-19 storage/library
|
||||||
sudo zfs create storage/secure/transmission -o recordsize=1M -o compression=zstd-9 -o exec=off -o sync=disabled
|
sudo zfs create -o recordsize=1M -o compression=zstd-19 -o sync=disabled storage/ollama
|
||||||
|
|||||||
21
systems/jeeves/services/filebrowser.nix
Normal file
21
systems/jeeves/services/filebrowser.nix
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
vars = import ../vars.nix;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
systemd.services.filebrowser = {
|
||||||
|
description = "filebrowser";
|
||||||
|
after = [ "network.target" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
User = "richie";
|
||||||
|
Group = "users";
|
||||||
|
ExecStart = "${pkgs.filebrowser}/bin/filebrowser --root=/zfs --address=0.0.0.0 --database=${vars.docker_configs}/filebrowser/filebrowser.db";
|
||||||
|
Restart = "on-failure";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
let
|
|
||||||
vars = import ../vars.nix;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
networking.firewall.allowedTCPPorts = [ 6443 ];
|
|
||||||
|
|
||||||
services.gitea = {
|
|
||||||
enable = true;
|
|
||||||
appName = "TMM Workshop";
|
|
||||||
stateDir = "${vars.services}/gitea/";
|
|
||||||
lfs.enable = true;
|
|
||||||
database = {
|
|
||||||
type = "postgres";
|
|
||||||
name = "gitea";
|
|
||||||
user = "gitea";
|
|
||||||
socket = "/run/postgresql";
|
|
||||||
port = 5432;
|
|
||||||
createDatabase = false;
|
|
||||||
};
|
|
||||||
settings = {
|
|
||||||
service.DISABLE_REGISTRATION = true;
|
|
||||||
server = {
|
|
||||||
DOMAIN = "tmmworkshop.com";
|
|
||||||
ROOT_URL = "https://gitea.tmmworkshop.com/";
|
|
||||||
HTTP_PORT = 6443;
|
|
||||||
SSH_PORT = 2223;
|
|
||||||
SSH_LISTEN_PORT = 2224;
|
|
||||||
START_SSH_SERVER = true;
|
|
||||||
PUBLIC_URL_DETECTION = "auto";
|
|
||||||
};
|
|
||||||
repository = {
|
|
||||||
ENABLE_PUSH_CREATE_USER = true;
|
|
||||||
DEFAULT_MERGE_STYLE = "rebase-merge";
|
|
||||||
};
|
|
||||||
log = {
|
|
||||||
LEVEL = "Trace";
|
|
||||||
ENABLE_SSH_LOG = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.gitea = {
|
|
||||||
requires = [ "docker.service" ];
|
|
||||||
after = [ "docker.service" ];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -27,21 +27,21 @@ frontend ContentSwitching
|
|||||||
# tmmworkshop.com
|
# tmmworkshop.com
|
||||||
acl host_audiobookshelf hdr(host) -i audiobookshelf.tmmworkshop.com
|
acl host_audiobookshelf hdr(host) -i audiobookshelf.tmmworkshop.com
|
||||||
acl host_cache hdr(host) -i cache.tmmworkshop.com
|
acl host_cache hdr(host) -i cache.tmmworkshop.com
|
||||||
|
acl host_filebrowser hdr(host) -i filebrowser.tmmworkshop.com
|
||||||
acl host_homeassistant hdr(host) -i homeassistant.tmmworkshop.com
|
acl host_homeassistant hdr(host) -i homeassistant.tmmworkshop.com
|
||||||
acl host_jellyfin hdr(host) -i jellyfin.tmmworkshop.com
|
acl host_jellyfin hdr(host) -i jellyfin.tmmworkshop.com
|
||||||
acl host_share hdr(host) -i share.tmmworkshop.com
|
acl host_share hdr(host) -i share.tmmworkshop.com
|
||||||
acl host_gcw hdr(host) -i gcw.tmmworkshop.com
|
acl host_gcw hdr(host) -i gcw.tmmworkshop.com
|
||||||
acl host_n8n hdr(host) -i n8n.tmmworkshop.com
|
acl host_n8n hdr(host) -i n8n.tmmworkshop.com
|
||||||
acl host_gitea hdr(host) -i gitea.tmmworkshop.com
|
|
||||||
|
|
||||||
use_backend audiobookshelf_nodes if host_audiobookshelf
|
use_backend audiobookshelf_nodes if host_audiobookshelf
|
||||||
use_backend cache_nodes if host_cache
|
use_backend cache_nodes if host_cache
|
||||||
|
use_backend filebrowser_nodes if host_filebrowser
|
||||||
use_backend homeassistant_nodes if host_homeassistant
|
use_backend homeassistant_nodes if host_homeassistant
|
||||||
use_backend jellyfin if host_jellyfin
|
use_backend jellyfin if host_jellyfin
|
||||||
use_backend share_nodes if host_share
|
use_backend share_nodes if host_share
|
||||||
use_backend gcw_nodes if host_gcw
|
use_backend gcw_nodes if host_gcw
|
||||||
use_backend n8n if host_n8n
|
use_backend n8n if host_n8n
|
||||||
use_backend gitea if host_gitea
|
|
||||||
|
|
||||||
backend audiobookshelf_nodes
|
backend audiobookshelf_nodes
|
||||||
mode http
|
mode http
|
||||||
@@ -51,6 +51,10 @@ backend cache_nodes
|
|||||||
mode http
|
mode http
|
||||||
server server 127.0.0.1:5000
|
server server 127.0.0.1:5000
|
||||||
|
|
||||||
|
backend filebrowser_nodes
|
||||||
|
mode http
|
||||||
|
server server 127.0.0.1:8080
|
||||||
|
|
||||||
backend homeassistant_nodes
|
backend homeassistant_nodes
|
||||||
mode http
|
mode http
|
||||||
server server 192.168.90.35:8123
|
server server 192.168.90.35:8123
|
||||||
@@ -73,7 +77,3 @@ backend gcw_nodes
|
|||||||
backend n8n
|
backend n8n
|
||||||
mode http
|
mode http
|
||||||
server server 127.0.0.1:5678
|
server server 127.0.0.1:5678
|
||||||
|
|
||||||
backend gitea
|
|
||||||
mode http
|
|
||||||
server server 127.0.0.1:6443
|
|
||||||
@@ -9,25 +9,13 @@ in
|
|||||||
host = "0.0.0.0";
|
host = "0.0.0.0";
|
||||||
loadModels = [
|
loadModels = [
|
||||||
"codellama:7b"
|
"codellama:7b"
|
||||||
"deepscaler:1.5b"
|
|
||||||
"deepseek-r1:14b"
|
"deepseek-r1:14b"
|
||||||
"deepseek-r1:32b"
|
"deepseek-r1:32b"
|
||||||
"deepseek-r1:8b"
|
"deepseek-r1:8b"
|
||||||
"devstral-small-2:24b"
|
|
||||||
"functiongemma:270m"
|
|
||||||
"gemma3:12b"
|
"gemma3:12b"
|
||||||
"gemma3:27b"
|
"gemma3:27b"
|
||||||
"gpt-oss:120b"
|
"gpt-oss:120b"
|
||||||
"gpt-oss:20b"
|
"gpt-oss:20b"
|
||||||
"llama3.1:70b"
|
|
||||||
"llama3.1:8b"
|
|
||||||
"llama3.2:1b"
|
|
||||||
"llama3.2:3b"
|
|
||||||
"magistral:24b"
|
|
||||||
"ministral-3:14b"
|
|
||||||
"nemotron-3-nano:30b"
|
|
||||||
"qwen3-coder:30b"
|
|
||||||
"qwen3-vl:32b"
|
|
||||||
"qwen3:14b"
|
"qwen3:14b"
|
||||||
"qwen3:30b"
|
"qwen3:30b"
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
let
|
|
||||||
vars = import ../vars.nix;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
services.open-webui = {
|
|
||||||
stateDir = "${vars.services}/open_webui/";
|
|
||||||
enable = true;
|
|
||||||
openFirewall = true;
|
|
||||||
environment = {
|
|
||||||
ANONYMIZED_TELEMETRY = "False";
|
|
||||||
DO_NOT_TRACK = "True";
|
|
||||||
SCARF_NO_ANALYTICS = "True";
|
|
||||||
OLLAMA_API_BASE_URL = "http://127.0.0.1:11434";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -28,7 +28,25 @@ in
|
|||||||
|
|
||||||
#type database DBuser origin-address auth-method
|
#type database DBuser origin-address auth-method
|
||||||
local hass hass trust
|
local hass hass trust
|
||||||
local gitea gitea trust
|
|
||||||
|
# ipv4
|
||||||
|
host hass hass 192.168.90.1/24 trust
|
||||||
|
host hass hass 127.0.0.1/32 trust
|
||||||
|
|
||||||
|
# ipv6
|
||||||
|
host hass hass ::1/128 trust
|
||||||
|
|
||||||
|
# megan
|
||||||
|
host megan megan 192.168.90.1/24 trust
|
||||||
|
host megan megan 127.0.0.1/32 trust
|
||||||
|
|
||||||
|
host gcw megan 192.168.90.1/24 trust
|
||||||
|
host gcw megan 127.0.0.1/32 trust
|
||||||
|
|
||||||
|
# gcw
|
||||||
|
local gcw gcw trust
|
||||||
|
host gcw gcw 192.168.90.1/24 trust
|
||||||
|
host gcw gcw 127.0.0.1/32 trust
|
||||||
|
|
||||||
# math
|
# math
|
||||||
local postgres math trust
|
local postgres math trust
|
||||||
@@ -79,7 +97,17 @@ in
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
name = "gitea";
|
name = "megan";
|
||||||
|
ensureDBOwnership = true;
|
||||||
|
ensureClauses = {
|
||||||
|
login = true;
|
||||||
|
createrole = true;
|
||||||
|
createdb = true;
|
||||||
|
replication = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "gcw";
|
||||||
ensureDBOwnership = true;
|
ensureDBOwnership = true;
|
||||||
ensureClauses = {
|
ensureClauses = {
|
||||||
login = true;
|
login = true;
|
||||||
@@ -100,9 +128,12 @@ in
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
ensureDatabases = [
|
ensureDatabases = [
|
||||||
|
"gcw"
|
||||||
"hass"
|
"hass"
|
||||||
"gitea"
|
|
||||||
"math"
|
"math"
|
||||||
|
"megan"
|
||||||
|
"mxr_dev"
|
||||||
|
"mxr_prod"
|
||||||
"n8n"
|
"n8n"
|
||||||
"richie"
|
"richie"
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ services = [
|
|||||||
"audiobookshelf",
|
"audiobookshelf",
|
||||||
"cloud_flare_tunnel",
|
"cloud_flare_tunnel",
|
||||||
"haproxy",
|
"haproxy",
|
||||||
|
"docker-qbitvpn",
|
||||||
"docker",
|
"docker",
|
||||||
|
"filebrowser",
|
||||||
"home-assistant",
|
"home-assistant",
|
||||||
"jellyfin",
|
"jellyfin",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -64,12 +64,24 @@ hourly = 12
|
|||||||
daily = 14
|
daily = 14
|
||||||
monthly = 2
|
monthly = 2
|
||||||
|
|
||||||
|
["scratch/qbitvpn"]
|
||||||
|
15_min = 0
|
||||||
|
hourly = 0
|
||||||
|
daily = 0
|
||||||
|
monthly = 0
|
||||||
|
|
||||||
["scratch/transmission"]
|
["scratch/transmission"]
|
||||||
15_min = 0
|
15_min = 0
|
||||||
hourly = 0
|
hourly = 0
|
||||||
daily = 0
|
daily = 0
|
||||||
monthly = 0
|
monthly = 0
|
||||||
|
|
||||||
|
["storage/qbitvpn"]
|
||||||
|
15_min = 0
|
||||||
|
hourly = 0
|
||||||
|
daily = 0
|
||||||
|
monthly = 0
|
||||||
|
|
||||||
["storage/transmission"]
|
["storage/transmission"]
|
||||||
15_min = 0
|
15_min = 0
|
||||||
hourly = 0
|
hourly = 0
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ in
|
|||||||
docker_configs = "${zfs_media}/docker/configs";
|
docker_configs = "${zfs_media}/docker/configs";
|
||||||
home_assistant = "${zfs_media}/home_assistant";
|
home_assistant = "${zfs_media}/home_assistant";
|
||||||
notes = "${zfs_media}/notes";
|
notes = "${zfs_media}/notes";
|
||||||
|
qbitvpn = "${zfs_storage}/qbitvpn";
|
||||||
|
qbitvpn_scratch = "${zfs_scratch}/qbitvpn";
|
||||||
secrets = "${zfs_storage}/secrets";
|
secrets = "${zfs_storage}/secrets";
|
||||||
services = "${zfs_media}/services";
|
services = "${zfs_media}/services";
|
||||||
share = "${zfs_media}/share";
|
share = "${zfs_media}/share";
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
./hardware.nix
|
./hardware.nix
|
||||||
./llms.nix
|
./llms.nix
|
||||||
./syncthing.nix
|
./syncthing.nix
|
||||||
./qmk.nix
|
|
||||||
inputs.nixos-hardware.nixosModules.framework-13-7040-amd
|
inputs.nixos-hardware.nixosModules.framework-13-7040-amd
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
{ pkgs, ... }:
|
|
||||||
{
|
|
||||||
environment.systemPackages = with pkgs; [
|
|
||||||
qmk
|
|
||||||
vial
|
|
||||||
];
|
|
||||||
|
|
||||||
services = {
|
|
||||||
udev = {
|
|
||||||
packages = [ pkgs.qmk-udev-rules ];
|
|
||||||
extraRules = ''
|
|
||||||
# Keychron keyboards
|
|
||||||
KERNEL=="hidraw*", ATTRS{idVendor}=="3434", MODE="0660", GROUP="plugdev"
|
|
||||||
SUBSYSTEM=="usb", ATTR{idVendor}=="3434", MODE="0660", GROUP="plugdev"
|
|
||||||
|
|
||||||
# Some boards use 32f0 as vendor id
|
|
||||||
KERNEL=="hidraw*", ATTRS{idVendor}=="32f0", MODE="0660", GROUP="plugdev"
|
|
||||||
SUBSYSTEM=="usb", ATTR{idVendor}=="32f0", MODE="0660", GROUP="plugdev"
|
|
||||||
|
|
||||||
# Keychron HID device permissions
|
|
||||||
SUBSYSTEM=="usb", ATTR{idVendor}=="3434", MODE="0660", GROUP="plugdev"
|
|
||||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="3434", MODE="0660", GROUP="plugdev"
|
|
||||||
KERNEL=="hidraw*", ATTRS{idVendor}=="32f0", MODE="0660", GROUP="plugdev"
|
|
||||||
SUBSYSTEM=="usb", ATTR{idVendor}=="32f0", MODE="0660", GROUP="plugdev"
|
|
||||||
|
|
||||||
|
|
||||||
# Keychron / QMK common bootloaders
|
|
||||||
SUBSYSTEM=="usb", ATTR{idVendor}=="0483", ATTR{idProduct}=="df11", MODE="0660", GROUP="plugdev"
|
|
||||||
SUBSYSTEM=="usb", ATTR{idVendor}=="03eb", MODE="0660", GROUP="plugdev"
|
|
||||||
SUBSYSTEM=="usb", ATTR{idVendor}=="16c0", MODE="0660", GROUP="plugdev"
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
96
tests/test_safe_reboot.py
Normal file
96
tests/test_safe_reboot.py
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
"""Tests for safe_reboot."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from python.tools.safe_reboot import reboot
|
||||||
|
from python.zfs.dataset import Dataset
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from pytest_mock import MockerFixture
|
||||||
|
|
||||||
|
SAFE_REBOOT = "python.tools.safe_reboot"
|
||||||
|
|
||||||
|
|
||||||
|
def create_dataset(mocker: MockerFixture, name: str, exec_state: str) -> Dataset:
|
||||||
|
"""Create a mock dataset."""
|
||||||
|
dataset = mocker.MagicMock(spec=Dataset)
|
||||||
|
dataset.name = name
|
||||||
|
dataset.exec = exec_state
|
||||||
|
return dataset
|
||||||
|
|
||||||
|
|
||||||
|
def test_reboot_reboots_when_checks_pass(mocker: MockerFixture) -> None:
|
||||||
|
"""The command should reboot when all checks pass."""
|
||||||
|
dataset = create_dataset(mocker, "root_pool/root", "on")
|
||||||
|
mocker.patch(f"{SAFE_REBOOT}.get_datasets", return_value=(dataset,))
|
||||||
|
mocker.patch(f"{SAFE_REBOOT}.drive_present", return_value=True)
|
||||||
|
mock_bash = mocker.patch(f"{SAFE_REBOOT}.bash_wrapper", return_value=("", 0))
|
||||||
|
|
||||||
|
reboot("/dev/disk/root-drive")
|
||||||
|
|
||||||
|
mock_bash.assert_called_once_with("systemctl reboot")
|
||||||
|
|
||||||
|
|
||||||
|
def test_reboot_reboots_without_drive_requirement(mocker: MockerFixture) -> None:
|
||||||
|
"""The command should reboot even when no drive is provided."""
|
||||||
|
dataset = create_dataset(mocker, "root_pool/root", "on")
|
||||||
|
mocker.patch(f"{SAFE_REBOOT}.get_datasets", return_value=(dataset,))
|
||||||
|
mock_bash = mocker.patch(f"{SAFE_REBOOT}.bash_wrapper", return_value=("", 0))
|
||||||
|
|
||||||
|
reboot(None)
|
||||||
|
|
||||||
|
mock_bash.assert_called_once_with("systemctl reboot")
|
||||||
|
|
||||||
|
|
||||||
|
def test_reboot_errors_on_non_exec_dataset(mocker: MockerFixture) -> None:
|
||||||
|
"""The command should exit when a dataset lacks exec."""
|
||||||
|
dataset = create_dataset(mocker, "root_pool/root", "off")
|
||||||
|
mocker.patch(f"{SAFE_REBOOT}.get_datasets", return_value=(dataset,))
|
||||||
|
mocker.patch(f"{SAFE_REBOOT}.drive_present", return_value=True)
|
||||||
|
mocker.patch(f"{SAFE_REBOOT}.bash_wrapper", return_value=("", 0))
|
||||||
|
|
||||||
|
with pytest.raises(SystemExit) as excinfo:
|
||||||
|
reboot("/dev/disk/root-drive")
|
||||||
|
|
||||||
|
assert excinfo.value.code == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_reboot_errors_when_driver_missing(mocker: MockerFixture) -> None:
|
||||||
|
"""The command should exit when the requested driver is absent."""
|
||||||
|
dataset = create_dataset(mocker, "root_pool/root", "on")
|
||||||
|
mocker.patch(f"{SAFE_REBOOT}.get_datasets", return_value=(dataset,))
|
||||||
|
mocker.patch(f"{SAFE_REBOOT}.drive_present", return_value=False)
|
||||||
|
mocker.patch(f"{SAFE_REBOOT}.bash_wrapper", return_value=("", 0))
|
||||||
|
|
||||||
|
with pytest.raises(SystemExit) as excinfo:
|
||||||
|
reboot("/dev/disk/root-drive")
|
||||||
|
|
||||||
|
assert excinfo.value.code == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_reboot_errors_when_no_datasets_found(mocker: MockerFixture) -> None:
|
||||||
|
"""The command should exit when no datasets match the prefix."""
|
||||||
|
mocker.patch(f"{SAFE_REBOOT}.get_datasets", return_value=())
|
||||||
|
mocker.patch(f"{SAFE_REBOOT}.drive_present", return_value=True)
|
||||||
|
mocker.patch(f"{SAFE_REBOOT}.bash_wrapper", return_value=("", 0))
|
||||||
|
|
||||||
|
with pytest.raises(SystemExit) as excinfo:
|
||||||
|
reboot("/dev/disk/root-drive")
|
||||||
|
|
||||||
|
assert excinfo.value.code == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_reboot_check_only_skips_reboot(mocker: MockerFixture) -> None:
|
||||||
|
"""The command should only validate when --check-only is provided."""
|
||||||
|
dataset = create_dataset(mocker, "root_pool/root", "on")
|
||||||
|
mocker.patch(f"{SAFE_REBOOT}.get_datasets", return_value=(dataset,))
|
||||||
|
mocker.patch(f"{SAFE_REBOOT}.drive_present", return_value=True)
|
||||||
|
mock_bash = mocker.patch(f"{SAFE_REBOOT}.bash_wrapper", return_value=("", 0))
|
||||||
|
|
||||||
|
reboot("/dev/disk/root-drive", check_only=True)
|
||||||
|
|
||||||
|
mock_bash.assert_not_called()
|
||||||
30
users/megan/default.nix
Normal file
30
users/megan/default.nix
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
sops.secrets.megan_password = {
|
||||||
|
sopsFile = ../secrets.yaml;
|
||||||
|
neededForUsers = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
users = {
|
||||||
|
users.megan = {
|
||||||
|
isNormalUser = true;
|
||||||
|
hashedPasswordFile = "${config.sops.secrets.megan_password.path}";
|
||||||
|
|
||||||
|
shell = pkgs.zsh;
|
||||||
|
group = "megan";
|
||||||
|
extraGroups = [
|
||||||
|
"audio"
|
||||||
|
"video"
|
||||||
|
"users"
|
||||||
|
];
|
||||||
|
uid = 1101;
|
||||||
|
};
|
||||||
|
|
||||||
|
groups.megan.gid = 1101;
|
||||||
|
};
|
||||||
|
home-manager.users.megan = import ./systems/${config.networking.hostName}.nix;
|
||||||
|
}
|
||||||
9
users/megan/home/cli/default.nix
Normal file
9
users/megan/home/cli/default.nix
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./direnv.nix
|
||||||
|
./git.nix
|
||||||
|
./zsh.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
programs.starship.enable = true;
|
||||||
|
}
|
||||||
8
users/megan/home/cli/direnv.nix
Normal file
8
users/megan/home/cli/direnv.nix
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
|
||||||
|
programs.direnv = {
|
||||||
|
enable = true;
|
||||||
|
enableZshIntegration = true;
|
||||||
|
nix-direnv.enable = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
14
users/megan/home/cli/git.nix
Normal file
14
users/megan/home/cli/git.nix
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
programs.git = {
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
user = {
|
||||||
|
email = "mousikos112@gmail.com";
|
||||||
|
name = "megan";
|
||||||
|
};
|
||||||
|
pull.rebase = true;
|
||||||
|
color.ui = true;
|
||||||
|
};
|
||||||
|
lfs.enable = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
31
users/megan/home/cli/zsh.nix
Normal file
31
users/megan/home/cli/zsh.nix
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
programs.zsh = {
|
||||||
|
enable = true;
|
||||||
|
syntaxHighlighting.enable = true;
|
||||||
|
history.size = 10000;
|
||||||
|
oh-my-zsh = {
|
||||||
|
enable = true;
|
||||||
|
plugins = [
|
||||||
|
"git"
|
||||||
|
"docker"
|
||||||
|
"docker-compose"
|
||||||
|
"colored-man-pages"
|
||||||
|
"rust"
|
||||||
|
"systemd"
|
||||||
|
"tmux"
|
||||||
|
"ufw"
|
||||||
|
"z"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
shellAliases = {
|
||||||
|
"lrt" = "eza --icons -lsnew";
|
||||||
|
"ls" = "eza";
|
||||||
|
"ll" = "eza --long --group";
|
||||||
|
"la" = "eza --all";
|
||||||
|
|
||||||
|
"rspace" = "'for f in *\ *; do mv \"$f\" \"\${f// /_}\"; done'";
|
||||||
|
"rebuild" = "sudo nixos-rebuild switch --flake /home/richie/dotfiles#$HOST";
|
||||||
|
"nix-test" = "nixos-rebuild test --flake /home/richie/dotfiles";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
18
users/megan/home/global.nix
Normal file
18
users/megan/home/global.nix
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{ config, ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./cli
|
||||||
|
./programs.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
programs = {
|
||||||
|
home-manager.enable = true;
|
||||||
|
git.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
home = {
|
||||||
|
username = "megan";
|
||||||
|
homeDirectory = "/home/${config.home.username}";
|
||||||
|
stateVersion = "24.05";
|
||||||
|
};
|
||||||
|
}
|
||||||
41
users/megan/home/programs.nix
Normal file
41
users/megan/home/programs.nix
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
# cli
|
||||||
|
bat
|
||||||
|
btop
|
||||||
|
eza
|
||||||
|
fd
|
||||||
|
ffmpegthumbnailer
|
||||||
|
fzf
|
||||||
|
git
|
||||||
|
gnupg
|
||||||
|
imagemagick
|
||||||
|
jq
|
||||||
|
ncdu
|
||||||
|
neofetch
|
||||||
|
ouch
|
||||||
|
p7zip
|
||||||
|
poppler
|
||||||
|
rar
|
||||||
|
ripgrep
|
||||||
|
starship
|
||||||
|
tmux
|
||||||
|
unzip
|
||||||
|
yazi
|
||||||
|
zoxide
|
||||||
|
# system info
|
||||||
|
hwloc
|
||||||
|
lynis
|
||||||
|
pciutils
|
||||||
|
smartmontools
|
||||||
|
usbutils
|
||||||
|
# networking
|
||||||
|
iperf3
|
||||||
|
nmap
|
||||||
|
wget
|
||||||
|
# python
|
||||||
|
poetry
|
||||||
|
ruff
|
||||||
|
];
|
||||||
|
}
|
||||||
5
users/megan/systems/jeeves.nix
Normal file
5
users/megan/systems/jeeves.nix
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
imports = [
|
||||||
|
../home/global.nix
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -41,7 +41,6 @@ in
|
|||||||
"scanner"
|
"scanner"
|
||||||
"transmission"
|
"transmission"
|
||||||
"uaccess"
|
"uaccess"
|
||||||
"uucp"
|
|
||||||
"wireshark"
|
"wireshark"
|
||||||
];
|
];
|
||||||
uid = 1000;
|
uid = 1000;
|
||||||
|
|||||||
@@ -9,25 +9,23 @@
|
|||||||
home.packages = with pkgs; [
|
home.packages = with pkgs; [
|
||||||
candy-icons
|
candy-icons
|
||||||
chromium
|
chromium
|
||||||
|
discord-canary
|
||||||
gimp
|
gimp
|
||||||
|
gparted
|
||||||
|
jetbrains.datagrip
|
||||||
mediainfo
|
mediainfo
|
||||||
|
nemo
|
||||||
|
nemo-fileroller
|
||||||
obs-studio
|
obs-studio
|
||||||
obsidian
|
obsidian
|
||||||
prismlauncher
|
prismlauncher
|
||||||
|
proxychains
|
||||||
prusa-slicer
|
prusa-slicer
|
||||||
|
signal-desktop
|
||||||
sweet-nova
|
sweet-nova
|
||||||
util-linux
|
util-linux
|
||||||
vlc
|
vlc
|
||||||
# comms
|
|
||||||
discord-canary
|
|
||||||
signal-desktop
|
|
||||||
zoom-us
|
zoom-us
|
||||||
# dev tools
|
|
||||||
claude-code
|
|
||||||
gparted
|
|
||||||
jetbrains.datagrip
|
|
||||||
master.antigravity-fhs
|
|
||||||
proxychains
|
|
||||||
# games
|
# games
|
||||||
dwarf-fortress
|
dwarf-fortress
|
||||||
tower-pixel-dungeon
|
tower-pixel-dungeon
|
||||||
|
|||||||
Reference in New Issue
Block a user