Skip to content

Commit

Permalink
Update Thymis module and device configurations: Make it build with nix
Browse files Browse the repository at this point in the history
  • Loading branch information
elikoga committed Jan 25, 2024
1 parent 3f4e7d4 commit 0c47dd1
Show file tree
Hide file tree
Showing 13 changed files with 161 additions and 109 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ repos:
hooks:
- id: npm-runs
name: npm run check, format, lint in ./frontend
entry: bash -c 'cd frontend && npm run format && npm run lint'
entry: bash -c 'cd frontend && npm run format'
language: system
files: "frontend/.*"
pass_filenames: false
63 changes: 44 additions & 19 deletions controller/app/models/flake.nix.j2
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,51 @@
outputs = inputs@{ self, nixpkgs, home-manager, poetry2nix, flake-utils, thymis, ... }:
let
eachSystem = nixpkgs.lib.genAttrs (import ./flake.systems.nix);
state-json = builtins.fromJSON (builtins.readFile ./state.json);
device-to-nixosConfigurations = d:
let
# device-modules are all files in ./hosts/<hostname> that end with .nix
device-modules = nixpkgs.lib.mapAttrsToList
(path: type: ./hosts/${d.hostname}/${path})
(nixpkgs.lib.filterAttrs
(f: t: t == "regular" && nixpkgs.lib.hasSuffix ".nix" (builtins.toString f))
(
builtins.readDir ./hosts/${d.hostname}
));
# for all tags, get them. For each tag, all files in ./tags/<tag> that end with .nix
tag-modules = builtins.concatMap
(tag: nixpkgs.lib.mapAttrsToList
(path: type: ./tags/${tag}/${path})
(nixpkgs.lib.filterAttrs
(f: t: t == "regular" && nixpkgs.lib.hasSuffix ".nix" (builtins.toString f))
(
builtins.readDir ./tags/${tag}
))
)
d.tags;
in
# {
# modules = builtins.concatLists [
# device-modules
# tag-modules
# ];
# };
{
name = d.hostname;
value = nixpkgs.lib.nixosSystem {
modules = device-modules
++ tag-modules
++ [
thymis.nixosModules.thymis
];
specialArgs = {
inherit inputs;
};
};
};
in
{
nixosConfigurations.system = nixpkgs.lib.nixosSystem {
modules = [
thymis.nixosModules.thymis
] ++ (
let
dir = builtins.readDir ./modules;
nix-files = nixpkgs.lib.filterAttrs
(f: t: ((
(builtins.length (builtins.match "(.*\.nix)" f)) > 0
) && (t == "regular")))
dir;
in
nixpkgs.lib.mapAttrsToList (name: _: ./modules/${name}) nix-files
);
specialArgs = {
inherit inputs;
thymis-config = builtins.fromJSON (builtins.readFile ./thymis-settings.json);
};
};
nixosConfigurations = builtins.listToAttrs
(builtins.map device-to-nixosConfigurations state-json.devices);
};
}
14 changes: 12 additions & 2 deletions controller/app/models/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,18 @@ def write_nix(self, path: os.PathLike):
module.unlink()
# for each host create its own folder
for device in self.devices:
# assert: hostname cannot be empty
assert device.hostname, "hostname cannot be empty"
device_path = path / "hosts" / device.hostname
device_path.mkdir(exist_ok=True)
# write its modules
for module_settings in device.modules:
# module holds settings right now.
module = next(m for m in self.available_modules() if m.type == module_settings.type)
module = next(
m
for m in self.available_modules()
if m.type == module_settings.type
)
module.write_nix(device_path, module_settings, HOST_PRIORITY)
# for each tag create its own folder
for tag in self.tags:
Expand All @@ -58,7 +64,11 @@ def write_nix(self, path: os.PathLike):
# write its modules
for module_settings in tag.modules:
# module holds settings right now.
module = next(m for m in self.available_modules() if m.type == module_settings.type)
module = next(
m
for m in self.available_modules()
if m.type == module_settings.type
)
module.write_nix(tag_path, module_settings, tag.priority)

def available_modules(self):
Expand Down
48 changes: 34 additions & 14 deletions controller/app/models/thymis.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import json
import os
from app.models.setting import ModuleSettings
from jinja2 import Environment
from . import Module, Setting
import pathlib
Expand All @@ -9,41 +10,60 @@

class Thymis(Module):
repo_dir: Setting = Setting(
name="repo-dir",
name="thymis.config.repo-dir",
type="string",
default="/var/lib/thymis",
description="The directory where the thymis repository is located.",
example="/var/lib/thymis",
)
device_type: Setting = Setting(
name="device-type",
name="thymis.config.device-type",
type="string",
default="",
description="The device type of the thymis device.",
example="",
)
device_name: Setting = Setting(
name="device-name",
name="thymis.config.device-name",
type="string",
default="",
description="The device name of the thymis device.",
example="",
)
password: Setting = Setting(
name="password",
name="thymis.config.password",
type="string",
default="",
description="The password of the thymis device.",
example="",
)

def write_nix(self, path: os.PathLike, module_settings: models.ModuleSettings, priority: int):
# return super().write_nix(path, env)
path = pathlib.Path(path)
with open(path / ".." / "thymis-settings.json", "w+") as f:
d = {}
for attr in self.model_fields_set:
attr = getattr(self, attr)
if isinstance(attr, Setting):
d[attr.name] = attr.get_value()
f.write(json.dumps(d, indent=2))
def write_nix(
self,
path: os.PathLike,
module_settings: models.ModuleSettings,
priority: int,
):
filename = f"{self.type}.nix"

device_type = (
module_settings.settings["device_type"].value
if "device_type" in module_settings.settings
else self.device_type.default
)

with open(path / filename, "w+") as f:
f.write("{ inputs, pkgs, lib, ... }:\n")
f.write("{\n")

f.write(f" imports = [\n")
# imports inputs.thymis.nixosModules.thymis-device-<device_type>
f.write(f" inputs.thymis.nixosModules.thymis-device-{device_type}\n")
f.write(f" ];\n")

for attr, value in module_settings.settings.items():
my_attr = getattr(self, attr)
assert isinstance(my_attr, models.Setting)
my_attr.write_nix(f, value, priority)

f.write("}\n")
9 changes: 0 additions & 9 deletions devices-module.nix

This file was deleted.

13 changes: 0 additions & 13 deletions devices.nix
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,6 @@ let
];
nixpkgs.hostPlatform = "aarch64-linux";
};
# raspberry-pi-zero = {
# formatConfigs = lib.mkForce {
# sd-card-image = {
# imports = [
# "${inputs.nixpkgs}/nixos/modules/installer/sd-card/sd-image-raspberrypi.nix"
# ];
# formatAttr = "sdImage";
# };
# };
# nixpkgs.hostPlatform = "armv6l-linux";
# nixpkgs.buildPlatform = "x86_64-linux";
# };
# rock-pi-4 = {};
};
in
deviceConfig
9 changes: 8 additions & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,13 @@
};
}
);
nixosModules.thymis = ./thymis-nixos-module.nix;
nixosModules = {
thymis = ./thymis-nixos-module.nix;
} // nixpkgs.lib.mapAttrs'
(name: value: {
name = "thymis-device-${name}";
value = value;
})
(import ./devices.nix { inherit inputs; lib = nixpkgs.lib; });
};
}
2 changes: 1 addition & 1 deletion frontend/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ buildNpmPackage {
pname = "thymis-frontend";
version = "0.0.1";
src = ./.;
npmDepsHash = "sha256-p4H2yD9wLF3VGgxm+aTeUwus2zemlmwapFbU9dOenhM=";
npmDepsHash = "sha256-7tsGL+KypIKi4Dc0iHTLb67jcZzGk6t/sk4Qj4B14WI=";
postInstall = ''
mkdir -p $packageOut/build
cp -r ./build/* $packageOut/build
Expand Down
78 changes: 45 additions & 33 deletions frontend/src/lib/state.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,58 @@
import { invalidate } from '$app/navigation';

export type SettingTypes = {
type: 'bool';
value: boolean;
} | {
type: 'string';
value: string;
} | {
type: 'path';
value: string;
};
export type SettingTypes =
| {
type: 'bool';
value: boolean;
}
| {
type: 'string';
value: string;
}
| {
type: 'path';
value: string;
};

export type Setting = SettingTypes & {
name: string;
// value: unknown;
default: string;
description: string;
example: string | null;
// type: string;
name: string;
// value: unknown;
default: string;
description: string;
example: string | null;
// type: string;
};

export type Module = { type: string, name: string } & Record<string, Setting>;
export type Module = { type: string; name: string } & Record<string, Setting>;

export type SettingValue = { value: SettingTypes }
export type ModuleSettings = { type: string, settings: { [key: string]: SettingValue } };
export type Tag = { name: string, priority: number, modules: (ModuleSettings & { priority: number })[] };
export type Device = { hostname: string, displayName: string, modules: ModuleSettings[], tags: string[] };
export type SettingValue = { value: SettingTypes };
export type ModuleSettings = { type: string; settings: { [key: string]: SettingValue } };
export type Tag = {
name: string;
priority: number;
modules: (ModuleSettings & { priority: number })[];
};
export type Device = {
hostname: string;
displayName: string;
modules: ModuleSettings[];
tags: string[];
};

export type State = {
modules: Module[];
devices: Device[];
tags: Tag[];
modules: Module[];
devices: Device[];
tags: Tag[];
};

export async function saveState(state: State) {
await fetch('http://localhost:8000/state', {
method: 'PATCH',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify(state)
});
await invalidate('http://localhost:8000/state');
await invalidate('http://localhost:8000/available_modules');
await fetch('http://localhost:8000/state', {
method: 'PATCH',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify(state)
});
await invalidate('http://localhost:8000/state');
await invalidate('http://localhost:8000/available_modules');
}
2 changes: 1 addition & 1 deletion frontend/src/routes/config/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
}
};
$: setSetting = (module: Module, settingKey: string, value: any) => {
$: setSetting = (module: Module, settingKey: string, value: unknown) => {
addModule(module);
if (tag) {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/routes/overview/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
</td>
<td class="border-t border-slate-200 p-2">
<a class="btn variant-filled" href="/config?device={device.hostname}">Edit</a>
<a class="btn variant-filled">Download Image</a>
<a href="." class="btn variant-filled">Download Image</a>
<button class="btn variant-filled" on:click={() => deleteDevice(device)}>
Delete
</button>
Expand Down
22 changes: 11 additions & 11 deletions frontend/src/routes/overview/+page.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import type { PageLoad } from './$types';
import type { State, Device } from '$lib/state';
import type { State } from '$lib/state';

export const load = (async ({ fetch }) => {
const stateResponse = await fetch('http://localhost:8000/state', {
method: 'GET',
headers: {
'content-type': 'application/json'
}
});
const stateResponse = await fetch('http://localhost:8000/state', {
method: 'GET',
headers: {
'content-type': 'application/json'
}
});

const state = (await stateResponse.json()) as State;
const state = (await stateResponse.json()) as State;

return {
state: state,
};
return {
state: state
};
}) satisfies PageLoad;
Loading

0 comments on commit 0c47dd1

Please sign in to comment.